EntityManagerFactory

4 EntityManagerFactory 
4.1 Overview 
    EntityManagerFactory可以被注入到应用中,也可以通过以下方式创建: 
    EntityManagerFactory emf = Persistence.createEntityManagerFactory("openjpa"); 
    Persistence.createEntityManagerFactory方法通过在类路径上查找META-INF目录中的persistence.xml文件来获得EntityManagerFactory的配置,persistence.xml文件中可以定义多个persistence-unit。其name属性值可以作为Persistence.createEntityManagerFactory方法的参数,transaction-type用来指定是使用JTA,还是使用局部事务。以下是个persistence.xml文件的例子: 

Xml代码 
<?xml version="1.0"?>  
<persistence>  
  <persistence-unit name="openjpa" transaction-type="RESOURCE_LOCAL" >  
    <provider>org.apache.openjpa.persistence.PersistenceProviderImpl</provider>  
    <class>tutorial.Animal</class>  
    <class>tutorial.Dog</class>  
    <class>tutorial.Rabbit</class>  
    <class>tutorial.Snake</class>  
    <properties>  
      <property name="openjpa.ConnectionURL" value="jdbc:hsqldb:tutorial_database"/>  
      <property name="openjpa.ConnectionDriverName" value="org.hsqldb.jdbcDriver"/>  
      <property name="openjpa.ConnectionUserName" value="sa"/>  
      <property name="openjpa.ConnectionPassword" value=""/>  
      <property name="openjpa.Log" value="DefaultLevel=WARN, Tool=INFO"/>  
    </properties>  
  </persistence-unit>  
</persistence>  

<?xml version="1.0"?> 
<persistence> 
  <persistence-unit name="openjpa" transaction-type="RESOURCE_LOCAL" > 
    <provider>org.apache.openjpa.persistence.PersistenceProviderImpl</provider> 
    <class>tutorial.Animal</class> 
    <class>tutorial.Dog</class> 
    <class>tutorial.Rabbit</class> 
    <class>tutorial.Snake</class> 
    <properties> 
      <property name="openjpa.ConnectionURL" value="jdbc:hsqldb:tutorial_database"/> 
      <property name="openjpa.ConnectionDriverName" value="org.hsqldb.jdbcDriver"/> 
      <property name="openjpa.ConnectionUserName" value="sa"/> 
      <property name="openjpa.ConnectionPassword" value=""/> 
      <property name="openjpa.Log" value="DefaultLevel=WARN, Tool=INFO"/> 
    </properties> 
  </persistence-unit> 
</persistence>    EntityManagerFactory 实例是重量级对象。每个EntityManagerFactory 实例可能要维护metadata cache、object state cache、EntityManager pool、connection pool等等资源。如果应用程序不再使用EntityManagerFactory,那么应该及时关闭它以便释放资源。如果在一个或多个EntityManager处于活跃状态时试图关闭EntityManagerFactory,那么会导致一个IllegalStateException。 



4.2 Persistence Context 
Persistence context包含一组entities,这些entities都有唯一的persistent identity。在persistence context中,EntityManager管理entities的生命周期,entities可以访问datastore来获取persistent state。当persistence context结束的时候,被EntityManager管理的所有entities都变成detached状态。Detached entities不再被EntityManager管理,也不能访问datastore。有两种类型的persistent context:transaction persistence context和extended persistence context。 

4.2.1 Transaction Persistence Context 
    在transaction persistence context模型中,EntityManager为每一个事务开始一个新的persistence context。当事务被提交或者回滚后,persistence context也就自动结束,被EntityManager管理的所有entity都变成detached状态。此时如果访问entity上尚未被加载的字段(例如lazy fetch字段)会导致没有定义的结果。 
    如果不在事务中通过EntityManager访问datastore,那么EntityManager会对每一次方法调用都创建一个新的persistence context。当方法调用结束时,persistence context也自动结束。例如当在事务之外调用EntityManager.find方法,EntityManager会创建一个临时的persistence context,并在这个临时的persistence context中访问datastore。当EntityManager.find方法结束时,临时的persistence context自动结束,并且EntityManager.find方法会返回一个detached entity。如果用相同的identity object再次调用EntityManager.find方法,那么会得到一个新的detached entity。以下是个描述transaction persistence context模型的行为的例子: 

Java代码 
EntityManager em; // injected   
...   
  
// outside a transaction:   
  
// each operation occurs in a separate persistence context, and returns    
// a new detached instance   
Magazine mag1 = em.find(Magazine.class, magId);   
Magazine mag2 = em.find(Magazine.class, magId);   
assertTrue(mag2 != mag1);   
...   
  
// transaction begins:   
  
// within a transaction, a subsequent lookup doesn't return any of the   
// detached objects.  however, two lookups within the same transaction   
// return the same instance, because the persistence context spans the   
// transaction   
Magazine mag3 = em.find(Magazine.class, magId);   
assertTrue(mag3 != mag1 && mag3 != mag2);   
Magazine mag4 = em.find(Magazine.class (magId);   
assertTrue(mag4 == mag3);   
...   
  
// transaction commits:   
  
// once again, each operation returns a new instance   
Magazine mag5 = em.find(Magazine.class, magId);   
assertTrue(mag5 != mag3);  

EntityManager em; // injected 
... 

// outside a transaction: 

// each operation occurs in a separate persistence context, and returns 
// a new detached instance 
Magazine mag1 = em.find(Magazine.class, magId); 
Magazine mag2 = em.find(Magazine.class, magId); 
assertTrue(mag2 != mag1); 
... 

// transaction begins: 

// within a transaction, a subsequent lookup doesn't return any of the 
// detached objects.  however, two lookups within the same transaction 
// return the same instance, because the persistence context spans the 
// transaction 
Magazine mag3 = em.find(Magazine.class, magId); 
assertTrue(mag3 != mag1 && mag3 != mag2); 
Magazine mag4 = em.find(Magazine.class (magId); 
assertTrue(mag4 == mag3); 
... 

// transaction commits: 

// once again, each operation returns a new instance 
Magazine mag5 = em.find(Magazine.class, magId); 
assertTrue(mag5 != mag3); 

4.2.2 Extended Persistence Context 
    在extended persistence context模型中,不论是否在事务内,EntityManager在其整个生命周期内维护相同一个persistence context。所有通过EntityManager得到的entities都被EntityManager管理,只有在EntityManager被关闭,或者entity被序列化的时候,entity才变成detached状态。 
以下是个描述extended persistence context模型的行为的例子: 

Java代码 
EntityManagerFactory emf = ...   
EntityManager em = emf.createEntityManager();   
  
// persistence context active for entire life of EM, so only one entity   
// for a given persistent identity   
Magazine mag1 = em.find(Magazine.class, magId);   
Magazine mag2 = em.find(Magazine.class, magId);   
assertTrue(mag2 == mag1);   
  
em.getTransaction().begin();   
  
// same persistence context active within the transaction   
Magazine mag3 = em.find(Magazine.class, magId);   
assertTrue(mag3 == mag1);   
Magazine mag4 = em.find(Magazine.class (magId);   
assertTrue(mag4 == mag1);   
  
em.getTransaction.commit ();   
  
// when the transaction commits, instance still managed   
Magazine mag5 = em.find(Magazine.class, magId);   
assertTrue(mag5 == mag1);   
  
// instance finally becomes detached when EM closes   
em.close();  

EntityManagerFactory emf = ... 
EntityManager em = emf.createEntityManager(); 

// persistence context active for entire life of EM, so only one entity 
// for a given persistent identity 
Magazine mag1 = em.find(Magazine.class, magId); 
Magazine mag2 = em.find(Magazine.class, magId); 
assertTrue(mag2 == mag1); 

em.getTransaction().begin(); 

// same persistence context active within the transaction 
Magazine mag3 = em.find(Magazine.class, magId); 
assertTrue(mag3 == mag1); 
Magazine mag4 = em.find(Magazine.class (magId); 
assertTrue(mag4 == mag1); 

em.getTransaction.commit (); 

// when the transaction commits, instance still managed 
Magazine mag5 = em.find(Magazine.class, magId); 
assertTrue(mag5 == mag1); 

// instance finally becomes detached when EM closes 
em.close(); 

5 EntityManager 
    EntityManager接口的方法可以大致分为以下几类。 
5.1 Transaction Association 

Java代码 
public EntityTransaction getTransaction ();  

public EntityTransaction getTransaction ();    EntityManager实例和EntityTransaction实例之间是一对一的关系。 通过getTransaction方法可以得到与EntityManager关联的EntityTransaction实例。 


5.2 Entity Identity Management 
    EntityManager负责管理entities,以下的这些方法的行为会因persistence context(transaction persistence context或者extended persistence context)的不同而有差异。 

Java代码 
public <T> T find(Class<T> cls, Object oid);  

public <T> T find(Class<T> cls, Object oid);    find方法返回persistent identity指定的entity。 如果这个entity存在于当前的persistence context中,那么返回值是被缓存的对象;否则会创建一个新的entity,并从datastore中加载相关的persistent state。如果datastore不存在持有指定persistent identity的记录,那么这个方法返回null。 Java代码 
public <T> T getReference(Class<T> cls, Object oid);  

public <T> T getReference(Class<T> cls, Object oid);    getReference方法与find相似。不同的是:如果缓存中没有指定的entity,EntityManager会创建一个新的entity,不是立即访问datastore(不加载persistent state),而是在第一次访问某个持久字段的时候才加载相应的persistent state。此外,getReference 方法不返回null,如果在datastore中找不到相应的entity,这个方法会抛出EntityNotFoundException。 Java代码 
public boolean contains(Object entity);  

public boolean contains(Object entity);   如果当前的persistence context 包含指定的entity,那么返回true;否则返回false。 



5.3 Cache Management 

Java代码 
public void flush();  

public void flush();   Flush方法把当前事务中所有的修改写入到datastore中。如果EntityManager没有连接到datastore,那么EntityManager首先会获取一个连接并一直持有到事务结束。Flush方法抛出的任何异常都会导致事务回滚。如果调用flush方法时没有一个活跃的事务,那么flush方法会抛出TransactionRequiredException。 

Java代码 
public FlushModeType getFlushMode();   
public void setFlushMode(FlushModeType flushMode);  

public FlushModeType getFlushMode(); 
public void setFlushMode(FlushModeType flushMode);    EntityManager的FlushMode 属性用来指定是否在执行query之前进行flush。这可以确保当前事务中的任何修改会体现在query的结果中。此外也可以在query实例上设置FlushMode。它有以下两个可选值: 
COMMIT: 只是在事务提交的时候flush。当前事务中的修改可能不会体现在query的结果中。 
AUTO: 在需要的时候进行flush以确保当前事务中的任何修改都会体现在query的结果中。 
   OpenJPA 只在当前事务的任何修改可能会影响到将要执行的query的结果时才进行flush。 

Java代码 
public void clear();  

public void clear();    Clear方法会结束当前的persistence context,被EntityManager管理的所有entities变成detached状态。 


5.4 Query Factory 

Java代码 
public Query createQuery(String query);  

public Query createQuery(String query);    createQuery方法根据提供的Java Persistence Query Language (JPQL) string来创建一个query。Java代码 
public Query createNamedQuery(String name);  

public Query createNamedQuery(String name);    createNamedQuery方法用来得到通过metadata定义的命名query。 Java代码 
public Query createNativeQuery(String sql);   
public Query createNativeQuery(String sql, Class resultCls);   
public Query createNativeQuery(String sql, String resultMapping);  

public Query createNativeQuery(String sql); 
public Query createNativeQuery(String sql, Class resultCls); 
public Query createNativeQuery(String sql, String resultMapping);    以上方法用来创建datastore特有的native queries。例如在关系型数据库中使用的Structured Query Language (SQL)。 



5.5 Closing 

Java代码 
public boolean isOpen();   
public void close();  

public boolean isOpen(); 
public void close();   当不再使用EntityManager 的时候,需要及时关闭它以便释放资源。如果EntityManager 已经关闭,那么除了调用isOpen 方法外,调用EntityManager上的其它方法会导致IllegalStateException。不能在一个事务正在进行中的时候关闭EntityManager。 



5.6 Entity Lifecycle Management 
5.6.1 public void persist(Object entity); 
    persist方法用于将新创建的entity纳入EntityManager的管理,在下一次的flush或者commit时,这个entity会被插入到datastore中。这个方法只能在一个活跃的事务环境中调用。它的行为如下: 

如果是新entity,那么它会被EntityManager管理。 
如果这个entity已经被EntityManager管理,那么会被忽略。 
如果这个entity之前被remove,那么它会重新被管理。 
如果这个entity的状态是detached,那么会导致IllegalArgumentException。 
   以下是个简单的例子: 

Java代码 
import java.util.Iterator;   
import java.util.List;   
  
import javax.persistence.Basic;   
import javax.persistence.CascadeType;   
import javax.persistence.Entity;   
import javax.persistence.FetchType;   
import javax.persistence.Id;   
import javax.persistence.OneToMany;   
  
import org.apache.openjpa.persistence.FetchAttribute;   
import org.apache.openjpa.persistence.FetchGroup;   
import org.apache.openjpa.persistence.FetchGroups;   
  
@Entity  
@FetchGroups({   
    @FetchGroup(name="detail", attributes={   
        @FetchAttribute(name="grade"),   
        @FetchAttribute(name="magazines")   
    })   
})   
public class Publisher {   
    private int id;   
       
    private String name;   
       
    private String grade;   
       
    private List<Magazine> magazines;   
       
    public String toString() {   
        StringBuffer sb = new StringBuffer();   
        sb.append("id: " + getId());   
        sb.append(", name: " + getName());   
        sb.append(", grade: " + getGrade());   
           
        sb.append(", magazines[");   
        if(getMagazines() != null) {   
            for(Iterator<Magazine> iter = getMagazines().iterator(); iter.hasNext(); )  {   
                sb.append(iter.next().toString());   
                if(iter.hasNext()) {   
                    sb.append("; ");   
                }   
            }   
        }   
        sb.append("]");   
        return sb.toString();   
    }   
       
    @Id  
    public int getId() {   
        return id;   
    }   
  
    public void setId(int id) {   
        this.id = id;   
    }   
       
    @Basic  
    public String getName() {   
        return name;   
    }   
  
    public void setName(String name) {   
        this.name = name;   
    }   
       
    @Basic(fetch=FetchType.LAZY)   
    public String getGrade() {   
        return grade;   
    }   
  
    public void setGrade(String grade) {   
        this.grade = grade;   
    }   
       
    @OneToMany(mappedBy="publisher", cascade=CascadeType.ALL, fetch=FetchType.LAZY)   
    public List<Magazine> getMagazines() {   
        return magazines;   
    }   
    public void setMagazines(List<Magazine> magazines) {   
        this.magazines = magazines;   
    }   
}  

import java.util.Iterator; 
import java.util.List; 

import javax.persistence.Basic; 
import javax.persistence.CascadeType; 
import javax.persistence.Entity; 
import javax.persistence.FetchType; 
import javax.persistence.Id; 
import javax.persistence.OneToMany; 

import org.apache.openjpa.persistence.FetchAttribute; 
import org.apache.openjpa.persistence.FetchGroup; 
import org.apache.openjpa.persistence.FetchGroups; 

@Entity 
@FetchGroups({ 
    @FetchGroup(name="detail", attributes={ 
        @FetchAttribute(name="grade"), 
        @FetchAttribute(name="magazines") 
    }) 
}) 
public class Publisher { 
private int id; 

private String name; 

private String grade; 

private List<Magazine> magazines; 

public String toString() { 
StringBuffer sb = new StringBuffer(); 
sb.append("id: " + getId()); 
sb.append(", name: " + getName()); 
sb.append(", grade: " + getGrade()); 

sb.append(", magazines["); 
if(getMagazines() != null) { 
for(Iterator<Magazine> iter = getMagazines().iterator(); iter.hasNext(); )  { 
sb.append(iter.next().toString()); 
if(iter.hasNext()) { 
sb.append("; "); 



sb.append("]"); 
return sb.toString(); 


@Id 
public int getId() { 
return id; 


public void setId(int id) { 
this.id = id; 


@Basic 
public String getName() { 
return name; 


public void setName(String name) { 
this.name = name; 


@Basic(fetch=FetchType.LAZY) 
public String getGrade() { 
return grade; 


public void setGrade(String grade) { 
this.grade = grade; 


@OneToMany(mappedBy="publisher", cascade=CascadeType.ALL, fetch=FetchType.LAZY) 
public List<Magazine> getMagazines() { 
return magazines; 

public void setMagazines(List<Magazine> magazines) { 
this.magazines = magazines; 

}Java代码 
import javax.persistence.CascadeType;   
import javax.persistence.Entity;   
import javax.persistence.Id;   
import javax.persistence.IdClass;   
import javax.persistence.JoinColumn;   
import javax.persistence.ManyToOne;   
  
@Entity  
@IdClass(Magazine.MagazineId.class)   
public class Magazine {   
    @Id  
    private String isbn;   
       
    @Id  
    private String title;   
       
    @ManyToOne(cascade=CascadeType.ALL)   
    @JoinColumn(name = "publisherId", referencedColumnName = "id")     
    private Publisher publisher;   
       
    public String toString() {   
        StringBuffer sb = new StringBuffer();   
        sb.append("isbn: " + isbn);   
        sb.append(", title: " + title);   
        return sb.toString();   
    }   
       
    public String getIsbn() {   
        return isbn;   
    }   
  
    public void setIsbn(String isbn) {   
        this.isbn = isbn;   
    }   
  
    public String getTitle() {   
        return title;   
    }   
  
    public void setTitle(String title) {   
        this.title = title;   
    }   
       
    public Publisher getPublisher() {   
        return publisher;   
    }   
  
    public void setPublisher(Publisher publisher) {   
        this.publisher = publisher;   
    }   
       
    public static class MagazineId {   
        private String isbn;   
        private String title;   
           
        public MagazineId() {   
        }   
           
        public MagazineId(String isbn, String title) {   
            this.isbn = isbn;   
            this.title = title;   
        }   
           
        public boolean equals(Object obj) {   
            if(this == obj) {   
                return true;   
            }   
            if(!(obj instanceof MagazineId)) {   
                return false;   
            }   
               
            MagazineId rhs = (MagazineId)obj;   
            boolean b1 = (isbn == rhs.isbn || (isbn != null && isbn.equals(rhs.isbn)));   
            boolean b2 = (title == rhs.title || (title != null && title.equals(rhs.title)));   
            return b1 && b2;   
        }   
           
        public int hashCode(){   
            int h1 = (isbn == null ? 0 : isbn.hashCode());   
            int h2 = (title == null ? 0 : title.hashCode());   
            return h1 ^ h2;   
        }   
           
        public String toString() {   
            StringBuffer sb = new StringBuffer();   
            sb.append("isbn: " + isbn);   
            sb.append(", title: " + title);   
            return sb.toString();   
        }   
    }   
}  

import javax.persistence.CascadeType; 
import javax.persistence.Entity; 
import javax.persistence.Id; 
import javax.persistence.IdClass; 
import javax.persistence.JoinColumn; 
import javax.persistence.ManyToOne; 

@Entity 
@IdClass(Magazine.MagazineId.class) 
public class Magazine { 
@Id 
private String isbn; 

@Id 
private String title; 

@ManyToOne(cascade=CascadeType.ALL) 
@JoinColumn(name = "publisherId", referencedColumnName = "id")  
private Publisher publisher; 

public String toString() { 
StringBuffer sb = new StringBuffer(); 
sb.append("isbn: " + isbn); 
sb.append(", title: " + title); 
return sb.toString(); 


public String getIsbn() { 
return isbn; 


public void setIsbn(String isbn) { 
this.isbn = isbn; 


public String getTitle() { 
return title; 


public void setTitle(String title) { 
this.title = title; 


public Publisher getPublisher() { 
return publisher; 


public void setPublisher(Publisher publisher) { 
this.publisher = publisher; 


public static class MagazineId { 
private String isbn; 
private String title; 

public MagazineId() { 


public MagazineId(String isbn, String title) { 
this.isbn = isbn; 
this.title = title; 


public boolean equals(Object obj) { 
if(this == obj) { 
return true; 

if(!(obj instanceof MagazineId)) { 
return false; 


MagazineId rhs = (MagazineId)obj; 
boolean b1 = (isbn == rhs.isbn || (isbn != null && isbn.equals(rhs.isbn))); 
boolean b2 = (title == rhs.title || (title != null && title.equals(rhs.title))); 
return b1 && b2; 


public int hashCode(){ 
int h1 = (isbn == null ? 0 : isbn.hashCode()); 
int h2 = (title == null ? 0 : title.hashCode()); 
return h1 ^ h2; 


public String toString() { 
StringBuffer sb = new StringBuffer(); 
sb.append("isbn: " + isbn); 
sb.append(", title: " + title); 
return sb.toString(); 


}Java代码 
Publisher p1 = new Publisher();   
p1.setId(id);   
p1.setName("publisher1");   
p1.setGrade("excellent");   
p1.setMagazines(new ArrayList<Magazine>());   
Magazine m1 = new Magazine();   
m1.setIsbn("isbn1");   
m1.setTitle("title1");   
m1.setPublisher(p1);   
p1.getMagazines().add(m1);   
Magazine m2 = new Magazine();   
m2.setIsbn("isbn2");   
m2.setTitle("title2");   
m2.setPublisher(p1);   
p1.getMagazines().add(m2);   
EntityManagerem = entityManagerFactory.createEntityManager();   
em.getTransaction().begin();   
em.persist(p1);   
em.getTransaction().commit();  

Publisher p1 = new Publisher(); 
p1.setId(id); 
p1.setName("publisher1"); 
p1.setGrade("excellent"); 
p1.setMagazines(new ArrayList<Magazine>()); 
Magazine m1 = new Magazine(); 
m1.setIsbn("isbn1"); 
m1.setTitle("title1"); 
m1.setPublisher(p1); 
p1.getMagazines().add(m1); 
Magazine m2 = new Magazine(); 
m2.setIsbn("isbn2"); 
m2.setTitle("title2"); 
m2.setPublisher(p1); 
p1.getMagazines().add(m2); 
EntityManagerem = entityManagerFactory.createEntityManager(); 
em.getTransaction().begin(); 
em.persist(p1); 
em.getTransaction().commit(); 
  
5.6.2 public void remove(Object entity); 
    remove方法用于删除被管理的entity。在下一次的flush或者commit时,这个entity会从datastore中删除。这个方法只能在一个活跃的事务环境中调用。它的行为如下: 

如果是新entity,那么会被忽略。 
如果是已经被管理的entity,那么它会被删除。 
如果这个entity之前被remove,那么会被忽略。 
如果这个entity的状态是detached,那么会导致IllegalArgumentException。 
5.6.3 public void refresh(Object entity); 
    refresh方法用于确保entity的persistent state和datastore中的persistent state同步。它的行为如下: 

如果是新entity,那么会被忽略。 
如果是已经被管理的entity,那么刷新它的persistent state。 
如果这个entity之前被remove,那么会被忽略。 
如果这个entity的状态是detached,那么会导致IllegalArgumentException。 
5.6.4 public Object merge(Object entity); 
    有些情况下,你需要编辑一个处于detached状态的entity,然后重新将这个entity纳入到EntityManager的管理中,并将对其persistent state的修改更新到datastore中。Merge方法返回该entity受管理的一份拷贝。这个方法只能在一个活跃的事务环境中调用。它的行为如下: 

如果是新entity,那么会创建该entity的一份拷贝,并将这份拷贝纳入EntityManager的管理。 
如果是已经被管理的entity,那么会被忽略。 
如果这个entity之前被remove,那么会导致IllegalArgumentException。 
如果这个entity的状态是detached,如果EntityManager中已经管理了具有相同的identity的entity B,那么会将原始entity的persistent state拷贝到entity B中;否则会创建该entity的一份拷贝,并将这份拷贝纳入EntityManager的管理。 
   以下是个简单的例子: 

Java代码 
p1.setName("publisher2");   
EntityManager em = entityManagerFactory.createEntityManager();   
em.getTransaction().begin();   
em.merge(obj);   
em.getTransaction().commit();  

p1.setName("publisher2"); 
EntityManager em = entityManagerFactory.createEntityManager(); 
em.getTransaction().begin(); 
em.merge(obj); 
em.getTransaction().commit(); 


5.6.5 public void lock (Object entity, LockModeType mode); 
    lock方法通过指定的LockModeType 来对entity加锁。LockModeType 有以下两个可选值: 

READ: 在其它事务中可以读取,但是不能更新。 
WRITE: 在其它事务中不可以读取或更新。在当前事务提交后,无论被WRITE lock锁定的entities是否改变,其version将会自动增加。 
5.6.6 Detach and Attach 
    除了JPA定义的detach和attach API之外,OpenJPA还支持更多的特性。例如OpenJPAEntityManager提供以下方法: 

Java代码 
public Object detach(Object pc);   
public Object[] detachAll(Object... pcs);   
public Collection detachAll(Collection pcs);  

public Object detach(Object pc); 
public Object[] detachAll(Object... pcs); 
public Collection detachAll(Collection pcs);    以上的detach方法返回给定entity的detached状态的拷贝。在detach在当前事务中被修改过的entity之前,flush方法会被调用,以便将这些修改保存到datastore中。由于detached entity不能访问datastore,因此有时候需要在detach之前加载一些persistent state(例如某些lazy fetch字段)。尽管可以通过手工编码完成,OpenJPA也提供了一些特性来自动完成类似的工作。例如DetachState,它有以下可选值: 
loaded: 保持已经加载的字段,对于没有加载的字段则保持不变。这是缺省值。 
fetch-groups: 根据fetch group来决定需要加载的字段。 
all: 加载所有的字段。 
   继续5.6.1中的例子: 

Java代码 
EntityManager em = entityManagerFactory.createEntityManager();   
Publisher p2 = (Publisher)em.find(Publisher.class, id);   
em.close();   
System.out.println(p2.toString());  

EntityManager em = entityManagerFactory.createEntityManager(); 
Publisher p2 = (Publisher)em.find(Publisher.class, id); 
em.close(); 
System.out.println(p2.toString());    以上例子中p2在em.close()之后变成detached状态。由于采用了缺省的DetachState,因此没有加载lazy fetch字段grade和magazines。输出如下: 
id: 1, name: publisher1, grade: null, magazines[] 



Java代码 
em = entityManagerFactory.createEntityManager();   
Publisher p4 = (Publisher)em.find(Publisher.class, id);   
p4.getGrade();   
p4.getMagazines();   
em.close();   
System.out.println(p4.toString());  

em = entityManagerFactory.createEntityManager(); 
Publisher p4 = (Publisher)em.find(Publisher.class, id); 
p4.getGrade(); 
p4.getMagazines(); 
em.close(); 
System.out.println(p4.toString());    以上例子中p4在em.close()之后变成detached状态。虽然采用了缺省的DetachState,但是由于程序中显式访问了lazy fetch字段,所以grade和magazines被加载,并且在detach之后仍然可以访问。输出如下: 
id: 1, name: publisher1, grade: excellent, magazines[isbn: isbn1, title: title1; isbn: isbn2, title: title2] 



Java代码 
em = entityManagerFactory.createEntityManager();   
((OpenJPAEntityManager)em).setDetachState(DetachStateType.ALL);   
Publisher p5 = (Publisher)em.find(Publisher.class, id);   
em.close();   
System.out.println(p5.toString());  

em = entityManagerFactory.createEntityManager(); 
((OpenJPAEntityManager)em).setDetachState(DetachStateType.ALL); 
Publisher p5 = (Publisher)em.find(Publisher.class, id); 
em.close(); 
System.out.println(p5.toString());    以上例子中p5在em.close()之后变成detached状态。由于采用了 DetachStateType.ALL,因此所有的lazy fetch字段在detach之前都自动被加载,并且在detach之后仍然可以访问。输出如下: 
id: 1, name: publisher1, grade: excellent, magazines[isbn: isbn1, title: title1; isbn: isbn2, title: title2] 



Java代码 
em = entityManagerFactory.createEntityManager();   
((OpenJPAEntityManager)em).setDetachState(DetachStateType.FETCH_GROUPS);   
((OpenJPAEntityManager)em).getFetchPlan().addFetchGroup("detail");   
Publisher p6 = (Publisher)em.find(Publisher.class, id);   
em.close();   
System.out.println(p6.toString());  

em = entityManagerFactory.createEntityManager(); 
((OpenJPAEntityManager)em).setDetachState(DetachStateType.FETCH_GROUPS); 
((OpenJPAEntityManager)em).getFetchPlan().addFetchGroup("detail"); 
Publisher p6 = (Publisher)em.find(Publisher.class, id); 
em.close(); 
System.out.println(p6.toString());    以上例子中p6在em.close()之后变成detached状态。由于采用了 DetachStateType. FETCH_GROUPS,而Publisher中名为"detail"的fetch group定义了要额外加载grade和magazines,因此grade和magazines被加载,并且在detach之后仍然可以访问。输出如下: 
id: 1, name: publisher1, grade: excellent, magazines[isbn: isbn1, title: title1; isbn: isbn2, title: title2]
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值