# 映射关系详解

表关系映射（双向映射）：

* @OneToOne 一对一关系
* @OneToMany 一对多
* @ManyToMany（不推荐使用，而是采用用中间对象，把多对多拆成两个对多一关系，如下书 与作者 的关系例子，还可以使用中间表用来搜索）

字段映射（单向映射）：

* @Embedded, @Embeddable 嵌入式关系（单向映射）
* @ElementCollection 集合一对多关系（单向映射）

> 注意：[hibernate jpa中 的 fetch](http://gong-10140.iteye.com/blog/678918)
>
> fetch 为关键映射的一个加载策略
>
> fetch的默认值：FetchType.EAGER，也就是加载的时候把响应的映射关系数据也加载出来
>
> 如果这不适合于应用程序或特定的持久字段，请将fetch设置为FetchType.LAZY，延迟加载，只要getxxxx（），具体获取时，再次执行一条sql语句获取

### @OneToOne 一对一关系

@OneToOne 属性

![](https://3562539340-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LfnT314x6hQ7gJbPKxx%2F-LfnTB6gvTwJcyb-RbKo%2F-LfnTJndtk3185WXiky2%2FOneToOne.png?generation=1558862985521161\&alt=media)

比如作者和作者详情信息(一些不常用信息)，就是一个一对一

Author.java

```java
@Entity
public class Author {
    @OneToOne
    private AuthorInfo info;
    ...... 省略其他
}
```

AuthorInfo.java

```java
@Entity
public class AuthorInfo {

    private String school;

    @OneToOne(mappedBy = "info")
    private Author author;

    ......省略其他
}
```

无属性的一方拥有管理权，也就是author 表中会多出来一个字段info\_id

### @OneToMany 一对多， @ManyToOne 多对一

> 注意一对多关系映射时，“One”端采用@OneToMany 注释时必须使用mappedBy来指定Many端的对象的哪个属性提供了对应的关系映射。
>
> 避免建立单向关系映射，以免产生新的中间表，而采用双向映射关系（这样many 的一端只会使用外键方式来维护关系）

@ManyToOne 的属性

![](https://3562539340-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LfnT314x6hQ7gJbPKxx%2F-LfnTB6gvTwJcyb-RbKo%2F-LfnTJnhesz-AYFkDRpv%2FManyToOne.png?generation=1558862987337384\&alt=media)

@OneToMany 属性

![](https://3562539340-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LfnT314x6hQ7gJbPKxx%2F-LfnTB6gvTwJcyb-RbKo%2F-LfnTJnl_N_uFO_upJUr%2FOneToMany.png?generation=1558862985842766\&alt=media)

一本书有多个作者（OneToMany 一对多）， 而书和作者表中，（"spring boot", revin"）只能属于一本书（ManyToOne 多对一）

Book.java

```java
@Entity
public class Book {

    private String name;

    @OneToMany(mappedBy = "book")
    private List<BookAuthor> authors;

    .....省略
}
```

一个作者出版了多本书（OneToMany 一对多）， 而书和作者表中，（"spring boot", revin"）只能属于一个作者（ManyToOne 多对一）

Author.java

```java
@Entity
public class Author {
    @OneToMany(mappedBy = "author")
    //@OrderBy("book.name ASC")
    private List<BookAuthor> books;
     .....省略
}
```

BookAuthor .java

```java
@Entity
public class BookAuthor {

    @ManyToOne
    private Book book;

    @ManyToOne
    private Author author;
    .....省略
}
```

比如一本书可以分属于多个栏目（OneToMany 一对多），而同一个栏目 只能有一本相同的书（ManyToOne 多对一）

Book.java

```java
@Entity
public class Book {

    private String name;

    @ManyToOne
    private Category category;

    .....省略
}
```

Category.java

```java
public class Category {
@OneToMany(mappedBy = "category")
    private List<Book> books;

    ......省略其他
}
```

### @Embedded, @Embeddable 嵌入式关系

意思就是说当你有一个用户信息表中，这个人有地址信息，而地址信息有可能别的类有其他的关系映射，所以需要独立处理，但是address表中的字段，你有需要在用户表中存在这可以这种嵌入式关系。

@Embedded嵌入Address 类

```java
@Entity
public class Author {
    @Embedded
    private Address address;
    ......  省略其他
}
```

@Embeddable声明Address 类是可嵌入的

```java
@Embeddable
public class Address {

    private String province;

    private String city;

    private String area;

    private String address;

    private String zipcode;

    ...... 省略其他

}
```

最后生成出来 author表中会包含province，city，area，address，zipcode这些字段。

### @ElementCollection 集合一对多关系

```java
@Entity
public class Author {

    @id
    @GeneratedValue
    private long id

    @ElementCollection
    private List<String> hobbies;
    ......  省略其他
}
```

生成效果为：数据表会出现一张新表为`author_hobbies`,并且字段名为`author_id` 和 hobbies , Author表与hobbies表产生了一个一对 的关系。

当你插入和获取用户信息的时，jpa会自动关联。

再举例子

当一个用户有多个地址，比如在电子商务场景中，会有多个收货地址

```java
@Entity
public class Author {

    @ElementCollection
    private List<Address> addresses;
    ......  省略其他
}
```

也会重新生成一张新表，并且字段名是Address类定义的字段。Author与addresses产生一个一对的关系。

## 资料

[1JPA 批注参考](http://www.oracle.com/technetwork/cn/middleware/ias/toplink-jpa-annotations-100895-zhs.html#OneToMany) - 推荐当手册用
