映射关系
1.单向多对一 @ManyToOne
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
@ToString
@Entity
@Table(name="tb_person")
public class Person {
@Id
@GeneratedValue
private Integer pid;
private String pname;
}
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
@ToString
@Entity
@Table(name="tb_book")
public class Book {
@Id
@GeneratedValue
private Integer bid;
private String bname;
//映射单向 n-1 的关联关系
//使用 @ManyToOne 来映射多对一的关联关系
//使用 @JoinColumn 来映射外键.
//可使用 @ManyToOne 的 fetch 属性来修改默认的关联属性的加载策略
@JoinColumn(name="p_id")
@ManyToOne(fetch=FetchType.LAZY)
private Person person;
}
/**
* 保存多对一时, 建议先保存 1 的一端, 后保存 n 的一端, 这样不会多出额外的 UPDATE 语句.
*/
@Test
public void testManyToOnePersist(){
Person person = new Person();
person.setPname("mmm");
Book book = new Book();
book.setBname("book");
Book book1 = new Book();
book.setBname("book1");
//设置关联关系
book.setPerson(person);
book1.setPerson(person);
//执行保存操作
entityManager.persist(person);
entityManager.persist(book);
entityManager.persist(book1);
}
//不能直接删除 1 的一端, 因为有外键约束.
@Test
public void testManyToOneRemove(){
Person person = entityManager.find(Person.class, 8);
//删除主表,子表还有记录,则会报错
entityManager.remove(person);
}
2 单向一对多 @OneToMany
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
@ToString
@Entity
@Table(name="tb_person")
public class Person {
@Id
@GeneratedValue
private Integer pid;
private String pname;
//映射单向 1-n 的关联关系
//使用 @OneToMany 来映射 1-n 的关联关系
//使用 @JoinColumn 来映射外键列的名称
//可以使用 @OneToMany 的 fetch 属性来修改默认的加载策略
//可以通过 @OneToMany 的 cascade 属性来修改默认的删除策略.
//注意: 若在 1 的一端的 @OneToMany 中使用 mappedBy 属性, 则 @OneToMany 端就不能再使用 @JoinColumn 属性了.
@JoinColumn(name="p_id")
@OneToMany(fetch=FetchType.LAZY)
private Set<Book> books = new HashSet<>();
}
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
@ToString
@Entity
@Table(name="tb_book")
public class Book {
@Id
@GeneratedValue
private Integer bid;
private String bname;
}
//单向 1-n 关联关系执行保存时, 一定会多出 UPDATE 语句.
//因为 n 的一端在插入时不会同时插入外键列.
@Test
public void testOneToManyPersist(){
Person person = new Person();
person.setPname("onetomany");
Book book = new Book();
book.setBname("book");
Book book1 = new Book();
book1.setBname("book1");
//设置关联关系
person.getBooks().add(book);
person.getBooks().add(book1);
//执行保存操作
entityManager.persist(person);
entityManager.persist(book);
entityManager.persist(book1);
}
3 双向多对一
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
@ToString
@Entity
@Table(name="tb_person")
public class Person {
@Id
@GeneratedValue
private Integer pid;
private String pname;
//映射单向 1-n 的关联关系
//使用 @OneToMany 来映射 1-n 的关联关系
//使用 @JoinColumn 来映射外键列的名称
//可以使用 @OneToMany 的 fetch 属性来修改默认的加载策略
//可以通过 @OneToMany 的 cascade 属性来修改默认的删除策略.
//注意: 若在 1 的一端的 @OneToMany 中使用 mappedBy 属性, 则 @OneToMany 端就不能再使用 @JoinColumn 属性了.
@JoinColumn(name="p_id")
@OneToMany(fetch=FetchType.LAZY)
private Set<Book> books = new HashSet<>();
}
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
@ToString
@Entity
@Table(name="tb_book")
public class Book {
@Id
@GeneratedValue
private Integer bid;
private String bname;
//映射单向 n-1 的关联关系
//使用 @ManyToOne 来映射多对一的关联关系
//使用 @JoinColumn 来映射外键.
//可使用 @ManyToOne 的 fetch 属性来修改默认的关联属性的加载策略
@JoinColumn(name="p_id")
@ManyToOne(fetch=FetchType.LAZY)
private Person person;
}
//若是双向 1-n 的关联关系, 执行保存时
//若先保存 n 的一端, 再保存 1 的一端, 默认情况下, 会多出 n 条 UPDATE 语句.
//若先保存 1 的一端, 则会多出 n 条 UPDATE 语句
//在进行双向 1-n 关联关系时, 建议使用 n 的一方来维护关联关系, 而 1 的一方不维护关联系, 这样会有效的减少 SQL 语句.
//注意: 若在 1 的一端的 @OneToMany 中使用 mappedBy 属性, 则 @OneToMany 端就不能再使用 @JoinColumn 属性了.
@Test
public void testOneToManyPersist(){
Person person = new Person();
person.setPname("onetomany");
Book book = new Book();
book.setBname("book");
Book book1 = new Book();
book1.setBname("book1");
//设置关联关系
person.getBooks().add(book);
person.getBooks().add(book1);
book.setPerson(person);
book1.setPerson(person);
//执行保存操作(两种顺序,sql执行的数量就不一样)
//sql执行13条
entityManager.persist(book);
entityManager.persist(book1);
entityManager.persist(person);
//sql执行11条
entityManager.persist(person);
entityManager.persist(book);
entityManager.persist(book1);
}
4 双向一对一
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
@ToString
@Entity
@Table(name="tb_person")
public class Person {
@Id
@GeneratedValue
private Integer pid;
private String pname;
//对于不维护关联关系, 没有外键的一方, 使用 @OneToOne 来进行映射, 建议设置 mappedBy=true
@OneToOne(mappedBy="person")
private Book book;
}
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
@ToString
@Entity
@Table(name="tb_book")
public class Book {
@Id
@GeneratedValue
private Integer bid;
private String bname;
//使用 @OneToOne 来映射 1-1 关联关系。
//若需要在当前数据表中添加主键则需要使用 @JoinColumn 来进行映射. 注意, 1-1 关联关系, 所以需要添加 unique=true
@JoinColumn(name="p_id", unique=true)
@OneToOne(fetch=FetchType.LAZY)
private Person person;
}
//双向 1-1 的关联关系, 建议先保存不维护关联关系的一方, 即没有外键的一方, 这样不会多出 UPDATE 语句.
@Test
public void testOneToOnePersistence(){
Person person = new Person();
person.setPname("one");
Book book = new Book();
book.setBname("toone");
//设置关联关系
person.setBook(book);
book.setPerson(person);
//执行保存操作
entityManager.persist(person);
entityManager.persist(book);
}
外键在book表里维护
5 双向多对多 @ManyToMany
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
@ToString
@Entity
@Table(name="tb_person")
public class Person {
@Id
@GeneratedValue
private Integer pid;
private String pname;
@ManyToMany(mappedBy="persons")
private Set<Book> books = new HashSet<>();
}
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
@ToString
@Entity
@Table(name="tb_book")
public class Book {
@Id
@GeneratedValue
private Integer bid;
private String bname;
//使用 @ManyToMany 注解来映射多对多关联关系
//使用 @JoinTable 来映射中间表
//1. name 指向中间表的名字
//2. joinColumns 映射当前类所在的表在中间表中的外键
//2.1 name 指定外键列的列名
//2.2 referencedColumnName 指定外键列关联当前表的哪一列
//3. inverseJoinColumns 映射关联的类所在中间表的外键
@JoinTable(name="person_book",
joinColumns={@JoinColumn(name="book_id", referencedColumnName="bid")},
inverseJoinColumns={@JoinColumn(name="person_id", referencedColumnName="pid")})
@ManyToMany
private Set<Person> persons = new HashSet<>();
}
//多对多的保存
@Test
public void testManyToManyPersist(){
Person person = new Person();
person.setPname("P1");
Person person2 = new Person();
person2.setPname("P2");
Book book = new Book();
book.setBname("B1");
Book book2 = new Book();
book2.setBname("B2");
//设置关联关系
person.getBooks().add(book);
person.getBooks().add(book2);
person2.getBooks().add(book);
person2.getBooks().add(book2);
book.getPersons().add(person);
book.getPersons().add(person2);
book2.getPersons().add(person);
book2.getPersons().add(person2);
//执行保存
entityManager.persist(person);
entityManager.persist(person2);
entityManager.persist(book);
entityManager.persist(book2);
}
多对多,会产生一个中间表