Hibernate:如何映射聚合?
目录
背景返回目录
DDD 是在 Hibernate 之后发现的概念,Hibernate 如何映射 DDD 中的聚合呢?本文给出一种思路。
参考资料:DDD:使用EntityFramework的话,如果只为聚合根设计仓储,其它实体如何处理?。
映射聚合返回目录
聚合模型返回目录
Order
1 package model; 2 3 import java.util.*; 4 5 public class Order { 6 private Integer orderId; 7 private String customer; 8 private Set<OrderItem> orderItems = new HashSet<OrderItem>(); 9 10 public Integer getOrderId() { 11 return orderId; 12 } 13 14 public void setOrderId(Integer orderId) { 15 this.orderId = orderId; 16 } 17 18 public String getCustomer() { 19 return customer; 20 } 21 22 public void setCustomer(String customer) { 23 this.customer = customer; 24 } 25 26 public Set<OrderItem> getOrderItems() { 27 return orderItems; 28 } 29 30 public void setOrderItems(Set<OrderItem> orderItems) { 31 this.orderItems = orderItems; 32 } 33 34 }
OrderItem
1 package model; 2 3 import java.io.Serializable; 4 5 public class OrderItem implements Serializable { 6 private static final long serialVersionUID = 8584993780461202406L; 7 private Integer orderId; 8 private Integer productId; 9 private String product; 10 11 public Integer getProductId() { 12 return productId; 13 } 14 15 public void setProductId(Integer productId) { 16 this.productId = productId; 17 } 18 19 public String getProduct() { 20 return product; 21 } 22 23 public void setProduct(String product) { 24 this.product = product; 25 } 26 27 public Integer getOrderId() { 28 return orderId; 29 } 30 31 public void setOrderId(Integer orderId) { 32 this.orderId = orderId; 33 } 34 }
映射配置返回目录
Order
1 <?xml version="1.0"?> 2 <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 3 "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> 4 <!-- Generated 2013-10-7 21:33:57 by Hibernate Tools 3.4.0.CR1 --> 5 <hibernate-mapping> 6 <class name="model.Order" table="Orders"> 7 <id name="orderId" type="java.lang.Integer"> 8 <column name="OrderId"/> 9 <generator class="identity"/> 10 </id> 11 <property generated="never" lazy="false" name="customer" type="java.lang.String"> 12 <column name="Customer"/> 13 </property> 14 <set cascade="all,delete-orphan" inverse="true" lazy="true" 15 name="orderItems" sort="unsorted" table="OrderITems"> 16 <key> 17 <column name="OrderId"/> 18 </key> 19 <one-to-many class="model.OrderItem"/> 20 </set> 21 </class> 22 </hibernate-mapping>
OrderItem
1 <?xml version="1.0"?> 2 <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 3 "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> 4 <!-- Generated 2013-10-7 21:33:57 by Hibernate Tools 3.4.0.CR1 --> 5 <hibernate-mapping> 6 <class name="model.OrderItem" table="OrderItems"> 7 <composite-id> 8 <key-property name="orderId"> 9 <column name="OrderId"/> 10 </key-property> 11 <key-property name="productId"> 12 <column name="ProductId"/> 13 </key-property> 14 <generator class="assigned"/> 15 </composite-id> 16 <property generated="never" lazy="false" name="product" type="java.lang.String"> 17 <column name="Product"/> 18 </property> 19 </class> 20 </hibernate-mapping>
重点注意:Order 的 set 指定了 cascade="all 和 delete-orphan" inverse="true",OrderItem 使用了双主键(不是必须的)。
测试返回目录
代码
1 package demo; 2 3 import model.*; 4 5 import org.hibernate.*; 6 7 /* 8 * 测试 聚合设计。 9 */ 10 public class AggregateDemo implements Demo { 11 12 @Override 13 public void run() { 14 SessionHelper.execute(new SessionAction() { 15 16 @Override 17 public void action(Session session) { 18 Order order = new Order(); 19 order.setCustomer("段光伟"); 20 session.save(order); 21 22 OrderItem item = new OrderItem(); 23 item.setOrderId(order.getOrderId()); 24 item.setProductId(1); 25 item.setProduct("苹果"); 26 order.getOrderItems().add(item); 27 } 28 29 }); 30 31 SessionHelper.execute(new SessionAction() { 32 33 @Override 34 public void action(Session session) { 35 Order order = (Order) session.get(Order.class, new Integer(1)); 36 order.getOrderItems() 37 .remove(order.getOrderItems().toArray()[0]); 38 } 39 40 }); 41 } 42 }
输出SQL
1 begin transaction 2 action 3 Hibernate: 4 /* insert model.Order 5 */ insert 6 into 7 Orders 8 (Customer) 9 values 10 (?) 11 flush and commit 12 Hibernate: 13 /* get current state model.OrderItem */ select 14 orderitem_.OrderId, 15 orderitem_.ProductId, 16 orderitem_.Product as Product3_16_ 17 from 18 OrderItems orderitem_ 19 where 20 orderitem_.OrderId=? 21 and orderitem_.ProductId=? 22 Hibernate: 23 /* insert model.OrderItem 24 */ insert 25 into 26 OrderItems 27 (Product, OrderId, ProductId) 28 values 29 (?, ?, ?) 30 begin transaction 31 action 32 Hibernate: 33 /* load model.Order */ select 34 order0_.OrderId as OrderId1_17_0_, 35 order0_.Customer as Customer2_17_0_ 36 from 37 Orders order0_ 38 where 39 order0_.OrderId=? 40 Hibernate: 41 /* load one-to-many model.Order.orderItems */ select 42 orderitems0_.OrderId as OrderId1_17_1_, 43 orderitems0_.OrderId as OrderId1_16_1_, 44 orderitems0_.ProductId as ProductI2_16_1_, 45 orderitems0_.OrderId as OrderId1_16_0_, 46 orderitems0_.ProductId as ProductI2_16_0_, 47 orderitems0_.Product as Product3_16_0_ 48 from 49 OrderItems orderitems0_ 50 where 51 orderitems0_.OrderId=? 52 flush and commit 53 Hibernate: 54 /* delete model.OrderItem */ delete 55 from 56 OrderItems 57 where 58 OrderId=? 59 and ProductId=?
备注返回目录
还有几个问题还没有深入想:
- 如何聚合的关联层次很大,聚合根之外的实体的主键的数量也需要相应的增加,开发是否方便呢?还无从验证。
- 是否有必要为聚合根之外的实体引入一个逻辑主键,这种模式只有 Hibernate 支持,EntityFramework 就不支持。
- 使用 bag + composite-element 是否也可以?效率会不会太低。
希望朋友们多给点建议。
分类: Hibernate