持久化带关系的实体
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);
} 但对应一对多的情况,得逐一删除关联实体,比较麻烦,设置级联删除会比较轻松。
浙公网安备 33010602011771号