2012-02-10 161 views
3

我想学习休眠。我有一个电影表和一个流派表的外键。每部电影都被分配到一个流派。每种类型都可以分配给许多电影。休眠外键语法

下面是表定义:

CREATE TABLE `movie` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `title` varchar(64) NOT NULL, 
    `genre_id` int(11) NOT NULL, 
    PRIMARY KEY (`id`), 
    KEY `fk_genre` (`genre_id`), 
    CONSTRAINT `fk_genre` FOREIGN KEY (`genre_id`) REFERENCES `genre` (`id`) ON UPDATE CASCADE, 

) 

CREATE TABLE IF NOT EXISTS `genre` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `name` varchar(32) DEFAULT NULL, 
    PRIMARY KEY (`id`) 
) 

对于代码,我有

@Entity 
public class Movie implements java.io.Serializable { 

    private static final long serialVersionUID = 1; 
    private Integer id; 
    private String title; 
    private Genre genre; 
    ... 

    @ManyToOne 
    public Genre getGenre() { 
     return genre; 
    } 

而且

@Entity 
public class Genre implements java.io.Serializable { 

    private static final long serialVersionUID = 1; 
    private Integer id; 
    private String name; 

    @Id 
    @GeneratedValue 
    @Column(name = "id") 
    public Integer getId() { 
     return this.id; 
    } 

然后选择由Hibernate生成看起来像

select 
    movie0_.id as column1_4_, 
    movie0_.genre_id as genre11_4_, 
    movie0_.title as title4_ 
from 
    Movie movie0_ 

这不正确,因为没有对流派表的引用。正确的查询应该与流派表连接。更多类似

select 
    movie0_.id as column1_4_, 
    genre.name as genre11_4_, 
    movie0_.title as title4_ 
from 
    Movie movie0_, Genre genre 
where 
    movie0_.genre_id = genre.id; 

我无所适从,我做错了一点点。多对一的注释应该在流派类中而不是电影类中吗?或者你看到我做错了什么?

基于下面的提醒,电影现在有

@Override 
public String toString() { 
    StringBuilder sb = new StringBuilder(); 
    sb.append(id).append(" "); 
    sb.append(title).append(" "); 

    this.getGenre(); //new 

    sb.append(genre.getName()); 
    return sb.toString(); 
} 

@ManyToOne(fetch=FetchType.EAGER) //new 
public Genre getGenre() { 
    return genre; 
} 

而且我加载电影的方式是通过

public static void main(String[] args) { 
    SessionFactory sf = HibernateUtil.getSessionFactory(); 
    Session session = sf.openSession(); 
    List<Movie> movies = session.createQuery("from Movie").list(); 
    for (Movie movie : movies) { 
     System.out.println(movie.toString()); 
    } 
    session.close(); 
} 

我所看到的是,即使我有渴望负载,我明确地说toString中的getGenre,没有生成查询,我只是得到一个空回来。

+0

你如何获取'Movie'对象?向我们展示您正在使用的代码。 – skaffman 2012-02-10 14:11:44

+0

我编辑了上述说明以回应您的建议,skaffman。 – 2012-02-10 14:22:34

回答

0

当您使用HQL语法(例如createQuery("from Movie")),则Hibernate/JPA将只有当您在Movie对象调用getGenre()获取Genre实体。这被称为“懒取”。当该方法被调用时,Hibernate将发出另一个查询来获取Genre

请注意,HQL查询会忽略注释上的FetchType - HQL用于告诉Hibernate 完全是该做什么,而不是在注释中使用提示。

,使其在同一查询作为MovieGenre,你需要告诉它:

createQuery("from Movie m join fetch m.genre") 
+0

是不是OneToOne和ManyToOnes'默认为EAGER? – SelimOber 2012-02-10 14:09:24

+0

@SelimOber:很对。据此编辑。 – skaffman 2012-02-10 14:30:29

+0

这也工作!我已经在http://clippy.tk/index.php?show=1036发布了这些文件的优秀版本。 – 2012-02-10 15:03:44

0

试试这个:

影视方面:

@ManyToOne 
@JoinColumn(name = "genre_id") 
public Genre getGenre() {..} 

和另一面(流派):

@OneToMany(mappedBy="genre") 
List/Set getMovies(){..} 

然后你可以从一个电影对象movie.getGenre()获得流派。

+0

在流派方面的映射不应该是必要的。但我也建议尝试使用joinColumn注释 – steffinchen 2012-02-10 14:35:05

+0

这工作!我已经在http://clippy.tk/index.php?show=1035发布了所有文件,希望它可以帮助别人。 – 2012-02-10 14:55:35