zoukankan      html  css  js  c++  java
  • Hibernate(9)_双向n对n

    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, 否则两端都维护关联关系可能会造成主键冲突.

  • 相关阅读:
    4、redis之使用commons-pool
    好用的eclipse properties插件
    1、redis之安装与配置
    谷歌浏览器禁止window.close的问题
    在浏览器中使用JS打开并展示PDF文件
    JAVA遍历Map的方法
    GEOS库学习之三:空间关系、DE-9IM和谓词
    GEOS库的学习之二:简单几何图形的创建
    GEOS库的学习之一:介绍和编译
    GEOS库在windows中的编译和测试(vs2012)
  • 原文地址:https://www.cnblogs.com/tengpengfei/p/10453955.html
Copyright © 2011-2022 走看看