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