Hibernate 4 的实体关系
原文: https://javabeginnerstutorial.com/hibernate/entity-relations-with-hibernate-4/
上次我介绍了注解而不是 XML 配置。 现在,我将更深入地研究并展示如何创建实体关系并将其映射到数据库。
如果在示例中查看图书实体,您可能会想到:“为什么将图书的作者存储为字符串?” 你是对的。 这使得作者查询书籍几乎是不可能的,或者至少没有表现得那么出色。 而且两次输入之间的错别字会使情况更糟。
在本文中,我将进一步举例说明,然后将作者的字符串提取到另一个实体中。
作者实体
让我们从一个拥有作者信息的新实体开始。 为简单起见,它将仅包含作者的姓名和作者创建的书籍列表。
@Entity@Table(name = "AUTHORS")public class Author {@Idprivate String name;@ManyToMany(mappedBy = "authors")private final List<Book> books = new ArrayList<>();private Author() {}public Author(String name) {this.name = name;}public String getName() {return this.name;}public void setName(String name) {this.name = name;}public List<Book> getBooks() {return this.books;}@Overridepublic String toString() {return MessageFormat.format("{0} has written {1} book(s).", this.name, this.books.size());}}
如您所见,这里有一个新的注解:@ManyToMany。 这告诉 Hibernate Author实体映射到其他Book实体。 mappingBy属性用于告诉 Hibernate 哪个实体是关系的所有者。 这主要用于一对多或多对一关系中。
将作者添加到Book实体
现在,将作者字符串更改为作者列表。 它看起来与Author实体完全相同:
@Entity@Table(name = "BOOKS")public class Book {@Idprivate String isbn;private String title;@ManyToManyprivate final List<Author> authors = new ArrayList<>();@Temporal(TemporalType.DATE)@Column(name = "PUBLISHED_DATE")private Date published;private Book() {}public Book(String isbn, String title, Date published) {this.isbn = isbn;this.title = title;this.published = published;}public String getIsbn() {return this.isbn;}public String getTitle() {return this.title;}public void setTitle(String title) {this.title = title;}public List<Author> getAuthors() {return this.authors;}public void setIsbn(String isbn) {this.isbn = isbn;}public Date getPublished() {return this.published;}public void setPublished(Date published) {this.published = published;}@Overridepublic String toString() {final String authorNames = this.authors.stream().map(Author::getName).collect(Collectors.joining(", "));return MessageFormat.format("{0} by {1} (ISBN: {2}), published {3}", this.title, authorNames, this.isbn, this.published);}}
在这里,我没有在@ManyToMany注解中添加任何参数,因为作者是所有者。
关系类型
当然,多对多关系不是唯一可用的关系。 如果需要,您也可以选择一对一,一对多或多对一。
一对一关系
对于一个实体,此关系类型仅包含一种引用类型,而对于另一实体也是如此。 在这种情况下,您可以选择用于存储引用的实体。例如,如果我将 ISBN 提取为具有其他一些属性的单独实体,则可能是书籍与 ISBN 号之间的关系:一本书具有一本 ISBN 和一本 ISBN 准确地指一本书。
一对多和多对一关系
在这种情况下,一个实体在其他实体中具有许多引用。 如果一本书只能有一位作者,那就是这种情况。 在这种情况下,引用 ID 将存储在BOOKS表中,因为有一本书参考了其作者。 我们在作者实体中使用一对多,在Book实体中使用多对一。
多对多关系
如您在第一个示例中所看到的,这种关系有点复杂。 在这里,我们需要一个单独的表格来包含书籍和作者之间的引用。 这就是所谓的联接表。 该表由 Hibernate 自动维护,但是您可以告诉该表如何命名。 如果您不选择名称,则 Hibernate 会使用实体名称,并用下划线将其分开,所有者名称为站点实体。 在此示例中,联接表名为:BOOKS_AUTHORS。
更改main方法
由于实体已更改,因此我也必须更改Main类的main方法。
final Book book = new Book("9781617291999", "Java 8 in Action", new Date());session.beginTransaction();Arrays.stream("Raoul-Gabriel Urma,Mario Fusco,Alan Mycroft".split(",")).map(name -> new Author(name)).forEach(author -> {author.getBooks().add(book);book.getAuthors().add(author);session.save(author);});session.save(book);session.getTransaction().commit();
如您所见,我使用一些 lambda 来动态创建作者。 有趣的部分是最后一个语句,forEach块:我将这本书添加到当前作者的图书列表中,然后将当前作者添加到这本书的作者列表中。 以后需要在数据库中一起查找书籍和作者时,需要使用此引用(如果您手动查询或使用 Hibernate 加载数据集)。
现在的结果与上次有所不同:
----Storing 1 books in the databaseJava 8 in Action by Raoul-Gabriel Urma, Mario Fusco, Alan Mycroft (ISBN: 9781617291999), published 2015.06.29\. 16:57----
如果我放弃声明book.getAuthors().add(author);,则结果不包含作者的姓名:
----Storing 1 books in the databaseJava 8 in Action by (ISBN: 9781617291999), published 2015.06.29\. 16:58----
总结
如您所见,有很多选项可以将实体关系映射到规范化数据库。 下次,我将向您展示如何将实体继承映射到数据库。
代码下载
您可以从 Github 此处下载特定章节的代码。