04. 关联关系映射(一对多)

关联关系映射

一对多双向关联关系(Order和OrderLine)

我们使用订单(Order)和订单项(OrderLine)来演示这种关系

一对多双向关联关系的表结构

Order表

CREATE TABLE t_order(
    id number(10) PRIMARY KEY,
    ordered_date date NOT NULL,
    shipped_date date,
    total number(10,2)
)

OrderLine表

CREATE TABLE t_orderline(
    id number(10) PRIMARY KEY,
    price number(10,2),
    quantity number(10),
    product varchar2(30),
    order_id number(10) REFERENCES t_order(id)
)
一对多双向关联关系的类结构

Order类

package com.li.association.one2many.pojo;

import java.io.Serializable;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;

public class Order implements Serializable{

    private static final long serialVersionUID = 1L;

    private Long id;
    private Date orderedDate;
    private Date shippedDate;
    private Double total;

    private Set<OrderLine> orderLines=new HashSet<OrderLine>();

    public Order() {}

    public Order(Long id, Date orderedDate, Date shippedDate, Double total, Set<OrderLine> orderLines) {
        super();
        this.id = id;
        this.orderedDate = orderedDate;
        this.shippedDate = shippedDate;
        this.total = total; 
        this.orderLines = orderLines;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public Date getOrderedDate() {
        return orderedDate;
    }

    public void setOrderedDate(Date orderedDate) {
        this.orderedDate = orderedDate;
    }

    public Date getShippedDate() {
        return shippedDate;
    }

    public void setShippedDate(Date shippedDate) {
        this.shippedDate = shippedDate;
    }

    public Double getTotal() {
        return total;
    }

    public void setTotal(Double total) {
        this.total = total;
    }

    public Set<OrderLine> getOrderLines() {
        return orderLines;
    }

    public void setOrderLines(Set<OrderLine> orderLines) {
        this.orderLines = orderLines;
    }

    @Override
    public String toString() {
        return "Order [id=" + id + ", orderedDate=" + orderedDate + ", shippenDate=" + shippedDate + ", total=" + total
                + ", orderLines=" + orderLines + "]";
    }
}

OrderLine类

package com.li.association.one2many.pojo;

public class OrderLine {
    private Long id;
    private Double price;
    private Long quantity;
    private String product;

    private Order order;

    public OrderLine() {}

    public OrderLine(Long id, Double price, Long quantity, String product, Order order) {
        super();
        this.id = id;
        this.price = price;
        this.quantity = quantity;
        this.product = product;
        this.order = order;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public Double getPrice() {
        return price;
    }

    public void setPrice(Double price) {
        this.price = price;
    }

    public Long getQuantity() {
        return quantity;
    }

    public void setQuantity(Long quantity) {
        this.quantity = quantity;
    }

    public String getProduct() {
        return product;
    }

    public void setProduct(String product) {
        this.product = product;
    }

    public Order getOrder() {
        return order;
    }

    public void setOrder(Order order) {
        this.order = order;
    }

    @Override
    public String toString() {
        return "OrderLine [id=" + id + ", price=" + price + ", quantity=" + quantity + ", product=" + product + "]";
    }

}
一对多双向关联关系的映射文件

order表(父表)

因为我们使用的是set集合来存储订单项(OrderLine),所以,我们要使用set标签来配置对应关系,如果我们使用List集合或者Map映射集来存储订单项,那么我们要用list标签或者map标签来配置,

  • name=”orderlines”:指示Order类中的属性(property),该属性用以设置或获取子表内容。

  • column=”ORDER_ID”:指示我们子表中的外键列。

<class name="Order" table="T_ORDER">
    ......
    <set name="orderlines" cascade="all">
        <key column="ORDER_ID"/>
        <one-to-many class="OrderLine"/>
    </set>
</class>

OrderLine表(子表)

  • name=”order”:指示OrderLine类中该有的属性。

  • culumn=”ORDER_ID”:对应外键。

<class name="OrderLine" table="T_ORDERLINE">
    ......
    <many-to-one name="order" culumn="ORDER_ID"/>
</class>

测试

测试前我们应该要把映射文件配置进入核心配置文件中(hibernate.cfg.xml)

package com.li.test;

import java.util.Calendar;
import java.util.Date;

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

import com.li.association.one2many.pojo.Order;
import com.li.association.one2many.pojo.OrderLine;
import com.li.common.HibernateSessionFactory;

/*一对多双向关联关系*/

public class Association3 {

    public static void main(String[] args) {
        OrderLine ol1=new OrderLine();
        ol1.setId(456L);
        ol1.setPrice(123.5);
        ol1.setProduct("book");
        ol1.setQuantity(3L);

        OrderLine ol2=new OrderLine();
        ol2.setId(789L);
        ol2.setPrice(123.5);
        ol2.setProduct("milk");
        ol2.setQuantity(3L);

        Order order=new Order();
        order.setId(123L);
        order.setOrderedDate(new Date(System.currentTimeMillis()));
        Calendar cl=Calendar.getInstance();
        cl.set(Calendar.DAY_OF_MONTH, cl.get(Calendar.DAY_OF_MONTH)+3);
        order.setShippedDate(new Date(cl.getTimeInMillis()));

        /*建立双向关联关系*/
        order.getOrderLines().add(ol1);
        order.getOrderLines().add(ol2);
        ol1.setOrder(order);
        ol2.setOrder(order);

        order.setTotal(ol1.getPrice()*ol1.getQuantity()+ol2.getPrice()*ol2.getQuantity());

        Session session = HibernateSessionFactory.getSession();

        Transaction trans=null;

         try {
            trans = session.beginTransaction();
            /*保存订单的同时会级联保存订单项*/
            session.save(order);

            /*级联查询*/
            Order o=session.get(Order.class, 123L);
            System.out.println(o);

            /*级联更新*/
            double total=0.0;
            for(OrderLine ol : o.getOrderLines()) {
                ol.setPrice(100.0);
                ol.setQuantity(10L);    
                total+=ol.getPrice()*ol.getQuantity();
            }
            o.setTotal(total);
            session.update(o);

            /*级联删除*/
            session.delete(o);

            trans.commit();
        } catch (Exception e) {
            e.printStackTrace();
            trans.rollback();
        }
    }

}

运行结果

Hibernate: select orderline_.ID, orderline_.PRICE as PRICE2_2_, orderline_.QUANTITY as QUANTITY3_2_, orderline_.PRODUCT as PRODUCT4_2_, orderline_.ORDER_ID as ORDER_ID5_2_ from T_ORDERLINE orderline_ where orderline_.ID=?
Hibernate: select orderline_.ID, orderline_.PRICE as PRICE2_2_, orderline_.QUANTITY as QUANTITY3_2_, orderline_.PRODUCT as PRODUCT4_2_, orderline_.ORDER_ID as ORDER_ID5_2_ from T_ORDERLINE orderline_ where orderline_.ID=?
Hibernate: insert into T_ORDER (ORDERED_DATE, SHIPPED_DATE, TOTAL, ID) values (?, ?, ?, ?)
Hibernate: insert into T_ORDERLINE (PRICE, QUANTITY, PRODUCT, ORDER_ID, ID) values (?, ?, ?, ?, ?)
Hibernate: insert into T_ORDERLINE (PRICE, QUANTITY, PRODUCT, ORDER_ID, ID) values (?, ?, ?, ?, ?)
Hibernate: update T_ORDERLINE set ORDER_ID=? where ID=?
Hibernate: update T_ORDERLINE set ORDER_ID=? where ID=?

我们通过输出结果可以看到,Hibernate最后还执行了两条 update 语句,这是为什么呢?我们稍后解释,如果我们给set标签添加 inverse 属并设置值为 false,就不会执行后面的更新操作。

即:

<class name="Order" table="T_ORDER">
    ......
    <set name="orderlines" cascade="all" inverse="true">
        <key column="ORDER_ID"/>
        <one-to-many class="OrderLine"/>
    </set>
</class>
<set>元素中的inverse元素

inverse是倒转的意思。

  1. 默认inverse=false,子表的外键由父表来维护,会出现多条update语句,用父表的主键来更新子表的外键,这样确保子表的外键不会出现null,实际上子表的外键我们已经插入成功了,这种操作可以说是“多此一举”的,只是确保结果的正确性而已。如果我们设置inverse=true或者不设置,那么也可以插入成功。

  2. 当inverse=true时,子表的外键由子表来维护,不会出现后面的update操作,那么外键可能会出现null的现象。

  3. 注意:在多对多的情况下,inverse一定要设置为true,在任何一方都可以。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值