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. php7安装参数编译

    系统:Centos6.8 软件包:php-7.0.14.tar.gz yum install bzip2 bzip2-devel -y yum install curl curl-devel -y y ...

  2. url、querystring模块获取请求request.url中的不同部分图解

    url.parse(string).query | url.parse(string).pathname | | | | | ------ ------------------- http://loc ...

  3. Apache Tomcat RCE(CVE-2017-12615 )漏洞案例分析

    首先搭建tomcat环境: 下载当前项目的版本的tomcat

  4. 2018牛客网暑假ACM多校训练赛(第五场)F take 树状数组,期望

    原文链接https://www.cnblogs.com/zhouzhendong/p/NowCoder-2018-Summer-Round5-F.html 题目传送门 - https://www.no ...

  5. HDU2732 Leapin' Lizards 网络流 最大流 SAP

    原文链接http://www.cnblogs.com/zhouzhendong/p/8362002.html 题目传送门 - HDU2732 题意概括 给你一个网格,网格上的一些位置上有一只蜥蜴,所有 ...

  6. Clairewd’s message ekmp

    给两个串第一个串是翻译表(密文可以通过翻译表翻译成明文),第二个串是由密文+明文组成,前面是密文(完整的),后面是明文(未必完整),问能不能把第二个串补全,输出最短的一种可能. 一开始 用的strin ...

  7. POJ 3061 Subsequence【二分答案】||【尺取法】

    <题目链接> 题目大意: 给你一段长度为n的整数序列,并且给出一个整数S,问你这段序列中区间之和大于等于S的最短区间长度是多少. 解题分析:本题可以用二分答案做,先求出前缀和,然后枚举区间 ...

  8. HDU3339 In Action 【最短路】+【01背包】

    <题目链接> 题目大意: 给出一个0-n组成的图,1-n的点上分布着值为pow的电站,给出图的m条边以及距离,从0出发到n个点中的x个点的行走距离和最小(因为是每炸一个点派出一辆坦克),且 ...

  9. JavaScript函数、闭包、原型、面向对象

    JavaScript函数.闭包.原型.面向对象 断言 单元测试框架的核心是断言方法,通常叫assert(). 该方法通常接收一个值--需要断言的值,以及一个表示该断言目的的描述. 如果该值执行的结果为 ...

  10. Django基础(一)

    Django基础(一) 知识预览 Django基本命令 二 路由配置系统(URLconf) 三 编写视图 四 Template 五 数据库与ORM admin的配置 一 什么是web框架? 框架,即f ...