# 与 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<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;
    }

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

    @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)下载特定章节的代码。

