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

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

public class Books {

    private Integer Id;
    private String Title;
    private String Author;
    private String ISBN;
    private int WordCount;
    private double UnitPrice;
    private String ContentDescription;
    //实体类类型属性
    private Publishers publisher;
    //忽略getter和setter方法
    ...
}

1端
Publishers.java

public class Publishers {

    private Integer id;
    private String Name;
    //集合属性
    private Set<Books> bks = new HashSet<>();
    //忽略getter和setter方法
    ...
}

3.映射文件
n端:

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

    <class name="Books" table="BOTH_BOOKS">

        <id name="Id" type="java.lang.Integer" access="field">
            <column name="ID" />
            <generator class="native" />
        </id>

        <property name="Title" type="java.lang.String">
            <column name="TITLE" />
        </property>

        <property name="Author" type="java.lang.String">
            <column name="AUTHOR" />
        </property>

        <property name="ISBN" type="java.lang.String">
            <column name="ISBN" />
        </property>

        <property name="WordCount" type="integer">
            <column name="WORD_COUNT"/>
        </property>

        <!-- 映射数据表字段你的类型,可以在property 里面使用type设置,也可以在column里面使用 sql-type-->
        <property name="UnitPrice">
            <column name="UNIT_PRICE" sql-type="double" />
        </property>

        <property name="ContentDescription" type="java.lang.String">
            <column name="CONTENT_DESCRIPTION" />
        </property>

        <!-- 配置多对一关联映射 -->
        <many-to-one name="publisher" class="Publishers" 
            column="PUBLISHER_ID" cascade="save-update"></many-to-one>
    </class>
</hibernate-mapping>

1端

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

    <class name="Publishers" table="BOTH_PUBLISHERS">

        <id name="id" type="java.lang.Integer" access="field">
            <column name="ID" />
            <generator class="native" />
        </id>

        <property name="Name" type="java.lang.String">
            <column name="NAME" />
        </property>

        <!-- 
            cascade(级联)级联的意思是指两个对象之间的操作联运关系,对一个对象执行了操作之后,
            对其指定的级联对象也需要执行相同的操作,取值:all,none,save_update,delete。
              1.all:代码在所有情况下都执行级联操作
              2.none:在所有情况下都不执行级联操作
              3.save-update:在保存和更新的情况下执行级联操作
              4.delete:在删除的时候执行级联操作
             inverse:属性设置为true代表一的一方不在拥有关联关系的控制权,而把控制权交给多的一方    
         -->
        <set name="bks" lazy="false" inverse="true" cascade="save-update,delete">
            <!-- <key>指定PUBLISHERS数据表的外键,使用的是BOOKS表中的PUBLISHER_ID列 -->
            <key column="PUBLISHER_ID"></key>
            <one-to-many class="Books"/>
        </set>
    </class>
</hibernate-mapping>

4.CRUD测试
①保存

/**
     * 保存操作,保存1的一端
     */
    @Test
    public void testBothManyToOneSave(){
        //创建出版社对象
        Publishers publisher = new Publishers();
        publisher.setName("北京大学出版社");

        //新建图书对象
        Books book = new Books();
        book.setTitle("大学英语");
        book.setISBN("2018012103");
        book.setAuthor("李玲");
        book.setWordCount(10000);
        book.setUnitPrice(95.5);
        book.setContentDescription("无");

        //新建图书对象
        Books book2 = new Books();
        book2.setTitle("管理学");
        book2.setISBN("2018012104");
        book2.setAuthor("张青");
        book2.setWordCount(10000);
        book2.setUnitPrice(95.5);
        book2.setContentDescription("无");

        //双向维护关系
        //设置关联关系,指定一到多的关联关系  ,若由1端维护关系,会产生update语句,影响效率,
        //所以在1端映射文件中设置inverse="true",控制权交给n端维护关系
        publisher.getBks().add(book);
        publisher.getBks().add(book2);

        //设置关联关系,指定多到一的关联关系  
        book.setPublisher(publisher);
        book2.setPublisher(publisher);

        //执行保存,设置cascade级联属性之后,
        //只保存一端即可(哪一端设置级联属性,可以只保存那一段,两端都设置,则任意一端都可以执行保存)
        session.save(publisher);
    }

②保存2

    /**
     * 保存操作
     */
    @Test
    public void testBothManyToOneSave2(){
        //创建出版社对象
        Publishers publisher = new Publishers();
        publisher.setName("北京大学出版社");

        //新建图书对象
        Books book = new Books();
        book.setTitle("大学英语");
        book.setISBN("2018012103");
        book.setAuthor("李玲");
        book.setWordCount(10000);
        book.setUnitPrice(95.5);
        book.setContentDescription("无");

        //新建图书对象
        Books book2 = new Books();
        book2.setTitle("管理学");
        book2.setISBN("2018012104");
        book2.setAuthor("张青");
        book2.setWordCount(10000);
        book2.setUnitPrice(95.5);
        book2.setContentDescription("无");

        //双向维护关系
        //设置关联关系,指定一到多的关联关系  ,因为会产生update语句,影响效率
        //publisher.getBks().add(book);
        //publisher.getBks().add(book2);

        //设置关联关系,指定多到一的关联关系  
        book.setPublisher(publisher);
        book2.setPublisher(publisher);

        //执行保存,设置cascade级联属性之后,
        //只保存一端即可(哪一端设置级联属性,可以只保存那一段,两端都设置,则任意一端都可以执行保存)
        session.save(book);
        session.save(book2);
    }

③查询

/**
     * 查询操作
     * 查询某出版社出版的图书
     */
    @Test
    public void testBothManyToOneGet(){
        Publishers publisher = (Publishers) session.get(Publishers.class, 1);
        Iterator<Books> iterator = publisher.getBks().iterator();
        System.out.println(publisher.getName() + "出版的图书有:");
        while(iterator.hasNext()){
            Books book = iterator.next();
            System.out.println(book.getTitle());
        }
    }

④修改

/**
     * 修改操作
     * 把id为1的图书所对应的id为1出版社修改为id为2出版社
     */
    @Test
    public void testBothManyToOneUpdate(){
        //获取出版社对象
        Publishers publisher = (Publishers) session.get(Publishers.class, 1);

        //获取图书对象
        Books book = (Books) session.get(Books.class, 1);
        book.setPublisher(publisher);

        session.update(book);
    }

⑤n端删除

/**
     * 删除操作,删除图书信息
     * 
     */
    @Test
    public void testBothManyToOneDelete(){
        Books book = (Books) session.get(Books.class, 12);
        session.delete(book);

    }

⑥1端删除

/**
     * 删除操作,删除出版社信息,以及出版社出版的图书
     * 
     */
    @Test
    public void testBothManyToOneDelete2(){
        Publishers publisher = (Publishers) session.get(Publishers.class, 1);
        session.delete(publisher);
    }

五.总结
(双向n对1):其实就是单向n对1和单向1对n同时使用
1端
①实体类:添加集合属性
②映射文件:使用<set> 元素映射集合属性,
name属性指定映射的属性名
inverse属性设置为true代表一的一方不在拥有关联关系的控制权,而把控制权交给多的一方
<key> 元素指定外键,属性值要与n端的<many-to-one> 元素的column属性值一致,
使用<one-to-many class="Books"/> 元素映射关联关系
详细如下:

  <!-- 
cascade(级联)级联的意思是指两个对象之间的操作联运关系,对一个对象
执行了操作之后,对其指定的级联对象也需要执行相同的操作,
取值:all,none,save_update,delete。
 1.all:代码在所有情况下都执行级联操作
 2.none:在所有情况下都不执行级联操作
 3.save-update:在保存和更新的情况下执行级联操作
 4.delete:在删除的时候执行级联操作
inverse:属性设置为true代表一的一方不在拥有关联关系的控制权,
而把控制权交给多的一方 
         -->
<set name="bks" lazy="false" inverse="true" cascade="save-update,delete">
<!-- <key>指定外键 -->
    <key column="PUBLISHER_ID" not-null="true"></key>
    <one-to-many class="Books"/>
</set>

n端:
①实体类:添加一个n端实体类型的属性
②映射文件:使用<many-to-one> 元素映射实体类型的属性,column属性指定外键,class指定关联的类的名字。
详细如下:

<!-- 配置多对一关联映射 -->
<many-to-one name="publisher" class="Publishers"
         column="PUBLISHER_ID" cascade="save-update">
</many-to-one>
原文地址:https://www.cnblogs.com/tengpengfei/p/10453954.html