【Hibernate学习笔记】11:使用one-to-many和many-to-one将N-M关联拆分为两个1-N关联

实际使用时原生的N-M关联用的不多,因为这样的N-M关联表是自动生成的,只能含有两个表的主键,而不能带有其它信息。但实际上往往会带有其它属性:
这里写图片描述
如订单本身可以有购买数目这一属性,还可以有当时折扣等属性。这时就要去人为建立订单表了,然后顾客到商品的N-M关联可以拆分成两个1-N关联,借助这个自己建立的订单表。
这里写图片描述
注意在1-N关联的配置时,1方映射文件的<set .../>里使用inverse="true"属性来让顾客、商品等作为订单这种弱实体主控对象,即是由顾客、商品信息的变化去更新订单这张表,而不应该是反过来的。

Customer类的属性

组合订单类对象。

    private Integer id;
    private String userName;
    private String password;
    private Set<Order> ordr;// 组合订单的集合

Customer.hbm.xml

对于cascade="all"这里应当慎重考虑,有些时候用户被删除,但是用户的行为(订单信息)应当保存下来,这时候就应该设置成cascade="save-update"了。

<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="myPOJO">
    <class name="Customer" table="CUSTOMER">

        <!-- 指定saveOrUpdate为null时插入,非null时更新 -->
        <id name="id" column="ID" unsaved-value="null">
            <generator class="native" />
        </id>

        <property name="userName" column="USERNAME" type="string"
            not-null="true" />
        <property name="password" column="PASSWORD" type="string"
            not-null="true" />

        <!-- 用组合的set属性配置1-N关联 -->
        <set name="ordr" table="ORDERMSG" cascade="all" inverse="true">
            <!-- 设置在关联表中关于本表的外键名 -->
            <key column="CUSID" />
            <!-- 指出1-N关联的N方的实现类 -->
            <one-to-many class="Order" />
        </set>

    </class>
</hibernate-mapping>

Product类的属性

同样地要组合订单类的对象。

    private Integer id;
    private String proName;
    private Double price;
    private Set<Order> ordr;// 组合订单的集合

Product.hbm.xml

<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="myPOJO">
    <class name="Product" table="PRODUCT">

        <!-- 指定saveOrUpdate为null时插入,非null时更新 -->
        <id name="id" column="ID" unsaved-value="null">
            <generator class="native" />
        </id>

        <property name="proName" column="PRONAME" type="string"
            not-null="true" />
        <property name="price" column="PRICE" type="double" not-null="true" />

        <!-- 用组合的set属性配置1-N关联 -->
        <set name="ordr" table="ORDERMSG" cascade="all" inverse="true">
            <!-- 设置在关联表中关于本表的外键名 -->
            <key column="PROID" />
            <!-- 指出1-N关联的N方的实现类 -->
            <one-to-many class="Order" />
        </set>

    </class>
</hibernate-mapping>

Order类的属性

组合了左右两个类的对象,把它们关联起来。

    private Integer id;// 订单号
    private Customer cus;// 顾客对象引用
    private Product pro;// 商品对象引用
    private int num;// 购买数目(不能为空所以没用包装类)
    private Double discount;// 折扣(可以为空)

Order.hbm.xml

往两边配置N-1映射。

<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="myPOJO">
    <class name="Order" table="ORDERMSG">

        <!-- 指定saveOrUpdate为null时插入,非null时更新 -->
        <id name="id" column="ID" unsaved-value="null">
            <generator class="native" />
        </id>

        <!-- 配置两个方向的N-1关联关系,给出实现类和对应的字段名 -->
        <many-to-one name="cus" class="Customer" column="CUSID" />
        <many-to-one name="pro" class="Product" column="PROID" />

        <property name="num" column="NUM" type="integer" not-null="true" />
        <property name="discount" column="DISCOUNT" type="double"/>

    </class>
</hibernate-mapping>

Main.java

同样也是,为了存储只对一侧设置关联就够了。

package myApplication;

import java.util.HashSet;
import java.util.Set;

import myPOJO.Customer;
import myPOJO.Order;
import myPOJO.Product;
import myTools.HibernateUtils;

import org.hibernate.Session;
import org.hibernate.Transaction;

public class Main {

    public static void main(String[] args) {
        // 先分别建立这两个类的对象
        Product pro1 = new Product("子弟薯片", 6.0, null);
        Product pro2 = new Product("冰红茶", 3.5, null);
        Customer cus1 = new Customer("刘知昊", "123", null);

        // 建立关联类(订单)的对象
        Order ordr1 = new Order(cus1, pro1, 5, 0.3);
        Order ordr2 = new Order(cus1, pro2, 7, null);

        // 设置关联
        // 在持久化时可以不做设置关联,直接把关联对象本身持久化
        // 也可以只做一侧,然后不必持久化关联对象,下面使用制作一侧的方式
        Set<Order> st_cus1 = new HashSet<Order>();
        st_cus1.add(ordr1);
        st_cus1.add(ordr2);
        cus1.setOrdr(st_cus1);

        // 获取Session对象
        Session sssn = HibernateUtils.getSession();
        // 开启事务
        Transaction trnsctn = sssn.beginTransaction();

        // 持久化PO
        sssn.save(pro1);
        sssn.save(pro2);
        sssn.save(cus1);

        // 提交事务
        trnsctn.commit();
        // 关闭Session实例并且把ThreadLocal中的副本清除
        HibernateUtils.closeSession();
    }
}

刚做的时候一个BUG坑了很久,原来ORDER是SQL关键字,拿它做表名才出了语法问题,所以改成了ORDERMSG。

运行结果

控制台输出:

Hibernate: insert into PRODUCT (PRONAME, PRICE) values (?, ?)
Hibernate: insert into PRODUCT (PRONAME, PRICE) values (?, ?)
Hibernate: insert into CUSTOMER (USERNAME, PASSWORD) values (?, ?)
Hibernate: insert into ORDERMSG (CUSID, PROID, NUM, DISCOUNT) values (?, ?, ?, ?)
Hibernate: insert into ORDERMSG (CUSID, PROID, NUM, DISCOUNT) values (?, ?, ?, ?)

数据库内生成:
这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

猜你喜欢

转载自blog.csdn.net/shu15121856/article/details/80143854
今日推荐