标签:
前两篇说了 Hibernate 的一对一和一对多, 这一篇说一下 Hibernate 关联关系中的多对多. 说完这个Hibernate的关联关系就结束了.
分类:
1. 单向多对多
2. 双向多对多
要想实现多对多关系, 必须提供中间表, 用外键的方式无法实现.
这里咱们用 分类(Category)和单品(Item) 来举例子.
OneByOne
一: 单向多对多
准备工作:
1. 建立持久化类
Category类:
package com.single.many2many; import java.util.HashSet; import java.util.Set; public class Category { private Integer id; private String name; private Set<Item> items = new HashSet<>(); public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Set<Item> getItems() { return items; } public void setItems(Set<Item> items) { this.items = items; } }
Item类:
package com.single.many2many; public class Item { private Integer id; private String name; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
2. 建立映射文件
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.single.many2many"> <class name="Category" table="CATEGORYS"> <id name="id" type="java.lang.Integer"> <column name="ID" /> <generator class="identity" /> </id> <property name="name" type="java.lang.String"> <column name="NAME" /> </property> <!-- table: 中间表表名 <key column="C_ID"></key>: 本数据表在中间表中的列名 <many-to-many class="Item" column="I_ID"></many-to-many>: 集合中元素的数据表在中间表中的列名 --> <set name="items" table="CATEGORY_ITEMS"> <key column="C_ID"></key> <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 package="com.single.many2many"> <class name="Item" table="ITEMS"> <id name="id" type="java.lang.Integer"> <column name="ID" /> <generator class="identity" /> </id> <property name="name" type="java.lang.String"> <column name="NAME" /> </property> </class> </hibernate-mapping>
3. 建立Hibernate的主配置文件 hibernate.cfg.xml, 并把 Item.hbm.xml, Category.hbm.xml 加入到 配置文件中.
4. 建立单元测试类:
package com.single.many2many; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import org.junit.After; import org.junit.Before; import org.junit.Test; public class TestHibernate { private SessionFactory sessionFactory; private Session session; private Transaction transaction; @Before public void init(){ sessionFactory = new Configuration().configure().buildSessionFactory(); session = sessionFactory.openSession(); transaction = session.beginTransaction(); } @After public void distory(){ transaction.commit(); session.close(); sessionFactory.close(); } }
1. 测试保存数据
@Test public void testInsert(){ Category category1 = new Category(); category1.setName("Category-01"); Item item1 = new Item(); item1.setName("item-01"); Item item2 = new Item(); item2.setName("item-02"); Item item3 = new Item(); item3.setName("item-03"); // 设置关联关系 category1.getItems().add(item1); category1.getItems().add(item2); category1.getItems().add(item3); session.save(item1); session.save(item2); session.save(item3); session.save(category1); }
2. 测试查询数据
@Test public void testQuery(){ Category category = session.get(Category.class, 1); System.out.println(category.getName()); // 会连接中间表进行查询 System.out.println(category.getItems().iterator().next().getName()); System.out.println(category.getItems().size()); }
3. 测试删除数据(略)
4. 测试更新数据(略)
二: 双向多对多
双向多对多与单向多对多差不多, 在单向多对多中我们在 Category类中添加了 Item 的集合, 现在我们不仅在 Category类中添加了 Item 的集合, 还要在 Item类中添加了 Category的集合.
在上面的测试基础上修改几个地方:
1. 修改 Item 类:
package com.single.many2many; import java.util.Set; public class Item { private Integer id; private String name; private Set<Category> categories = new HashSet<>(); // getter/setter... }
2. 修改 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 package="com.single.many2many"> <class name="Item" table="ITEMS"> <id name="id" type="java.lang.Integer"> <column name="ID" /> <generator class="identity" /> </id> <property name="name" type="java.lang.String"> <column name="NAME" /> </property> <!-- 双向 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, 否则两端都维护关联关系可能会造成主键冲突. --> <set name="categories" table="CATEGORY_ITEMS"> <key column="I_ID"></key> <many-to-many class="Category" column="C_ID"></many-to-many> </set> </class> </hibernate-mapping>
xml中的说明我感觉应该挺详细了. 如果不懂可以给我发消息.
1. 测试保存数据
@Test public void testSave(){ Category category1 = new Category(); category1.setName("Category-04"); Category category2 = new Category(); category2.setName("Category-05"); Category category3 = new Category(); category3.setName("Category-06"); Item item1 = new Item(); item1.setName("item-04"); Item item2 = new Item(); item2.setName("item-05"); Item item3 = new Item(); item3.setName("item-06"); category1.getItems().add(item1); category1.getItems().add(item2); item1.getCategories().add(category1); item2.getCategories().add(category1); item2.getCategories().add(category2); item2.getCategories().add(category3); session.save(item1); session.save(item2); session.save(item3); session.save(category1); session.save(category2); session.save(category3); }
2. 测试查询数据(同单向多对多)
3. 测试删除数据(略)
4. 测试更新数据(略)
动手敲才是硬道理!
标签:
原文地址:http://www.cnblogs.com/wuqinglong/p/5149311.html