1.概述

①双向 n-n 关联需要两端都使用集合属性

②双向n-n关联必须使用连接表

③集合属性应增加 key 子元素用以映射外键列, 集合元素里还应增加many-to-many子元素关联实体类

④在双向 n-n 关联的两边都需指定连接表的表名及外键列的列名. 两个集合元素 set 的 table 元素的值必须指定,而且必须相同。set元素的两个子元素:key 和 many-to-many 都必须指定 column 属性,其中,key 和 many-to-many 分别指定本持久化类和关联类在连接表中的外键列名,因此两边的 key 与 many-to-many 的column属性交叉相同。也就是说,一边的set元素的key的 cloumn值为a,many-to-many 的 column 为b;则另一边的 set 元素的 key 的 column 值 b,many-to-many的 column 值为 a.

⑤对于双向 n-n 关联, 必须把其中一端的 inverse 设置为 true, 否则两端都维护关联关系可能会造成主键冲突.

2.实体类

Category.java

public class Category {

    private Integer id;
private String name;
//添加集合属性
private Set<Item> item = new HashSet<>();
//忽略getter和setter方法
...
}

Item.java

public class Item {

    private Integer id;
private String name;
//添加集合属性
private Set<Category> category = new HashSet<Category>();
//忽略getter和setter方法
...
}

3.映射文件

Category.hbm.xml

<!--
package指定实体类路径,在这个节点中的实体类就可以不用写全类名了,
auto-import设置为true(默认)是表示:使用HQL语句时,即使不指定具体的实体类,Hibernate会自动找到唯一的名称的实体映射,将其补全为全类名,
因为无法确定那个类是所需要的。
-->
<hibernate-mapping package="com.withXml.bothManyToMany.entity" auto-import="false"> <class name="Category" table="BOTH_CATEGORYS"> <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:中间表 column:Category持久化类在中间表的外键-->
<set name="item" table="BOTH_CATEGORY_ITEM" inverse="true">
<key>
<column name="C_ID" />
</key>
<!-- 使用many-to-many指定多对多的关联关系,column:指定Set集合中的持久化类在中间表的外键列的名称,即Item持久化类在中间表的外键 -->
<many-to-many class="Item" column="I_ID"></many-to-many>
</set>
</class>
</hibernate-mapping>

Item.hbm.xml

<hibernate-mapping package="com.withXml.bothManyToMany.entity" auto-import="false">

    <class name="Item" table="BOTH_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>
<!-- table:中间表 column:Item持久化类在中间表的外键-->
<set name="category" table="BOTH_CATEGORY_ITEM" inverse="false" lazy="true">
<key>
<column name="I_ID" />
</key>
<!-- 使用many-to-many指定多对多的关联关系,column:指定Set集合中的持久化类在中间表的外键列的名称,即Category持久化类在中间表的外键 -->
<many-to-many class="Category" column="C_ID"></many-to-many>
</set>
</class>
</hibernate-mapping>

4.CRUD测试

①保存操作

    @Test
public void testSave(){
Category category = new Category();
category.setName("C-AA");
Category category2 = new Category();
category2.setName("C-BB"); Item item = new Item();
item.setName("I-AA");
Item item2 = new Item();
item2.setName("I-BB"); //设定关联关系
category.getItem().add(item);
category.getItem().add(item2); category2.getItem().add(item);
category2.getItem().add(item2); item.getCategory().add(category);
item.getCategory().add(category2); item2.getCategory().add(category);
item2.getCategory().add(category2); //保存操作
session.save(category);
session.save(category2);
session.save(item);
session.save(item2); }

②获取

@Test
public void testGet(){
Category category = (Category) session.get(Category.class, 1);
System.out.println(category.getName());
//支持懒加载
System.out.println(category.getItem().toString()); //需要连接中间表
Set<Item> itmes = category.getItem();
System.out.println(itmes.size());
}

5.总结

①实体类:两端都需要添加集合属性

②映射文件:

Category端

<set> 元素:name属性指定该映射文件所对应的实体类的集合属性

table属性指定中间表,要与另一端映射文件中指定的中间表一致

<key> 元素:column属性指定外键,引用该映射文件对应数据表的主键,即自己的主键

<many-to-many>元素:class属性指定另一端的实体类,column指定外键,引用另一端实体类对应数据表的主键,即对方的主键,该值要与对方<key> 元素值一致

详细如下:

 <!-- table:中间表  column:Category持久化类在中间表的外键-->
<set name="item" table="BOTH_CATEGORY_ITEM" inverse="true">
<key>
<column name="C_ID" />
</key>
<!-- 使用many-to-many指定多对多的关联关系,column:指定Set集合中的持久化类在中间表的外键列的名称,即Item持久化类在中间表的外键 -->
<many-to-many class="Item" column="I_ID"></many-to-many>
</set>

Item端

<set> 元素:name属性指定该映射文件所对应的实体类的集合属性

table属性指定中间表,要与另一端映射文件中指定的中间表一致

<key> 元素:column属性指定外键,引用该映射文件对应数据表的主键,即自己的主键

<many-to-many>元素:class属性指定另一端的实体类,column指定外键,引用另一端实体类对应数据表的主键,即对方的主键,该值要与对方<key> 元素值一致

详细如下:


<!-- table:中间表 column:Item持久化类在中间表的外键-->
<set name="category" table="BOTH_CATEGORY_ITEM" inverse="false" lazy="true">
<key>
<column name="I_ID" />
</key>
<!-- 使用many-to-many指定多对多的关联关系,column:指定Set集合中的持久化类在中间表的外键列的名称,即Category持久化类在中间表的外键 -->
<many-to-many class="Category" column="C_ID"></many-to-many>
</set>

③必须把其中一端的 inverse 设置为 true, 否则两端都维护关联关系可能会造成主键冲突.

Hibernate(9)_双向n对n的更多相关文章

  1. Hibernate(10)_双向n对1(双向1对n)

    1.双向 1-n 与 双向 n-1 是完全相同的两种情形,这里使用双向多对一来演示 双向 1-n 需要在 1 的一端可以访问 n 的一端, 反之依然. 出版社和图书的关系:Publishers--Bo ...

  2. 转:HIBERNATE一些_方法_@注解_代码示例---写的非常好

    HIBERNATE一些_方法_@注解_代码示例操作数据库7步骤 : 1 创建一个SessionFactory对象 2 创建Session对象 3 开启事务Transaction : hibernate ...

  3. hibernate多对一双向关联

    关联是类(类的实例)之间的关系,表示有意义和值得关注的连接. 本系列将介绍Hibernate中主要的几种关联映射 Hibernate一对一主键单向关联Hibernate一对一主键双向关联Hiberna ...

  4. hibernate one-to-many many-to-one 双向注解

    建表语句: DROP TABLE IF EXISTS `t_company`; CREATE TABLE `t_company` ( `companyId` ) unsigned NOT NULL A ...

  5. Java进阶知识12 Hibernate多对多双向关联(Annotation+XML实现)

    1.Annotation 注解版 1.1.应用场景(Student-Teacher):当学生知道有哪些老师教,老师也知道自己教哪些学生时,可用双向关联 1.2.创建Teacher类和Student类 ...

  6. Hibernate(12)_基于主键的双向1对1

    一.基于主键的双向1对1 1.介绍: 基于主键的映射策略:指一端的主键生成器使用 foreign 策略,表明根据"对方"的主键来生成自己的主键,自己并不能独立生成主键. <p ...

  7. Hibernate(11)_基于外键的双向1对1

    一.基于外键的双向1对1 对于基于外键的1-1关联,其外键可以存放在任意一边,在需要存放外键一端,增加many-to-one元素.为many-to-one元素增加unique="true&q ...

  8. 【SSH系列】hibernate映射 -- 一对一双向关联映射

    开篇前言 上篇博文[SSH进阶之路]hibernate映射--一对一单向关联映射,小编介绍了一对一的单向关联映射,单向是指只能从人(Person)这端加载身份证端(IdCard),但是反过来,不能从身 ...

  9. Hibernate多对多双向关联的配置

    Hibernate的双向多对多关联有两种配置方法:那我们就来看看两种方案是如何配置的.  一.创建以各自类为类型的集合来关联 1.首先我们要在两个实体类(雇员<Emploee>.工程< ...

随机推荐

  1. Appearance-and-Relation Networks for Video Classification论文笔记 (ARTnet)

    ARTnet: caffe实现:代码 1 Motivation:How to model appearance and relation (motion) 主要工作是在3D卷积的基础上,提升了acti ...

  2. iTOP4412环境搭建:arm-linux-gcc: 没有那个文件或目录

    系统:vmware下的ubuntu14.04 对于iTOP4412自己搭建环境,在source /root/.bashrc后发现还是没有正常,调用arm-linux-gcc -v提示没有那个文件或目录 ...

  3. 使用spark操作kudu

    Spark与KUDU集成支持: DDL操作(创建/删除) 本地Kudu RDD Native Kudu数据源,用于DataFrame集成 从kudu读取数据 从Kudu执行插入/更新/ upsert ...

  4. glusterfs分布式复制扩容卷以及平衡卷

    随着数据量的增长,需要扩容满足使用.今天测试下glusterfs磁盘扩容的具体步骤 1.扩容 之前用的2台计算机的分布式复制卷.需要同时之两个服务器增加一块磁盘并格式化,挂载并扩容 热添加磁盘 ech ...

  5. es6 promise对象

    function next(){ return new Promise( function( resolve, reject ){ var num =7 // Math.floor( Math.ran ...

  6. 51Nod1773 A国的贸易 多项式 FWT

    原文链接https://www.cnblogs.com/zhouzhendong/p/51Nod1773.html 题目传送门 - 51Nod1773 题意 给定一个长度为 $2^n$ 的序列,第 $ ...

  7. BZOJ4556 [Tjoi2016&Heoi2016]字符串 SA ST表 二分答案 主席树

    原文链接https://www.cnblogs.com/zhouzhendong/p/BZOJ4556.html 题目传送门 - BZOJ4556 题意 给定一个长度为 $n$ 的字符串 $s$ . ...

  8. [ 高危 ] my网任意账户登陆

    该网站的任意登录其实都已经提交得差不多了,本来以为这个漏洞会是一个重复的,然而试了一下发现思路奇葩. 任意登录,一般都为验证码爆破,4位手机验证码,而用于拦截的图片验证码没有或者可以重复使用,所以就能 ...

  9. js获取http请求响应头信息

    var req = new XMLHttpRequest(); req.open('GET', document.location, false); req.send(null); var heade ...

  10. BZOJ.4340.[BJOI2015]隐身术(后缀数组 搜索)

    BZOJ \(Description\) 给定两个串\(S,T\)以及一个数\(k\),求\(T\)中有多少个子串,满足和\(S\)的编辑距离不超过\(k\). \(|S|+|T|\leq10^5,\ ...