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

单向的n-n关联关系

  如果仅使用两张数据表,是不能实现n-n的关联关系的,如下图:
  
  商品ITEM_AA属于商品种类CATEGORY_AA,但是如果商品ITEM_AA又同时属于商品种类CATEGORY_BB呢,两张数据表无法实现这种关系,所以我们需要使用到连接表,如下图所示:
  
  我们添加一张连接表,其中的每一条记录表示某一个商品和某一个商品种类的对应关系。
  单向的n-n关联关系的域模型和关系数据模型如下图所示:
  
  下面来实现这种关系,首先新建两个类:

public class Category {private Integer id;private String name;private Set<Item> items = new HashSet<>();//getters and setters
}public class Item {private Integer id;private String name;//getters and setters
}

生成并编辑映射文件:
 
Category.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><hibernate-mapping package="com.atguigu.hibernate.n2n"><class name="Category" table="CATEGORIES"><id name="id" type="java.lang.Integer"><column name="ID" /><generator class="native" /></id><property name="name" type="java.lang.String"><column name="NAME" /></property><!-- table: 指定中间表 --><set name="items" table="CATEGORIES_ITEMS"><key><column name="C_ID" /></key><!-- 使用 many-to-many 指定多对多的关联关系. column 执行 Set 集合中的持久化类在中间表的外键列的名称  --><many-to-many class="Item" column="I_ID"></many-to-many></set></class>
</hibernate-mapping>

Item.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><hibernate-mapping><class name="com.atguigu.hibernate.n2n.Item" table="ITEMS"><id name="id" type="java.lang.Integer"><column name="ID" /><generator class="native" /></id><property name="name" type="java.lang.String"><column name="NAME" /></property></class>
</hibernate-mapping>

  与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操作:

@Testpublic void testSave(){Category category1 = new Category();category1.setName("C-AA");Category category2 = new Category();category2.setName("C-BB");Item item1 = new Item();item1.setName("I-AA");Item item2 = new Item();item2.setName("I-BB");//设定关联关系category1.getItems().add(item1);category1.getItems().add(item2);category2.getItems().add(item1);category2.getItems().add(item2);//执行保存操作session.save(category1);session.save(category2);session.save(item1);session.save(item2);}

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

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

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

双向的n-n关联关系

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

public class Category {private Integer id;private String name;private Set<Item> items = new HashSet<>();//getters and setters
}public class Item {private Integer id;private String name;private Set<Category> categories = new HashSet<>();//getters and setters
}

生成并编辑映射文件:
 
Category.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><hibernate-mapping package="com.atguigu.hibernate.n2n"><class name="Category" table="CATEGORIES"><id name="id" type="java.lang.Integer"><column name="ID" /><generator class="native" /></id><property name="name" type="java.lang.String"><column name="NAME" /></property><!-- table: 指定中间表 --><set name="items" table="CATEGORIES_ITEMS"><key><column name="C_ID" /></key><!-- 使用 many-to-many 指定多对多的关联关系. column 执行 Set 集合中的持久化类在中间表的外键列的名称  --><many-to-many class="Item" column="I_ID"></many-to-many></set></class>
</hibernate-mapping>

Item.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><hibernate-mapping><class name="com.atguigu.hibernate.n2n.Item" table="ITEMS"><id name="id" type="java.lang.Integer"><column name="ID" /><generator class="native" /></id><property name="name" type="java.lang.String"><column name="NAME" /></property><set name="categories" table="CATEGORIES_ITEMS" inverse="true"><key column="I_ID"></key><many-to-many class="com.atguigu.hibernate.n2n.Category" column="C_ID"></many-to-many></set></class>
</hibernate-mapping>

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

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

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

  下面测试save操作和get操作:
  
双向n-n关联关系的save操作:

Category category1 = new Category();category1.setName("C-AA");Category category2 = new Category();category2.setName("C-BB");Item item1 = new Item();item1.setName("I-AA");Item item2 = new Item();item2.setName("I-BB");//设定关联关系category1.getItems().add(item1);category1.getItems().add(item2);category2.getItems().add(item1);category2.getItems().add(item2);item1.getCategories().add(category1);item1.getCategories().add(category2);item2.getCategories().add(category1);item2.getCategories().add(category2);//执行保存操作session.save(category1);session.save(category2);session.save(item1);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操作:

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

  双向n-n关联关系的get操作和单向n-n中一样,包含懒加载机制和内连接。
  补充一下,双向n-n中两端的映射文件的字段对应如下图所示:
  

Hibernate的多对多关联关系(单向和双向)相关推荐

  1. (转)Hibernate框架基础——多对多关联关系映射

    http://blog.csdn.net/yerenyuan_pku/article/details/52756536 多对多关联关系映射 多对多的实体关系模型也是很常见的,比如学生和课程的关系.一个 ...

  2. Hibernate的一对多关联关系(单向和双向)

    在领域模型中,类与类之间最普遍的关系就是关联关系.在 UML 中,关联是有方向的.以 Customer 和 Order 为例:一个用户能发出多个订单, 而一个订单只能属于一个客户.从 Order 到 ...

  3. 关于Hibernate多对多关联关系的更新问题。

    一个账套类Reckoning和账套项目类 AccountItem.这两个类是双向多对多关联关系. Reckoning.hbm.xml文件的配置如下 <set name="account ...

  4. hibernate的多对多

    1. 数据库的多对多 1.1 数据库中不能直接映射多对多 处理:创建一个桥接表(中间表),将一个多对多关系转换成两个一对多 注1:数据库多表联接查询永远就是二个表的联接查询A B C Dt1 C Dt ...

  5. Django框架(十)--常用字段、参数、元信息、多对多关联关系

    一.ORM字段 # AutoField() int自增列,必须填入参数 primary_key=True.当model中如果没有自增列,则自动会创建一个列名为id的列# IntegerField() ...

  6. java多对多关联数据操作,hibernate实施多对多关联查询时,关联表数据被删除

    hibernate执行多对多关联查询时,关联表数据被删除 本帖最后由 binbb521 于 2012-12-04 11:48:29 编辑 S2SH框架开发的网站,执行两个多对多关系的表查询时,关联两个 ...

  7. WCF简单教程(6) 单向与双向通讯

    第六篇:单向与双向通讯 项目开发中我们时常会遇到需要异步调用的问题,有时忽略服务端的返回值,有时希望服务端在需要的时候回调,今天就来看看在WCF中如何实现. 先看不需要服务端返回值的单向调用,老规矩, ...

  8. 地址总线是单向还是双向_如何区分晶闸管的单双向问题?

    可控硅又叫做晶闸管,是一种常用的半导体器件,是一种能像闸门一样控制电流大小的半导体器件.因此,可控硅也具有开关控制.电压调整和整流等功能.可控硅的种类较多,强电电路采用的可控硅主要有单向晶闸管和双向晶 ...

  9. hibernate之多对多关联映射

    hibernate之多对多关联映射 转载于:https://www.cnblogs.com/liuyang-1037/archive/2009/06/06/1497589.html

最新文章

  1. 数据库设计和管理规范
  2. ZOJ Monthly, January 2013
  3. sql求平均日活_杨学峰博客 | Flask Sqlarchemy实现按日、周、月统计并图表展示
  4. JDK 14的新特性:文本块Text Blocks
  5. 用户注册的mysql代码_用户的注册登陆流程及代码实现
  6. [蓝桥杯][基础练习VIP]完美的代价-贪心
  7. C#中的泛型化方法的实现
  8. 信息学奥赛C++语言:插队问题
  9. JAVA8的双重循环怎么优化_Java8处理List的双层循环问题代码实例
  10. OpenShift4 - 使用 Service CA 证书增加内部通讯安全
  11. (C语言)验证哥德巴赫猜想,输入一个大于6的偶数,输出这个数能被分解为哪两个质数的和
  12. MySQL 死锁专题问题处理
  13. listview 刷新某一个item
  14. 拼接大屏数据展示_4K高清拼接屏大数据点对点显示解决方案
  15. Hi3519AV100 SDK文档解读
  16. 战舰少女r魔盒服务器维护,战舰少女r魔盒官方
  17. 商业融资项目计划PPT模板
  18. 【html5期末大作业】基于HTML仿QQ音乐官网网站
  19. layui框架实战案例(8):web图片裁切插件croppers.js组件实现上传图片的自定义截取(含php后端)
  20. 苹果手机使用技巧篇:教你完美使用好苹果手机的4个方法

热门文章

  1. SQL Serve 安装相关错误
  2. Mac苹果电脑MacBook Air、MacBook Pro怎么安装win10双系统或Windows软件
  3. 科技云报道:大小巨头涌入赛道,隐私计算迎来商业落地元年
  4. android gridlayout点击事件,Android GridLayout
  5. javascript/JS限制用户名只能输入字母和数字下划线
  6. spring-boot-starter-parent
  7. 如何启动虚拟磁盘服务器,Hyper-V管理实战之添加虚拟硬盘
  8. 银川计算机学院,刘立波
  9. Android permission 权限大全
  10. unity全局雾处理