单向多对一

1) 保存

  1. public void testManyToOnePersistence() {
  2. //多对一映射关联关系
  3. //一个customer可以有多个order。
  4. Customer customer = new Customer();
  5. customer.setAge(112);
  6. customer.setLastName("b");
  7. customer.setEmail("b");
  8. customer.setBirth(new Date());
  9. customer.setCreateTime(new Date());
  10. Order order = new Order();
  11. order.setOderName("o-ff-1");
  12. Order order1 = new Order();
  13. order1.setOderName("o-ff-2");
  14. order.setCustomer(customer);
  15. order1.setCustomer(customer);
  16. entityManager.persist(customer);
  17. entityManager.persist(order);
  18. entityManager.persist(order1);
  19. }

注意: 保存多对一时,建议先保存1的一端,后保存n的一端,这样不会多出额外的update语句

2) 查询

  1. public void testManyToOneFind() {
  2. Order order = entityManager.find(Order.class, 1);
  3. System.out.println(order.getOrderName());
  4. System.out.println(order.getCustomer().getLastName());
  5. }

默认情况下,使用左外连接的方式来获取n的一端的对象和其关联的1的一端的对象
可以在Order.getCustomer()使用ManyToOne(fetch = FetchType.LAZY) 来修改关联属性的加载策略
05 关联关系 - 图1

3) 删除

  1. public void testManyToOneRemove() {
  2. // 删除多的一方
  3. Order order = entityManager.find(Order.class, 1);
  4. entityManager.remove(order);
  5. // 删除1的一方
  6. Customer customer = entityManager.find(Customer.class, 7);
  7. entityManager.remove(customer);
  8. }

注意: 不能直接删除1的一端,因为有外键;除非多的一端没有数据,否则会报错

单向一对多

1) 保存

  1. @Test
  2. public void testOneToManyPersistence() {
  3. Customer customer = new Customer();
  4. customer.setAge(16);
  5. customer.setEmail("qqqq@qq.com");
  6. customer.setLastName("yy");
  7. customer.setBirth(new Date());
  8. customer.setCreatedTime(new Date());
  9. Order order1 = new Order();
  10. order1.setOrderName("o-y-1");
  11. Order order2 = new Order();
  12. order2.setOrderName("o-y-2");
  13. // 设置关联关系
  14. customer.getOrders().add(order1);
  15. customer.getOrders().add(order2);
  16. // 执行保存操作
  17. entityManager.persist(customer);
  18. entityManager.persist(order1);
  19. entityManager.persist(order2);
  20. }

注意: 单向1-n 执行保存时,一定会多出update语句,因为n的一端在插入时不会同时插入外键列

2) 查询

  1. public void testOneToManyFind() {
  2. Customer customer = entityManager.find(Customer.class, 9);
  3. System.out.println(customer.getLastName());
  4. System.out.println(customer.getOrders().size());
  5. }

默认懒加载,在Customer.getOrders()中使用OneToMany(fetch = FetchType.EAGER) 修改加载策略

3)删除

  1. public void testOneToManyRemove() {
  2. Customer customer = entityManager.find(Customer.class, 10);
  3. entityManager.remove(customer);
  4. }

默认情况下,若删除1的一端,则会把关联的n的一端的外键置空,然后进行删除1的一端
使用OneToMany(cascade = CascadeType.REMOVE) 修改删除策略

双向一对多

双向一对多关系中,必须存在一个关系维护端,在 JPA 规范中,要求 many 的一方作为关系的维护端(owner side), one 的一方作为被维护端(inverse side)。
可以在 one 方指定 OneToMany 注释并设置 mappedBy 属性,以指定它是这一关联中的被维护端,many 为维护端。
在 many 方指定 ManyToOne 注释,并使用 JoinColumn 指定外键名称
05 关联关系 - 图2
05 关联关系 - 图3

  1. public void testDoubleOneToManyPersistence() {
  2. Customer customer = new Customer();
  3. customer.setAge(16);
  4. customer.setEmail("ggg@qq.com");
  5. customer.setLastName("bb");
  6. customer.setBirth(new Date());
  7. customer.setCreatedTime(new Date());
  8. Order order1 = new Order();
  9. order1.setOrderName("o-b-1");
  10. Order order2 = new Order();
  11. order2.setOrderName("o-b-2");
  12. // 设置关联关系
  13. customer.getOrders().add(order1);
  14. customer.getOrders().add(order2);
  15. order1.setCustomer(customer);
  16. order2.setCustomer(customer);
  17. // 执行保存操作
  18. entityManager.persist(customer);
  19. entityManager.persist(order1);
  20. entityManager.persist(order2);
  21. }

若是双向1-n的关联关系,执行保存时
先保存n的一端,再保存1的一端,默认情况下,会多出4条update语句
先保存1的一端,会多出n条update语句
建议: 使用n的一方来维护关联关系,而1的一方不维护关联关系,这样会有效的减少sql语句
注意: 若在1的一端的@OneToMany中使用mappedBy属性,则@OneToMany端就不能使用@JoinColumn属性了

双向一对一

基于外键的 1-1 关联关系:在双向的一对一关联中,需要在关系被维护端(inverse side)中的 OneToOne 注释中指定 mappedBy,以指定是这一关联中的被维护端。同时需要在关系维护端(owner side)建立外键列指向关系被维护端的主键列。
05 关联关系 - 图4

1) 保存

  1. public void testOneToOnePersistence() {
  2. Manager manager = new Manager();
  3. manager.setMgrName("m-22");
  4. Department department = new Department();
  5. department.setDeptName("d-22");
  6. // 设置关联关系
  7. manager.setDepartment(department);
  8. department.setManager(manager);
  9. // 执行保存操作
  10. entityManager.persist(department);
  11. entityManager.persist(manager);
  12. }

双向1-1的关联关系,建议先保存不维护关联关系的一方,即没有外键的一方,这样不会多出update语句
05 关联关系 - 图5
05 关联关系 - 图6

2) 查询

  1. public void testOneToOneFind() {
  2. Department department = entityManager.find(Department.class, 1);
  3. System.out.println(department.getDeptName());
  4. System.out.println(department.getManager().getClass().getName());
  5. }

默认情况下,若获取维护关联关系的一方,则会通过左外连接获取其关联的对象
可以通过OneToOne(fetch = FetchType.LAZY)来修改加载策略

  1. public void testOneToOneFind2() {
  2. Manager manager = entityManager.find(Manager.class, 1);
  3. System.out.println(manager.getMgrName());
  4. System.out.println(manager.getDepartment().getClass().getName());
  5. }

默认情况下,若获取不维护关联关系的一方,也会通过左外连接获取其关联的对象
可以通过OneToOne(fetch = FetchType.LAZY)来修改加载策略,但依然会再发送SQl语句来初始化器关联的对象
说明在不维护关联关系的一方,不建议修改fatch属性
不延迟加载的原因:
1.如果延迟加载要起作用, 就必须设置一个代理对象.
2.Manager 其实可以不关联一个 Department
3.如果有 Department 关联就设置为代理对象而延迟加载, 如果不存在关联的 Department 就设置 null, 因为外键字段是定义在 Department 表中的,Hibernate 在不读取 Department 表的情况是无法判断是否有关联有 Deparmtment, 因此无法判断设置 null 还是代理对象, 而统一设置为代理对象,也无法满足不关联的情况, 所以无法使用延迟加载,只 有显式读取 Department.
05 关联关系 - 图7

双向多对多

在双向多对多关系中,我们必须指定一个关系维护端(owner side),可以通过 ManyToMany 注释中指定 mappedBy 属性来标识其为关系维护端。
ManyToMany
@JoinTable(name=”中间表名称”,

  1. joinColumns={

@joinColumn(name=”本类的外键”,referencedColumnName=”本类与外键对应的主键”)

  1. },
  2. inversejoinColumns={

@JoinColumn(name=”对方类的外键”,referencedColunName=”对方类与外键对应的主键”)

  1. }

)
05 关联关系 - 图8
05 关联关系 - 图9
05 关联关系 - 图10

1) 保存

  1. // 共8条insert语句
  2. public void testManyToManyPersistence() {
  3. Item i1 = new Item();
  4. i1.setItemName("i-1");
  5. Item i2 = new Item();
  6. i2.setItemName("i-2");
  7. Category c1 = new Category();
  8. c1.setCategoryName("c-1");
  9. Category c2 = new Category();
  10. c2.setCategoryName("c-2");
  11. // 设置关联关系
  12. i1.getCategories().add(c1);
  13. i1.getCategories().add(c2);
  14. i2.getCategories().add(c1);
  15. i2.getCategories().add(c2);
  16. c1.getItems().add(i1);
  17. c1.getItems().add(i2);
  18. c2.getItems().add(i1);
  19. c2.getItems().add(i2);
  20. // 执行保存
  21. entityManager.persist(i1);
  22. entityManager.persist(i2);
  23. entityManager.persist(c1);
  24. entityManager.persist(c2);
  25. }

2) 查询

  1. public void testManyToManyFind() {
  2. /*Item item = entityManager.find(Item.class, 1);
  3. System.out.println(item.getItemName());
  4. System.out.println(item.getCategories().size());*/
  5. Category category = entityManager.find(Category.class, 1);
  6. System.out.println(category.getCategoryName());
  7. System.out.println(category.getItems().size());
  8. }

对于关联的集合对象,默认使用懒加载的策略
使用维护关联的关系一方获取,还是使用不维护关联关系的一方获取,sql语句相同