Hibernate对象关系之级联
级联及组合关系:强聚合关系,代表整体和部分之间不能分开,整体和部分单独存在没有意义;
组合关系的两个对象都是在一个模块当中管理的;都是在整体那个对象的模块中管理;
(1)以销售订单(主对象)和订单的明细数据(子对象)为例分析:
- 对于销售订单对象来说:
1、存在一个列表;
2、添加:在添加页面需要添加销售订单对象上的属性,还需要添加这个销售订单的明细数据;
3、修改:仍然在销售订单的编辑页面中完成;
4、删除:在销售订单列表中删除销售订单; - 对于销售订单明细对象来说:
1、对于销售订单明细对象,不需要列表;
2、添加:
a、在销售订单对象的添加的时候,可以添加销售订单明细对象;
b、在销售订单对象的保存,可以添加销售订单明细对象;
3、修改:在销售订单对象的修改方法中完成的;
4、删除:在销售订单对象的修改方法中完成的;在删除销售订单的时候,也要去删除这个销售订单的明细;
(2)分析执行流程
- 只需要有销售订单对象的DAO接口就可以了,销售订单明细的CRUD都是在销售订单对象的DAO中完成的;
- save:
1、保存销售订单对象;
2、保存销售订单对象对应的销售订单明细对象; - update:
1、修改销售订单对象(游离);
2、保存新的销售订单明细对象(临时对象);
3、修改修改过的销售订单明细对象(游离);
4、删除去掉了的销售订单明细对象(删除和主对象没有关系的销售订单明细对象); - delete:
1、删除销售订单对象的明细;
2、删除主对象;
(3)参考代码如下:
SaleBill对象:
public class SaleBill {
private Long id;
private String sn;
private Date inputTime;
private Set<SaleBillItem> items = new HashSet<SaleBillItem>();
}
SaleBillItem对象
public class SaleBillItem {
private Long id;
private String product;
private SaleBill bill;
}
映射文件
<class name="SaleBill">
<id name="id">
<generator class="native"/>
</id>
<property name="sn"/>
<set name="items" inverse="true" cascade="all-delete-orphan">
<key column="BILL_ID" />
<one-to-many class="SaleBillItem"/>
</set>
</class>
<class name="SaleBillItem">
<id name="id">
<generator class="native"/>
</id>
<property name="product"/>
<many-to-one name="bill" column="BILL_ID" />
</class>
SaleBillDAO接口
public interface ISaleBillDAO {
void save(SaleBill saleBill);
void update(SaleBill saleBill);
void delete(Long id);
SaleBill get(Long id);
}
SaleBillDAOImpl实现类
public class SaleBillDAOImpl implements ISaleBillDAO {
@Override
public void save(SaleBill bill) {
Session session = HibernateUtil.getInstance().openSession();
session.beginTransaction();
session.save(bill);
session.getTransaction().commit();
session.close();
}
@Override
//这个update方法是用来更新SaleBillItem的
public void update(SaleBill saleBill) {
Session session = HibernateUtil.getInstance().openSession();
session.beginTransaction();
SaleBill old=(SaleBill)session.get(SaleBill.class, saleBill.getId());
List<SaleBillItem> deletes=new ArrayList<SaleBillItem>();
for(SaleBillItem item:old.getItems()){
boolean find=false;
for(SaleBillItem newItem:saleBill.getItems()){
if(newItem.getId()!=null && item.getId().equals(newItem.getId())){
find=true;
}
}
if(!find){
deletes.add(item);
}
}
old.getItems().removeAll(deletes);
for(SaleBillItem item:deletes){
item.setBill(null);
}
session.update(old);
session.getTransaction().commit();
session.close();
}
public void update2(SaleBill saleBill) {
Session session = HibernateUtil.getInstance().openSession();
session.beginTransaction();
session.update(saleBill);
session.getTransaction().commit();
session.close();
}
@Override
public void delete(Long id) {
Session session = HibernateUtil.getInstance().openSession();
session.beginTransaction();
SaleBill bill = (SaleBill) session.get(SaleBill.class, id);
session.delete(bill);
session.getTransaction().commit();
session.close();
}
@Override
public SaleBill get(Long id) {
Session session = HibernateUtil.getInstance().openSession();
session.beginTransaction();
SaleBill bill = (SaleBill) session.get(SaleBill.class, id);
Hibernate.initialize(bill.getItems());
session.getTransaction().commit();
session.close();
return bill;
}
}
测试类:
public class CascadeTest {
private ISaleBillDAO dao=new SaleBillDAOImpl();
@Before
public void testSave(){
SaleBill bill=new SaleBill();
bill.setSn("001");
bill.setInputTime(new Date());
SaleBillItem item1=new SaleBillItem("p1");
SaleBillItem item2=new SaleBillItem("p2");
SaleBillItem item3=new SaleBillItem("p3");
item1.setBill(bill);
item2.setBill(bill);
item3.setBill(bill);
bill.getItems().add(item1);
bill.getItems().add(item2);
bill.getItems().add(item3);
dao.save(bill);
}
@Test
public void testUpdate2(){
SaleBill bill=dao.get(1L);
SaleBillItem delete=bill.getItems().iterator().next();
bill.getItems().remove(delete);
dao.update(bill);
}
@Test
public void testUpdate(){
SaleBill bill=dao.get(1L);
SaleBillItem item=new SaleBillItem("pnew");
item.setBill(bill);
bill.getItems().add(item);
SaleBillItem item1=bill.getItems().iterator().next();
item1.setProduct("pupdate");
dao.update(bill);
}
@Test
public void testDelete(){
dao.delete(1L);
}
}
级联的使用在现在电商和供应链领域的使用还是比较常见的,大家可以结合上述代码进行测试和学习。上述代码对象的getter、setter和tostring方法,以及ISaleBillDAO的接口还需大家自己完善。
(4)级联策略
-
使用级联来完成SaleBillDAOImpl:(在组合关系中,一般把整体称为主对象,把部分称为子对象)
1、在one方的集合上面,可以添加cascade属性,这个属性的意思就叫做级联;
2、级联能根据配置的级联策略,对这个集合里面的对象自动做一些操作;
-
级联策略:
1、save-update:在保存或者修改主对象的时候,去级联的持久化临时的子对象,修改游离的子对象;
2、delete:在删除主对象的时候,去级联的删除所有的子对象;
3、all:save-update+delete
4、delete-orphan:删除和主对象打破关系的子对象;
5、all-delete-orphan:all+delete-orphan
6、一般来说,对于组合关系,我们就直接使用all-delete-orphan就可以了;