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
(?, ?, ?)
否则报错。
浙公网安备 33010602011771号