博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
hibernate多对多单向(双向)关系映射
阅读量:4687 次
发布时间:2019-06-09

本文共 6017 字,大约阅读时间需要 20 分钟。

 

n-n(多对多)的关联关系必须通过连接表实现。下面以商品种类和商品之间的关系,即一个商品种类下面可以有多种商品,一种商品又可以属于多个商品种类,分别介绍单向的n-n关联关系和双向的n-n关联关系。

单向的n-n关联关系

  如果仅使用两张数据表,是不能实现n-n的关联关系的,如下图:

 

商品ITEM_AA属于商品种类CATEGORY_AA,但是如果商品ITEM_AA又同时属于商品种类CATEGORY_BB呢,两张数据表无法实现这种关系,所以我们需要使用到连接表,如下图所示: 

我们添加一张连接表,其中的每一条记录表示某一个商品和某一个商品种类的对应关系。 

单向的n-n关联关系的域模型和关系数据模型如下图所示: 

 

 

 

 下面来实现这种关系,首先新建两个类:

1 public class Category { 2  3     private Integer id; 4     private String name; 5  6     private Set
items = new HashSet<>(); 7 8 //getters and setters 9 }10 11 public class Item {12 13 private Integer id;14 private String name;15 16 //getters and setters17 }

 

 生成并编辑映射文件: 

  
Category.hbm.xml

1 
2 4 5
6 7
8 9
10
11
12
13 14
15
16
17 18
19
20
21
22
23
24
25
26 27
28

Item.hbm.xml

1 
2 4 5
6 7
8 9
10
11
12
13 14
15
16
17
18

与1-n关联关系类似,在映射时,必须在category类的映射文件中设置set节点。但是不同的是,在set节点中指定的表为连接表CATEGORIES_ITEMS,而不再是所关联的类Item所对应的表,而且,在set节点中设置的是many-to-many节点,而不再是one-to-many。many-to-many节点的class属性指定了items集合中存放的对象类型是Item,colume属性指定了连接表CATEGORIES_ITEMS中参照ITEMS表的外键是ITEM_ID。

现在随便一个测试程序,发现除了生成了表CATEGORIES和表ITEMS,还生成了连接表CATEGORIES_ITEMS,表结构为:

 

下面测试save操作和get操作: 

   
单向n-n关联关系的save操作:

1 @Test 2     public void testSave(){ 3         Category category1 = new Category(); 4         category1.setName("C-AA"); 5  6         Category category2 = new Category(); 7         category2.setName("C-BB"); 8  9         Item item1 = new Item();10         item1.setName("I-AA");11 12         Item item2 = new Item();13         item2.setName("I-BB");14 15         //设定关联关系16         category1.getItems().add(item1);17         category1.getItems().add(item2);18 19         category2.getItems().add(item1);20         category2.getItems().add(item2);21 22         //执行保存操作23         session.save(category1);24         session.save(category2);25 26         session.save(item1);27         session.save(item2);28     }

运行程序,根据控制台打印的sql语句,发现会先往CATEGORIES表和ITEMS表分别插入两条记录,然后再往连接表CATEGORIES_ITEMS插入四条记录,这是符合我们的预期的: 

 

 

 

单向n-n关联关系的get操作:

 

1 @Test2     public void testGet(){3         Category category = (Category) session.get(Category.class, 1);4         System.out.println(category.getName()); 5 6         //需要连接中间表7         Set
items = category.getItems();8 System.out.println(items.size()); 9 }

同1-n、1-1中类似,先查询category会使用懒加载机制,不会立即加载items,只有使用到items的时候才会加载。当加载items的时候,是通过内连接连接中间表CATEGORIES_ITEMS进行查询的: 

 

 

 

双向的n-n关联关系

  在双向的n-n关联关系中,两端的类都需要使用集合属性,即Category中要包含一个Set<Item>,Item中也要包含一个Set<Category>,,且在数据库中同样需要使用连接表连接。其域模型和关系数据模型如下: 

 

 

1 public class Category { 2  3     private Integer id; 4     private String name; 5  6     private Set
items = new HashSet<>(); 7 8 //getters and setters 9 }10 11 public class Item {12 13 private Integer id;14 private String name;15 16 private Set
categories = new HashSet<>();17 18 //getters and setters19 }

生成并编辑映射文件: 

  
Category.hbm.xml

1 
2 4 5
6 7
8 9
10
11
12
13 14
15
16
17 18
19
20
21
22
23
24
25
26 27
28

Item.hbm.xml

1 
2 4 5
6 7
8 9
10
11
12
13 14
15
16
17 18
19
20
21
22 23
24

大部门内容和单向n-n中类似,只是需要在Item类中添加字段

1  private Set
categories = new HashSet<>();

并且需要在Item类的映射文件中像Category映射文件中那样配置set节点。此外,还有一个很重要的地方,就是需要在Category和Item的其中一端的映射文件中的set节点中设置inverse=”true”属性,以放弃维护关联关系,否则两端都会维护默认关系,这在某些情况下会导致错误,下面会演示。

  现在生成数据表,表结构和单向n-n中一样:
下面测试save操作和get操作: 
   
双向n-n关联关系的save操作:

1 Category category1 = new Category(); 2         category1.setName("C-AA"); 3  4         Category category2 = new Category(); 5         category2.setName("C-BB"); 6  7         Item item1 = new Item(); 8         item1.setName("I-AA"); 9 10         Item item2 = new Item();11         item2.setName("I-BB");12 13         //设定关联关系14         category1.getItems().add(item1);15         category1.getItems().add(item2);16 17         category2.getItems().add(item1);18         category2.getItems().add(item2);19 20         item1.getCategories().add(category1);21         item1.getCategories().add(category2);22 23         item2.getCategories().add(category1);24         item2.getCategories().add(category2);25 26         //执行保存操作27         session.save(category1);28         session.save(category2);29 30         session.save(item1);31         session.save(item2);

运行程序,和单向n-n中一样,一共打印8条insert语句,并成功插入记录。但是,现在我们移除Item.hbm.xml文件中的inverse=”true”属性,再运行程序,会抛出异常。这是因为在默认情况下n-n的两端都会维护关联关系,当执行上述四条save代码后,category要维护关联关系,往连接表中添加4条记录,然后item也要维护关联关系,往连接表中添加相同的4条记录,会导致连接表中主键重复,解决方法就是在Item.hbm.xml文件中设置inverse=”true”属性。

双向n-n关联关系的get操作:

@Test    public void testGet(){        Category category = (Category) session.get(Category.class, 1);        System.out.println(category.getName());         //需要连接中间表        Set
items = category.getItems(); System.out.println(items.size()); }

 

 双向n-n关联关系的get操作和单向n-n中一样,包含懒加载机制和内连接。 

  补充一下,双向n-n中两端的映射文件的字段对应如下图所示: 

完事!

 

转载于:https://www.cnblogs.com/java-123/p/10473044.html

你可能感兴趣的文章
第一次使用maven记录
查看>>
SharePoint服务器端对象模型 之 使用CAML进展数据查询
查看>>
Building Tablet PC Applications ROB JARRETT
查看>>
Adobe® Reader®.插件开发
查看>>
【POJ 3461】Oulipo
查看>>
Alpha 冲刺 (5/10)
查看>>
使用Siege进行WEB压力测试
查看>>
斑马为什么有条纹?
查看>>
android多层树形结构列表学习笔记
查看>>
Android_去掉EditText控件周围橙色高亮区域
查看>>
《构建之法》第一、二、十六章阅读笔记
查看>>
arrow:让Python的日期与时间变的更好
查看>>
(转)Excel的 OleDb 连接串的格式(连接Excel 2003-2013)
查看>>
Java并发编程
查看>>
Git Stash用法
查看>>
sql server 2008学习8 sql server存储和索引结构
查看>>
Jquery radio选中
查看>>
postgressql数据库中limit offset使用
查看>>
测试思想-集成测试 关于接口测试 Part 2
查看>>
windows下mysql密码忘了怎么办?【转】
查看>>