Hibernate 外键语法

3

我想学习Hibernate。我有一个电影表,其中包含指向流派表的外键。每部电影都归属于一种流派,而每个流派可以被分配给多个电影。

以下是表的定义:

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;

我有点不知道我做错了什么。是不是应该在Genre类中而不是Movie类中使用多对一的注释?或者您还看到我其他做错的地方吗?

根据下面的建议,现在Movie有:

@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();
}

我看到的是,尽管我有使用“eager load”,并且在toString中明确指定了getGenre,但是没有生成查询语句,我只是得到了一个空值。

你是如何获取 Movie 对象的?请展示你所使用的代码。 - skaffman
我根据你的建议修改了上面的描述,skaffman。 - P.H.
2个回答

0
当您使用HQL语法(例如createQuery("from Movie"))时,Hibernate/JPA仅在您在Movie对象上调用getGenre()时才会获取Genre实体。这被称为“延迟加载”。当调用该方法时,Hibernate将发出另一个查询以获取Genre
请注意,HQL查询忽略注释中的FetchType - HQL用于告诉Hibernate 确切地要做什么,而不是使用注释中的提示。
要使其在与Movie相同的查询中获取Genre,您需要告诉它:
createQuery("from Movie m join fetch m.genre")

一对一和多对一关系默认不是EAGER吗? - SelimOber
这也起作用了!我已经在http://clippy.tk/index.php?show=1036发布了好的文件版本。 - P.H.
非常感谢您的帮助。在我继续进行一对多之前,我将尝试更多地了解Hibernate的内部工作原理。 - P.H.

0

试试这个:

电影方面:

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

而在另一方面(类型):

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

然后你可以从一个电影对象 movie.getGenre() 获取电影类型。


在类型方面的映射可能不是必需的,但我建议尝试使用JoinColumn注释。 - steffinchen
这个可行!我已经将所有文件发布在http://clippy.tk/index.php?show=1035,希望能对其他人有所帮助。 - P.H.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接