Hibernate多对多

以下使用订单(order)和产品(product)的例子,订单-产品关联保存在表orderitem中

1.使用many-to-many单向关联

<class name="com.tazi.domin.Orders" table="orders" catalog="hib">
        <id name="id" type="java.lang.Integer">
            <column name="id" />
            <generator class="identity" />
        </id>
        <property name="address" type="java.lang.String">
            <column name="address" length="100" />
        </property>
        <property name="realname" type="java.lang.String">
            <column name="realname" length="20" />
        </property>
        <set name="products" table="orderitem" cascade="save-update">
            <key column="order_id" />
             <many-to-many class="com.tazi.domin.Product" column="product_id"/>
        </set> 
 </class>

 <class name="com.tazi.domin.Product" table="product" catalog="hib" >
        <id name="id" type="java.lang.Integer">
            <column name="ID" />
            <generator class="identity" />
        </id>
        <property name="name" type="java.lang.String">
            <column name="NAME" length="200" not-null="true" />
        </property>
        <property name="price" type="java.lang.Float">
            <column name="PRICE" precision="12" scale="0" />
        </property>
        <property name="description" type="java.lang.String">
            <column name="DESCRIPTION" length="2000" />
        </property>
    </class>

 (1).保存数据。

维护关系的一方(order)负责维护关系表orderitem,不负责维护另一方(product).比如session.save(order),就order本身而言,只会生成如下语句:

Hibernate: 
    insert 
    into
        hib.orders
        (address, realname) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        orderitem
        (order_id, product_id) 
    values
        (?, ?)

  所以如果order中的product没有事先和数据库中的记录建立关系的话,执行结果会报错。如果在维护关系的一方(order)的many-to-many中设置了cascade="save-update"等,则由于session.save(order)其实也会导致session.save(product),所以结果正确,如下(orders中有两个products)。

Hibernate: 
    insert 
    into
        hib.orders
        (address, realname) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        hib.product
        (NAME, PRICE, DESCRIPTION) 
    values
        (?, ?, ?)
Hibernate: 
    insert 
    into
        hib.product
        (NAME, PRICE, DESCRIPTION) 
    values
        (?, ?, ?)
Hibernate: 
    insert 
    into
        orderitem
        (order_id, product_id) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        orderitem
        (order_id, product_id) 
    values
        (?, ?)

 (2).加载数据执行Orders order=(Orders)session.get(Orders.class, 2); 

Hibernate: 
    select
        orders0_.id as id5_0_,
        orders0_.address as address5_0_,
        orders0_.realname as realname5_0_ 
    from
        hib.orders orders0_ 
    where
        orders0_.id=?

当程序中需要用到order的products成员或设置了lazy="false"后,

Hibernate: 
    select
        orders0_.id as id5_0_,
        orders0_.address as address5_0_,
        orders0_.realname as realname5_0_ 
    from
        hib.orders orders0_ 
    where
        orders0_.id=?
Hibernate: 
    select
        products0_.order_id as order1_1_,
        products0_.product_id as product2_1_,
        product1_.ID as ID4_0_,
        product1_.NAME as NAME4_0_,
        product1_.PRICE as PRICE4_0_,
        product1_.DESCRIPTION as DESCRIPT4_4_0_ 
    from
        orderitem products0_ 
    left outer join
        hib.product product1_ 
            on products0_.product_id=product1_.ID 
    where
        products0_.order_id=?

 使用左连接,从关联表(orderitem)再连到另一方的表(product) .

(3).使用双向关联。即在product的映射配置中增加

 <set name="orders" table="orderitem" cascade="save-update" >
            <key column="product_id" />
             <many-to-many class="com.tazi.domin.Orders" column="order_id"/>
</set> 

 则如下保存的代码运行会报错:

                Product product=new Product();
		product.setName("台灯");
		product.setPrice(262.3f);
		
		Orders order=new Orders();
		order.setRealname("tazi");
		order.setAddress("苏州");
		order.getProducts().add(product);
		order.getProducts().add(product2);
		product.getOrders().add(order);
		
		session.save(order);
//执行的sql语句如下
Hibernate: 
    insert 
    into
        hib.orders
        (address, realname) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        hib.product
        (NAME, PRICE, DESCRIPTION) 
    values
        (?, ?, ?)
Hibernate: 
    insert 
    into
        orderitem
        (order_id, product_id) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        orderitem
        (product_id, order_id) 
    values
        (?, ?)

可见,同一个order和product的对应关系试图在关联表(orderitem)中保存两次。这是因为多对多的双方地位是相同的,而每一方都会去维护关系。解决办法是在其中一方的many-to-many中加上inverse="true",取消维护关系(即修改或插入orderitem)的行为,此时另一方必须担负起维护关系的责任。运行结果如下:

Hibernate: 
    insert 
    into
        hib.orders
        (address, realname) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        hib.product
        (NAME, PRICE, DESCRIPTION) 
    values
        (?, ?, ?)
Hibernate: 
    insert 
    into
        orderitem
        (order_id, product_id) 
    values
        (?, ?)

(4).双向关联时,如果双方lazy都为false,则执行加载语句

Product product=(Product)session.get(Product.class, 8);执行的结果是很多select语句,而且语句的个数是无法事先估算的,除非知道数据库表中的数据。因为加载原始product,加载原始product对应的orders,然后每个order都要分别加载对应的product,而新加载出来的对象都要考虑关联对象,直到所有关联对象都已经在session中。

2.分解多对多为两个一对多关联。使用many-to-many的缺点就是无法保存多余的数据(如orderitem中的数量,购买价等)。(推荐)

MyEclipse自动生成的对应于关联表(orderitem)的类和映射文件如下:

类OrderitemId 成员Orders orders;(其实是一个产品,因为order是数据库关键字,表名取为orders,自动生成的类和对象也带了s)Product product;

类Orderitem 成员OrderitemId id;(id为复合主键,组件形式)Integer quantity;(多余的属性)

类Orders 中Set orderItems= new HashSet(0);

    <class name="com.tazi.domin.Orderitem" table="orderitem" catalog="hib">
        <composite-id name="id" class="com.tazi.domin.OrderitemId">
            <key-many-to-one name="orders" class="com.tazi.domin.Orders">
                <column name="order_id" />
            </key-many-to-one>
            <key-many-to-one name="product" class="com.tazi.domin.Product">
                <column name="product_id" />
            </key-many-to-one>
        </composite-id>
        <property name="quantity" type="java.lang.Integer">
            <column name="quantity" />
        </property>
    </class>

Product中不保存关联关系。Order中保存one-to-many关系与orderitem关联。在orderitem中保存与Product和Order的关系,这就足够了。另外,为了把维护关系的责任全权托付给orderitem,在Order的one-to-many上加上inverse.如下

 <set name="orderItems" cascade="save-update" inverse="true">
            <key column="order_id" />
            <one-to-many class="com.tazi.domin.OrderItem" />
</set> 

保存如下:

                Product product=new Product();
		product.setName("台灯");
		product.setPrice(262.3f);
		
		Orders order=new Orders();
		order.setRealname("tazi");
		order.setAddress("苏州");

                OrderitemId id=new OrderitemId(order, product);
		Orderitem orderitem=new Orderitem(id,12);
		session.save(order);
		session.save(product);
		session.save(orderitem);

如果orderitem中的数据是从数据库中事先加载的,则在试图保存orderitem时会先检查数据库中是否已经存在这条(order-product)对应的记录。

                Product product=(Product)session.get(Product.class, 11);
		Orders order=(Orders)session.get(Orders.class, 15);
		
		OrderitemId id=new OrderitemId(order, product);
		Orderitem orderitem=new Orderitem(id,12);
		
		order.getOrderItems().add(orderitem);

即使没有save语句,但当session关闭或事务提交时,会自动检查是否有需要更新到数据库的。执行sql语句如下:

Hibernate: 
    select
        product0_.ID as ID4_0_,
        product0_.NAME as NAME4_0_,
        product0_.PRICE as PRICE4_0_,
        product0_.DESCRIPTION as DESCRIPT4_4_0_ 
    from
        hib.product product0_ 
    where
        product0_.ID=?
Hibernate: 
    select
        orders0_.id as id5_0_,
        orders0_.address as address5_0_,
        orders0_.realname as realname5_0_ 
    from
        hib.orders orders0_ 
    where
        orders0_.id=?
Hibernate: 
    select
        orderitems0_.order_id as order1_1_,
        orderitems0_.product_id as product2_1_,
        orderitems0_.order_id as order1_6_0_,
        orderitems0_.product_id as product2_6_0_,
        orderitems0_.quantity as quantity6_0_ 
    from
        hib.orderitem orderitems0_ 
    where
        orderitems0_.order_id=?
Hibernate: 
    select
        orderitem_.order_id,
        orderitem_.product_id,
        orderitem_.quantity as quantity6_ 
    from
        hib.orderitem orderitem_ 
    where
        orderitem_.order_id=? 
        and orderitem_.product_id=?

如果不存在对应关系,则插入到关联表中

Hibernate: 
    insert 
    into
        hib.orderitem
        (quantity, order_id, product_id) 
    values
        (?, ?, ?)

否则报错。

 

 

 

 

 

 

posted @ 2011-12-13 21:13  tazi  阅读(387)  评论(0编辑  收藏  举报