go4it

just do it

持久化带关系的实体

customer与address单向一对一关系

1.增加级联

  在customer中

@OneToOne
@JoinColumn(name="address_id")
public Address getAddress(){
  return this.address;
}
 address中无特别的注解
 
  同时增加一个customer和address:
@PersistenceContext
protected EntityManager em;

public Customer addCustomer(Customer customer,Address address){
     em.persist(address);
     customer.setAddress(address);
     em.persist(customer);
   
     return customer;
    
}
---------------------------------------------------------------------------
但该customer与address的级联关系如下:
@OneToOne(cascade=CascadeType.PERSIST)
@JoinColumn(name="address_id")
public Address getAddress(){
  return this.address;
}
则session bean的增加方法改为如下:
@PersistenceContext
protected EntityManager em;

public Customer addCustomer(Customer customer,Address address){
  //   em.persist(address);
     customer.setAddress(address);
     em.persist(customer);
   
     return customer;
    
}

由于级联persist,就不用自己在persist address了。

-----------------------------------------------------------------------------------------------------------------------

2.及时加载和延迟加载

@PersistenceContext
protected EntityManager em;

public Customer findCustomerById(Integer customerId){
     Customer customer=em.find(Customer.class,customerId);
     return customer;
    
}
由于customer和address为一对一关系,默认为及时加载,
所以在find customer的时候,其实select语句是左连接address,同时取出关联address的。
 
如果改为延迟加载:
@OneToOne(cascade=CascadeType.PERSIST,fetch=FetchType.LAZY)
@JoinColumn(name="address_id")
public Address getAddress(){
  return this.address;
}
 
则在session bean中的find方法:
@PersistenceContext
protected EntityManager em;

public Customer findCustomerById(Integer customerId){
     Customer customer=em.find(Customer.class,customerId);
   //通过调用延迟加载关联的address
     customer.getAddress();
     return customer;
    
}

 

其实分两个select语句来实行,一个是先select customer,第二个是通过where address_id来select关联的address

如果客户端要使用customer的getAddress()方法,则必须在session bean中延迟加载customer.getAddress(),否则

客户端调用时会报错。延迟加载只能在持久化上下文(session bean)中执行。

 

实体关系默认的加载关系:凡是加载的是集合类,默认为LAZY方式,否则为EAGER方式。

 

-------------------------------------------------------------------------------------------------------------------------------------------

3.更新级联

  merge():先查找,将实体的数据重新从数据库中读取出来;然后比较,如果实体属性有变化才会更新。

@PersistenceContext
protected EntityManager em;

public Customer updateCustomer(Customer customer){
     //返回更新后的实体,保持托管的实体与数据库中的一致性。
      return em.merge(customer);

 }   
如果customer与address的级联关系为merge:
@OneToOne(cascade=CascadeType.MERGE)
@JoinColumn(name="address_id")
public Address getAddress(){
  return this.address;
}
如果客户端:
Customer customer=cdao.findCustomerById(new Integer(1));
//更新关联实体属性
customer.getAddress().setZip("100083");
//保持更新后的实体,此时它所关联的address实体也将保存
cdao.updateCustomer(customer);
 
此时实体管理器不仅检查customer实体是否被修改,也检查关联的address实体。
若address是managed托管状态,则更新address实体到数据库中。
若address为transient(下一篇介绍)瞬时状态,则自动持久化address实体,然后保存。
 
Customer customer=cdao.findCustomerById(new Integer(1));
//增加address实体
Address add=new Address();
add.setLine1("line 1");
add.setLine2("line 2");
add.setZip("100083");
//由于级联merge,不用手工persist address
customer.setAddress(add);

//保持更新后的实体,此时它所关联的address实体也将被自动持久化
cdao.updateCustomer(customer);
 
--------------------------------------------------------------------------------------------------------------------------
4.删除级联
 
在customer和address无级联删除时:
 session bean:
@PersistenceContext protected EntityManager em; public void deleteCustomer(Integer customerId){ Customer customer=em.find(Customer.class,customerId); em.remove(customer); }
这里仅仅删除customer表中的记录。
如果要同时删除关联的address,可以设置级联删除:
@OneToOne(cascade=CascadeType.REMOVE)
@JoinColumn(name="address_id")
public Address getAddress(){
  return this.address;
}
 
也可以不设置级联删除,手动删除:
@PersistenceContext
protected EntityManager em;
public void deleteCustomer(Integer customerId){
     Customer customer=em.find(Customer.class,customerId);
     em.remove(customer.getAddress());
     em.remove(customer);
 } 
但对应一对多的情况,得逐一删除关联实体,比较麻烦,设置级联删除会比较轻松。
 
 
 

posted on 2009-01-23 13:59  cxccbv  阅读(402)  评论(0)    收藏  举报

导航