- 浏览: 147439 次
- 来自: ...
文章分类
最新评论
-
fisher:
真心感谢楼主! 解决了困扰我几天的大问题啊!
EntityManagerFactory -
悲剧了:
太棒了,我们项目正在用这个
struts2 convention-plugin -
nforce_com:
...
jpa继承关系详解 -
guanchuangsheng:
精辟~~
总算明白了·~
桥接模式和适配器模式的区别 -
lping2:
强,写得太全面了
EntityManagerFactory
10 Miscellaneous Features
10.1 Restoring State
JPA规范要求不应该使用rolled back objects,但是这些对象在OpenJPA中是有效的。可以通过配置openjpa.RestoreState 属性来控制是否将对象的状态回滚到事务前的状态。它有以下可选值:
none: 不回滚对象状态,但是对象变成hollow,在下次访问的时候会重新加载。
immutable: 回滚不可变的状态,可变的状态变成hollow,在下次访问的时候会重新加载。
all: 回滚所有状态。
10.2 Typing and Ordering
当为对象的属性加载persistent state的时候,OpenJPA会检查这个属性在声明时或者无参构造函数中被赋值的类型。如果这个类型比声明的类型更精确,那么OpenJPA会用这个类型。如果你在初始化某个属性的时候使用了comparator,那么OpenJPA也会在每次加载persistent state的时候使用这个comparator。例如:
Java代码
public class Company {
// OpenJPA 会在每次加载数据的时候使用SalaryComparator。
private Collection employeesBySal = new TreeSet(new SalaryComparator());
private Map departments;
public Company {
// OpenJPA会使用TreeMap来保存departments 相关的persistent state。
departments = new TreeMap();
}
}
public class Company {
// OpenJPA 会在每次加载数据的时候使用SalaryComparator。
private Collection employeesBySal = new TreeSet(new SalaryComparator());
private Map departments;
public Company {
// OpenJPA会使用TreeMap来保存departments 相关的persistent state。
departments = new TreeMap();
}
}
10.3 Proxies
10.3.1 Smart Proxies
在运行时,OpenJPA可以通过代理跟踪entity 实例的属性是否被修改过,以便更有效地更新数据库。当设计persistent class的时候,应该尽可能将collection field映射成java.util.Set、java.util.TreeSet或java.util.HashSet。Smart proxy对这些类型可以进行更好的优化。
10.3.2 Large Result Set Proxies
当遍历persistent collection 或者map属性的时候,ORM的缺省行为是把所有persistent state载入到内存中。然而,如果载入的数据量过大,那么可能会降低性能。OpenJPA为这些large result set属性使用特殊的代理。它并不在内存中缓存任何数据,相反它会访问数据库来获得相关的结果。例如large result set collection的contains方法会导致在数据库中执行类似于SELECT COUNT(*) WHERE的查询。类似地,在每次试图获得iterator的时候,OpenJPA会使用当前的large result set配置来执行特定的query。在调用iterator.next方法的时候,OpenJPA会按需载入结果对象。此时需要通过OpenJPAPersistence.close方法来释放资源,例如:
Java代码
import org.apache.openjpa.persistence.*;
@Entity
public class Company {
@ManyToMany
@LRS
private Collection<Employee> employees;
...
}
Collection employees = company.getEmployees(); // employees is a lrs collection
Iterator itr = employees.iterator();
while (itr.hasNext()) {
process((Employee) itr.next());
}
OpenJPAPersistence.close(itr);
import org.apache.openjpa.persistence.*;
@Entity
public class Company {
@ManyToMany
@LRS
private Collection<Employee> employees;
...
}
Collection employees = company.getEmployees(); // employees is a lrs collection
Iterator itr = employees.iterator();
while (itr.hasNext()) {
process((Employee) itr.next());
}
OpenJPAPersistence.close(itr);
Large result set 属性只能被声明成java.util.Collection 或者java.util.Map;它不能包含externalizer;Large result set proxy不能从一个entity 实例转移到另外一个entity 实例中,例如以下代码会导致提交时的一个错误:
Java代码
Collection employees = company.getEmployees() // employees is a lrs collection
company.setEmployees(null);
anotherCompany.setEmployees(employees);
Collection employees = company.getEmployees() // employees is a lrs collection
company.setEmployees(null);
anotherCompany.setEmployees(employees);
10.3.3 Custom Proxies
OpenJPA通过org.apache.openjpa.util.ProxyManager接口管理代理。其缺省的实现是org.apache.openjpa.util.ProxyManagerImpl。它有以下配置属性:
TrackChanges: 是否使用smart proxy,缺省是true。
AssertAllowedType: 在向collection或map中加入元素的时候,如果跟metadata 中声明的类型不符,是否抛出异常,缺省是false。
以下是个简单的例子:
Xml代码
<property name="openjpa.ProxyManager" value="TrackChanges=false"/>
<property name="openjpa.ProxyManager" value="TrackChanges=false"/> 缺省的proxy manager可以代理 Collection, List, Map, Queue, Date, or Calendar 等类上的标准方法,也可以代理定制类型,但是这些定制类型必须复合以下条件:
Custom container types必须有一个公共的无参构造函数,或者一个公共的以Comparator为参数类型的构造函数。
Custom date types必须有一个公共的无参构造函数,或者一个公共的以long为参数 类型(代表当前的时间)的构造函数。
Other custom types必须有一个公共的无参构造函数,或者公共的拷贝构造函数。如果没有公共的拷贝构造函数,那么在进行拷贝的时候,首先会创建一个对象B,然后通过以A上getter方法的返回值为参数,调用B的setter方法。 因此你要确保通过这种方式,B是A的完整拷贝。
如果某个custom classes无法满足以上条件,那么OpenJPA允许你定义你自己的proxy class和proxy manager。
10.4 Externalization
OpenJPA 支持通过custom field mappings 来完全控制entity class的field在datastore中怎样被保存、查询和加载。然而一个更轻量级的方法是使用externalization 。Externalization 支持通过指定某些方法来控制保存和加载的方式。需要注意的是,不能在@EmbeddedId字段上使用externalization。
OpenJPA使用org.apache.openjpa.persistence.Externalizer annotation指定将某个属性转换为external value的方法名。如果指定一个non-static方法,那么OpenJPA会假定目标对象是被Externalizer标记的属性对象;如果指定一个static方法, 那么被OpenJPA会把被Externalizer标记的属性对象作为一个方法的参数。每个方法也可以接受一个StoreContext 型的参数。方法的返回值指定了缺省的external 类型。假设希望将某个CustomType类型的属性转换成String类型,那么可以采用以下的方法:
Method Extension
public String CustomType.toString() @Externalizer("toString")
public String CustomType.toString(StoreContext ctx) @Externalizer("toString")
public static String AnyClass.toString(CustomType ct) @Externalizer("AnyClass.toString")
public static String AnyClass.toString(CustomType ct, StoreContext ctx) @Externalizer("AnyClass.toString")
OpenJPA使用org.apache.openjpa.persistence.Factory annotation指定根据external value初始化某个属性的方法名。 如果指定static方法,那么这个方法必须返回这个属性类型的一个实例。这个方法可以接受StoreContext 类型的一个参数。如果没有指定factory annotation,那么这个属性的class必须包含以external form为参数的构造函数,否则会抛出一个异常。假设希望将String类型转换成某个CustomType类型,那么可以采用以下的方法:
Method Extension
public CustomType(String str) none
public static CustomType CustomType.fromString(String str) @Factory("fromString")
public static CustomType CustomType.fromString(String str, StoreContext ctx) @Factory("fromString")
public static CustomType AnyClass.fromString(String str) @Factory("AnyClass.fromString")
public static CustomType AnyClass.fromString(String str, StoreContext ctx) @Factory("AnyClass.fromString")
OpenJPA使用org.apache.openjpa.persistence.ExternalValues annotation指定external value的转换。 其value pairs用于指定Java和datastore的类型。如果datastore的类型不同于Java类型,那么通过org.apache.openjpa.persistence.Type annotation 指定datastore类型。如果externalized属性不是标准的persistent type,那么必须用org.apache.openjpa.persistence.Persistent annotation显式地进行标记。如果externalized 属性是可变的,而且不是collection、map和date类型,那么OpenJPA无法进行脏检查。可以手动进行标记为dirty,或者使用custom field proxy。以下是个简单的例子:
Java代码
@Entity
public class Externalization {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Persistent
@Externalizer("getName")
@Factory("forName")
private Class clazz;
@Persistent
@Factory("Externalization.stringToURL")
@Externalizer("Externalization.urlToString")
private URL url;
@Basic
@ExternalValues({"SMALL=5", "MEDIUM=8", "LARGE=10"})
@Type(int.class)
private String size;
public static URL stringToURL(String s) {
try {
return new URL(s);
} catch (MalformedURLException e) {
throw new RuntimeException(e);
}
}
public static String urlToString(URL url) {
return url.toExternalForm();
}
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("id: ").append(id);
sb.append(", clazz: ").append(clazz);
sb.append(", url: ").append(url);
sb.append(", size: ").append(size);
return sb.toString();
}
}
EntityManager em = entityManagerFactory.createEntityManager();
em.getTransaction().begin();
Externalization e1 = new Externalization();
e1.setClazz(Externalization.class);
e1.setUrl(new URL("http://www.abc.com"));
e1.setSize("MEDIUM");
em.persist(e1);
em.getTransaction().commit();
em.close();
em = entityManagerFactory.createEntityManager();
Query q = em.createQuery("select m from Externalization m where m.url = 'http://www.abc.com'");
List<Externalization> r1 = (List<Externalization>)q.getResultList();
for(Iterator iter = r1.iterator(); iter.hasNext(); ) {
System.out.println(iter.next().toString());
}
em.close();
@Entity
public class Externalization {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Persistent
@Externalizer("getName")
@Factory("forName")
private Class clazz;
@Persistent
@Factory("Externalization.stringToURL")
@Externalizer("Externalization.urlToString")
private URL url;
@Basic
@ExternalValues({"SMALL=5", "MEDIUM=8", "LARGE=10"})
@Type(int.class)
private String size;
public static URL stringToURL(String s) {
try {
return new URL(s);
} catch (MalformedURLException e) {
throw new RuntimeException(e);
}
}
public static String urlToString(URL url) {
return url.toExternalForm();
}
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("id: ").append(id);
sb.append(", clazz: ").append(clazz);
sb.append(", url: ").append(url);
sb.append(", size: ").append(size);
return sb.toString();
}
}
EntityManager em = entityManagerFactory.createEntityManager();
em.getTransaction().begin();
Externalization e1 = new Externalization();
e1.setClazz(Externalization.class);
e1.setUrl(new URL("http://www.abc.com"));
e1.setSize("MEDIUM");
em.persist(e1);
em.getTransaction().commit();
em.close();
em = entityManagerFactory.createEntityManager();
Query q = em.createQuery("select m from Externalization m where m.url = 'http://www.abc.com'");
List<Externalization> r1 = (List<Externalization>)q.getResultList();
for(Iterator iter = r1.iterator(); iter.hasNext(); ) {
System.out.println(iter.next().toString());
}
em.close();
以上代码执行完毕后数据库中externalization表的数据如下: Sql代码
mysql> select * from externalization;
+----+-----------------+------+--------------------+
| id | clazz | size | url |
+----+-----------------+------+--------------------+
| 1 | Externalization | 8 | http://www.abc.com |
+----+-----------------+------+--------------------+
mysql> select * from externalization;
+----+-----------------+------+--------------------+
| id | clazz | size | url |
+----+-----------------+------+--------------------+
| 1 | Externalization | 8 | http://www.abc.com |
+----+-----------------+------+--------------------+
10.5 Fetch Groups
Fetch groups是一组同时被加载的属性。之前介绍的Fetch Type指定了如何通过annotations指定某个属性是eagerly还是 lazily 加载。Fetch groups 则是提供了动态指定加载方式的能力。.
10.5.1 Custom Fetch Groups
OpenJPA缺省fetch group中的属性都会被eagerly加载。此外可以通过org.apache.openjpa.persistence.FetchGroup annotation定义named fetch groups以便在运行时激活它。在加载的时候,OpenJPA会eagerly加载所有被激活的fetch groups中的属性。FetchGroup annotation有以下属性:
String name: fetch group 的全局名。以下名字被OpenJPA保留:default 、values、 all、none以及任何以jdo、jpa或openjpa开头的名字。
FetchAttribute[] attributes: fetch group中persistent fileds或者properties数组。
String[] fetchGroups: 包含在次fetch group中的其它fetch groups名。
org.apache.openjpa.persistence.FetchAttribute annotation的属性如下:
String name: persistent field 或者 property 名。
recursionDepth: eager-fetch 的递归深度,缺省是1(-1无限制)。
Entity class的某个属性可以包含在任何的fetch group中,它也可以声明其load fetch group。缺省情况下,OpenJPA在第一次访问lazy-loaded属性的时候访问数据库。然而如果你直到当你访问某个lazy-loaded属性A的时候,你很可能也同时访问lazy-loaded 属性B和C,因此在一次数据库访问中同时加载A、B和C是更有效的。
通过org.apache.openjpa.persistence.LoadFetchGroup annotation为某个属性指定load fetch group。以下是个简单的例子:
Java代码
import org.apache.openjpa.persistence.*;
@Entity
@FetchGroups({
@FetchGroup(name="detail", attributes={
@FetchAttribute(name="publisher"),
@FetchAttribute(name="articles")
})
})
public class Magazine {
@ManyToOne(fetch=FetchType.LAZY)
@LoadFetchGroup("detail")
private Publisher publisher;
}
import org.apache.openjpa.persistence.*;
@Entity
@FetchGroups({
@FetchGroup(name="detail", attributes={
@FetchAttribute(name="publisher"),
@FetchAttribute(name="articles")
})
})
public class Magazine {
@ManyToOne(fetch=FetchType.LAZY)
@LoadFetchGroup("detail")
private Publisher publisher;
}
10.5.2 Custom Fetch Group Configuration
OpenJPAEntityManager接口和OpenJPAQuery接口可以用于访问org.apache.openjpa.persistence.FetchPlan。FetchPlan通过以下方法维护当前活跃的fetch groups和maximum fetch depth:
Java代码
public FetchPlan addFetchGroup(String group);
public FetchPlan addFetchGroups(String... groups);
public FetchPlan addFetchGroups(Collection groups);
public FetchPlan removeFetchGrop(String group);
public FetchPlan removeFetchGroups(String... groups);
public FetchPlan removeFetchGroups(Collection groups);
public FetchPlan resetFetchGroups();
public Collection<String> getFetchGroups();
public void clearFetchGroups();
public FetchPlan setMaxFetchDepth(int depth);
public int getMaxFetchDepth();
public FetchPlan addFetchGroup(String group);
public FetchPlan addFetchGroups(String... groups);
public FetchPlan addFetchGroups(Collection groups);
public FetchPlan removeFetchGrop(String group);
public FetchPlan removeFetchGroups(String... groups);
public FetchPlan removeFetchGroups(Collection groups);
public FetchPlan resetFetchGroups();
public Collection<String> getFetchGroups();
public void clearFetchGroups();
public FetchPlan setMaxFetchDepth(int depth);
public int getMaxFetchDepth(); Maximum fetch depth指定了加载时遍历对象的深度,缺省值是-1(无限制)。如果MaxFetchDepth是1,那么OpenJPA将会加载目标实例和它的直接relations; 如果MaxFetchDepth是2,那么OpenJPA会加载目标实例、直接relations和直接relations上的relations;如果MaxFetchDepth是-1,那么OpenJPA会加载目标实例以及所有的relatons直到到达对象图的边缘。当然以上的加载过程依赖于被加载属性是否是eagerly load,以及当前活跃的fetch group。以下是个简单的例子: Java代码
OpenJPAQuery kq = OpenJPAPersistence.cast(em.createQuery(...));
kq.getFetchPlan().setMaxFetchDepth(3).addFetchGroup("detail");
List results = kq.getResultList();
OpenJPAQuery kq = OpenJPAPersistence.cast(em.createQuery(...));
kq.getFetchPlan().setMaxFetchDepth(3).addFetchGroup("detail");
List results = kq.getResultList();
10.5.3 Per-field Fetch Configuration
除了基于per-fetch-group 的配置外,OpenJPA也支持基于per-field的配置。通过以下方法将特定的field包含到当前的fetch plan中。
Java代码
public FetchPlan addField(String field);
public FetchPlan addFields(String... fields);
public FetchPlan addFields(Class cls, String... fields);
public FetchPlan addFields(Collection fields);
public FetchPlan addFields(Class cls, Collection fields);
public FetchPlan removeField(String field);
public FetchPlan removeFields(String... fields);
public FetchPlan removeFields(Class cls, String... fields);
public FetchPlan removeFields(Collection fields);
public FetchPlan removeFields(Class cls, Collection fields);
public Collection<String> getFields();
public void clearFields();
public FetchPlan addField(String field);
public FetchPlan addFields(String... fields);
public FetchPlan addFields(Class cls, String... fields);
public FetchPlan addFields(Collection fields);
public FetchPlan addFields(Class cls, Collection fields);
public FetchPlan removeField(String field);
public FetchPlan removeFields(String... fields);
public FetchPlan removeFields(Class cls, String... fields);
public FetchPlan removeFields(Collection fields);
public FetchPlan removeFields(Class cls, Collection fields);
public Collection<String> getFields();
public void clearFields(); 需要注意的是,以上方法中的field必须定义在指定的类中,而不是在其父类中。如果field publisher被定义在Publication中,而不是其子类Magazine中,那么必须用 addField (Publication.class, "publisher"),而不是addField (Magazine.class, "publisher")。出于性能上的考虑,OpenJPA并不对class name / field name 对进行验证。如果指定了不存在的class name / field name 对,那么会被OpenJPA忽略。以下是个简单的例子: Java代码
OpenJPAEntityManager kem = OpenJPAPersistence.cast(em);
kem.getFetchPlan().addField(Magazine.class, "publisher");
Magazine mag = em.find(Magazine.class, magId);
10.1 Restoring State
JPA规范要求不应该使用rolled back objects,但是这些对象在OpenJPA中是有效的。可以通过配置openjpa.RestoreState 属性来控制是否将对象的状态回滚到事务前的状态。它有以下可选值:
none: 不回滚对象状态,但是对象变成hollow,在下次访问的时候会重新加载。
immutable: 回滚不可变的状态,可变的状态变成hollow,在下次访问的时候会重新加载。
all: 回滚所有状态。
10.2 Typing and Ordering
当为对象的属性加载persistent state的时候,OpenJPA会检查这个属性在声明时或者无参构造函数中被赋值的类型。如果这个类型比声明的类型更精确,那么OpenJPA会用这个类型。如果你在初始化某个属性的时候使用了comparator,那么OpenJPA也会在每次加载persistent state的时候使用这个comparator。例如:
Java代码
public class Company {
// OpenJPA 会在每次加载数据的时候使用SalaryComparator。
private Collection employeesBySal = new TreeSet(new SalaryComparator());
private Map departments;
public Company {
// OpenJPA会使用TreeMap来保存departments 相关的persistent state。
departments = new TreeMap();
}
}
public class Company {
// OpenJPA 会在每次加载数据的时候使用SalaryComparator。
private Collection employeesBySal = new TreeSet(new SalaryComparator());
private Map departments;
public Company {
// OpenJPA会使用TreeMap来保存departments 相关的persistent state。
departments = new TreeMap();
}
}
10.3 Proxies
10.3.1 Smart Proxies
在运行时,OpenJPA可以通过代理跟踪entity 实例的属性是否被修改过,以便更有效地更新数据库。当设计persistent class的时候,应该尽可能将collection field映射成java.util.Set、java.util.TreeSet或java.util.HashSet。Smart proxy对这些类型可以进行更好的优化。
10.3.2 Large Result Set Proxies
当遍历persistent collection 或者map属性的时候,ORM的缺省行为是把所有persistent state载入到内存中。然而,如果载入的数据量过大,那么可能会降低性能。OpenJPA为这些large result set属性使用特殊的代理。它并不在内存中缓存任何数据,相反它会访问数据库来获得相关的结果。例如large result set collection的contains方法会导致在数据库中执行类似于SELECT COUNT(*) WHERE的查询。类似地,在每次试图获得iterator的时候,OpenJPA会使用当前的large result set配置来执行特定的query。在调用iterator.next方法的时候,OpenJPA会按需载入结果对象。此时需要通过OpenJPAPersistence.close方法来释放资源,例如:
Java代码
import org.apache.openjpa.persistence.*;
@Entity
public class Company {
@ManyToMany
@LRS
private Collection<Employee> employees;
...
}
Collection employees = company.getEmployees(); // employees is a lrs collection
Iterator itr = employees.iterator();
while (itr.hasNext()) {
process((Employee) itr.next());
}
OpenJPAPersistence.close(itr);
import org.apache.openjpa.persistence.*;
@Entity
public class Company {
@ManyToMany
@LRS
private Collection<Employee> employees;
...
}
Collection employees = company.getEmployees(); // employees is a lrs collection
Iterator itr = employees.iterator();
while (itr.hasNext()) {
process((Employee) itr.next());
}
OpenJPAPersistence.close(itr);
Large result set 属性只能被声明成java.util.Collection 或者java.util.Map;它不能包含externalizer;Large result set proxy不能从一个entity 实例转移到另外一个entity 实例中,例如以下代码会导致提交时的一个错误:
Java代码
Collection employees = company.getEmployees() // employees is a lrs collection
company.setEmployees(null);
anotherCompany.setEmployees(employees);
Collection employees = company.getEmployees() // employees is a lrs collection
company.setEmployees(null);
anotherCompany.setEmployees(employees);
10.3.3 Custom Proxies
OpenJPA通过org.apache.openjpa.util.ProxyManager接口管理代理。其缺省的实现是org.apache.openjpa.util.ProxyManagerImpl。它有以下配置属性:
TrackChanges: 是否使用smart proxy,缺省是true。
AssertAllowedType: 在向collection或map中加入元素的时候,如果跟metadata 中声明的类型不符,是否抛出异常,缺省是false。
以下是个简单的例子:
Xml代码
<property name="openjpa.ProxyManager" value="TrackChanges=false"/>
<property name="openjpa.ProxyManager" value="TrackChanges=false"/> 缺省的proxy manager可以代理 Collection, List, Map, Queue, Date, or Calendar 等类上的标准方法,也可以代理定制类型,但是这些定制类型必须复合以下条件:
Custom container types必须有一个公共的无参构造函数,或者一个公共的以Comparator为参数类型的构造函数。
Custom date types必须有一个公共的无参构造函数,或者一个公共的以long为参数 类型(代表当前的时间)的构造函数。
Other custom types必须有一个公共的无参构造函数,或者公共的拷贝构造函数。如果没有公共的拷贝构造函数,那么在进行拷贝的时候,首先会创建一个对象B,然后通过以A上getter方法的返回值为参数,调用B的setter方法。 因此你要确保通过这种方式,B是A的完整拷贝。
如果某个custom classes无法满足以上条件,那么OpenJPA允许你定义你自己的proxy class和proxy manager。
10.4 Externalization
OpenJPA 支持通过custom field mappings 来完全控制entity class的field在datastore中怎样被保存、查询和加载。然而一个更轻量级的方法是使用externalization 。Externalization 支持通过指定某些方法来控制保存和加载的方式。需要注意的是,不能在@EmbeddedId字段上使用externalization。
OpenJPA使用org.apache.openjpa.persistence.Externalizer annotation指定将某个属性转换为external value的方法名。如果指定一个non-static方法,那么OpenJPA会假定目标对象是被Externalizer标记的属性对象;如果指定一个static方法, 那么被OpenJPA会把被Externalizer标记的属性对象作为一个方法的参数。每个方法也可以接受一个StoreContext 型的参数。方法的返回值指定了缺省的external 类型。假设希望将某个CustomType类型的属性转换成String类型,那么可以采用以下的方法:
Method Extension
public String CustomType.toString() @Externalizer("toString")
public String CustomType.toString(StoreContext ctx) @Externalizer("toString")
public static String AnyClass.toString(CustomType ct) @Externalizer("AnyClass.toString")
public static String AnyClass.toString(CustomType ct, StoreContext ctx) @Externalizer("AnyClass.toString")
OpenJPA使用org.apache.openjpa.persistence.Factory annotation指定根据external value初始化某个属性的方法名。 如果指定static方法,那么这个方法必须返回这个属性类型的一个实例。这个方法可以接受StoreContext 类型的一个参数。如果没有指定factory annotation,那么这个属性的class必须包含以external form为参数的构造函数,否则会抛出一个异常。假设希望将String类型转换成某个CustomType类型,那么可以采用以下的方法:
Method Extension
public CustomType(String str) none
public static CustomType CustomType.fromString(String str) @Factory("fromString")
public static CustomType CustomType.fromString(String str, StoreContext ctx) @Factory("fromString")
public static CustomType AnyClass.fromString(String str) @Factory("AnyClass.fromString")
public static CustomType AnyClass.fromString(String str, StoreContext ctx) @Factory("AnyClass.fromString")
OpenJPA使用org.apache.openjpa.persistence.ExternalValues annotation指定external value的转换。 其value pairs用于指定Java和datastore的类型。如果datastore的类型不同于Java类型,那么通过org.apache.openjpa.persistence.Type annotation 指定datastore类型。如果externalized属性不是标准的persistent type,那么必须用org.apache.openjpa.persistence.Persistent annotation显式地进行标记。如果externalized 属性是可变的,而且不是collection、map和date类型,那么OpenJPA无法进行脏检查。可以手动进行标记为dirty,或者使用custom field proxy。以下是个简单的例子:
Java代码
@Entity
public class Externalization {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Persistent
@Externalizer("getName")
@Factory("forName")
private Class clazz;
@Persistent
@Factory("Externalization.stringToURL")
@Externalizer("Externalization.urlToString")
private URL url;
@Basic
@ExternalValues({"SMALL=5", "MEDIUM=8", "LARGE=10"})
@Type(int.class)
private String size;
public static URL stringToURL(String s) {
try {
return new URL(s);
} catch (MalformedURLException e) {
throw new RuntimeException(e);
}
}
public static String urlToString(URL url) {
return url.toExternalForm();
}
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("id: ").append(id);
sb.append(", clazz: ").append(clazz);
sb.append(", url: ").append(url);
sb.append(", size: ").append(size);
return sb.toString();
}
}
EntityManager em = entityManagerFactory.createEntityManager();
em.getTransaction().begin();
Externalization e1 = new Externalization();
e1.setClazz(Externalization.class);
e1.setUrl(new URL("http://www.abc.com"));
e1.setSize("MEDIUM");
em.persist(e1);
em.getTransaction().commit();
em.close();
em = entityManagerFactory.createEntityManager();
Query q = em.createQuery("select m from Externalization m where m.url = 'http://www.abc.com'");
List<Externalization> r1 = (List<Externalization>)q.getResultList();
for(Iterator iter = r1.iterator(); iter.hasNext(); ) {
System.out.println(iter.next().toString());
}
em.close();
@Entity
public class Externalization {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Persistent
@Externalizer("getName")
@Factory("forName")
private Class clazz;
@Persistent
@Factory("Externalization.stringToURL")
@Externalizer("Externalization.urlToString")
private URL url;
@Basic
@ExternalValues({"SMALL=5", "MEDIUM=8", "LARGE=10"})
@Type(int.class)
private String size;
public static URL stringToURL(String s) {
try {
return new URL(s);
} catch (MalformedURLException e) {
throw new RuntimeException(e);
}
}
public static String urlToString(URL url) {
return url.toExternalForm();
}
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("id: ").append(id);
sb.append(", clazz: ").append(clazz);
sb.append(", url: ").append(url);
sb.append(", size: ").append(size);
return sb.toString();
}
}
EntityManager em = entityManagerFactory.createEntityManager();
em.getTransaction().begin();
Externalization e1 = new Externalization();
e1.setClazz(Externalization.class);
e1.setUrl(new URL("http://www.abc.com"));
e1.setSize("MEDIUM");
em.persist(e1);
em.getTransaction().commit();
em.close();
em = entityManagerFactory.createEntityManager();
Query q = em.createQuery("select m from Externalization m where m.url = 'http://www.abc.com'");
List<Externalization> r1 = (List<Externalization>)q.getResultList();
for(Iterator iter = r1.iterator(); iter.hasNext(); ) {
System.out.println(iter.next().toString());
}
em.close();
以上代码执行完毕后数据库中externalization表的数据如下: Sql代码
mysql> select * from externalization;
+----+-----------------+------+--------------------+
| id | clazz | size | url |
+----+-----------------+------+--------------------+
| 1 | Externalization | 8 | http://www.abc.com |
+----+-----------------+------+--------------------+
mysql> select * from externalization;
+----+-----------------+------+--------------------+
| id | clazz | size | url |
+----+-----------------+------+--------------------+
| 1 | Externalization | 8 | http://www.abc.com |
+----+-----------------+------+--------------------+
10.5 Fetch Groups
Fetch groups是一组同时被加载的属性。之前介绍的Fetch Type指定了如何通过annotations指定某个属性是eagerly还是 lazily 加载。Fetch groups 则是提供了动态指定加载方式的能力。.
10.5.1 Custom Fetch Groups
OpenJPA缺省fetch group中的属性都会被eagerly加载。此外可以通过org.apache.openjpa.persistence.FetchGroup annotation定义named fetch groups以便在运行时激活它。在加载的时候,OpenJPA会eagerly加载所有被激活的fetch groups中的属性。FetchGroup annotation有以下属性:
String name: fetch group 的全局名。以下名字被OpenJPA保留:default 、values、 all、none以及任何以jdo、jpa或openjpa开头的名字。
FetchAttribute[] attributes: fetch group中persistent fileds或者properties数组。
String[] fetchGroups: 包含在次fetch group中的其它fetch groups名。
org.apache.openjpa.persistence.FetchAttribute annotation的属性如下:
String name: persistent field 或者 property 名。
recursionDepth: eager-fetch 的递归深度,缺省是1(-1无限制)。
Entity class的某个属性可以包含在任何的fetch group中,它也可以声明其load fetch group。缺省情况下,OpenJPA在第一次访问lazy-loaded属性的时候访问数据库。然而如果你直到当你访问某个lazy-loaded属性A的时候,你很可能也同时访问lazy-loaded 属性B和C,因此在一次数据库访问中同时加载A、B和C是更有效的。
通过org.apache.openjpa.persistence.LoadFetchGroup annotation为某个属性指定load fetch group。以下是个简单的例子:
Java代码
import org.apache.openjpa.persistence.*;
@Entity
@FetchGroups({
@FetchGroup(name="detail", attributes={
@FetchAttribute(name="publisher"),
@FetchAttribute(name="articles")
})
})
public class Magazine {
@ManyToOne(fetch=FetchType.LAZY)
@LoadFetchGroup("detail")
private Publisher publisher;
}
import org.apache.openjpa.persistence.*;
@Entity
@FetchGroups({
@FetchGroup(name="detail", attributes={
@FetchAttribute(name="publisher"),
@FetchAttribute(name="articles")
})
})
public class Magazine {
@ManyToOne(fetch=FetchType.LAZY)
@LoadFetchGroup("detail")
private Publisher publisher;
}
10.5.2 Custom Fetch Group Configuration
OpenJPAEntityManager接口和OpenJPAQuery接口可以用于访问org.apache.openjpa.persistence.FetchPlan。FetchPlan通过以下方法维护当前活跃的fetch groups和maximum fetch depth:
Java代码
public FetchPlan addFetchGroup(String group);
public FetchPlan addFetchGroups(String... groups);
public FetchPlan addFetchGroups(Collection groups);
public FetchPlan removeFetchGrop(String group);
public FetchPlan removeFetchGroups(String... groups);
public FetchPlan removeFetchGroups(Collection groups);
public FetchPlan resetFetchGroups();
public Collection<String> getFetchGroups();
public void clearFetchGroups();
public FetchPlan setMaxFetchDepth(int depth);
public int getMaxFetchDepth();
public FetchPlan addFetchGroup(String group);
public FetchPlan addFetchGroups(String... groups);
public FetchPlan addFetchGroups(Collection groups);
public FetchPlan removeFetchGrop(String group);
public FetchPlan removeFetchGroups(String... groups);
public FetchPlan removeFetchGroups(Collection groups);
public FetchPlan resetFetchGroups();
public Collection<String> getFetchGroups();
public void clearFetchGroups();
public FetchPlan setMaxFetchDepth(int depth);
public int getMaxFetchDepth(); Maximum fetch depth指定了加载时遍历对象的深度,缺省值是-1(无限制)。如果MaxFetchDepth是1,那么OpenJPA将会加载目标实例和它的直接relations; 如果MaxFetchDepth是2,那么OpenJPA会加载目标实例、直接relations和直接relations上的relations;如果MaxFetchDepth是-1,那么OpenJPA会加载目标实例以及所有的relatons直到到达对象图的边缘。当然以上的加载过程依赖于被加载属性是否是eagerly load,以及当前活跃的fetch group。以下是个简单的例子: Java代码
OpenJPAQuery kq = OpenJPAPersistence.cast(em.createQuery(...));
kq.getFetchPlan().setMaxFetchDepth(3).addFetchGroup("detail");
List results = kq.getResultList();
OpenJPAQuery kq = OpenJPAPersistence.cast(em.createQuery(...));
kq.getFetchPlan().setMaxFetchDepth(3).addFetchGroup("detail");
List results = kq.getResultList();
10.5.3 Per-field Fetch Configuration
除了基于per-fetch-group 的配置外,OpenJPA也支持基于per-field的配置。通过以下方法将特定的field包含到当前的fetch plan中。
Java代码
public FetchPlan addField(String field);
public FetchPlan addFields(String... fields);
public FetchPlan addFields(Class cls, String... fields);
public FetchPlan addFields(Collection fields);
public FetchPlan addFields(Class cls, Collection fields);
public FetchPlan removeField(String field);
public FetchPlan removeFields(String... fields);
public FetchPlan removeFields(Class cls, String... fields);
public FetchPlan removeFields(Collection fields);
public FetchPlan removeFields(Class cls, Collection fields);
public Collection<String> getFields();
public void clearFields();
public FetchPlan addField(String field);
public FetchPlan addFields(String... fields);
public FetchPlan addFields(Class cls, String... fields);
public FetchPlan addFields(Collection fields);
public FetchPlan addFields(Class cls, Collection fields);
public FetchPlan removeField(String field);
public FetchPlan removeFields(String... fields);
public FetchPlan removeFields(Class cls, String... fields);
public FetchPlan removeFields(Collection fields);
public FetchPlan removeFields(Class cls, Collection fields);
public Collection<String> getFields();
public void clearFields(); 需要注意的是,以上方法中的field必须定义在指定的类中,而不是在其父类中。如果field publisher被定义在Publication中,而不是其子类Magazine中,那么必须用 addField (Publication.class, "publisher"),而不是addField (Magazine.class, "publisher")。出于性能上的考虑,OpenJPA并不对class name / field name 对进行验证。如果指定了不存在的class name / field name 对,那么会被OpenJPA忽略。以下是个简单的例子: Java代码
OpenJPAEntityManager kem = OpenJPAPersistence.cast(em);
kem.getFetchPlan().addField(Magazine.class, "publisher");
Magazine mag = em.find(Magazine.class, magId);
发表评论
-
EJB3 QL查询
2008-07-17 15:57 1547EJB3 QL查询 EJB3的查询语言是一种和SQL非常类似的 ... -
Table
2008-07-08 12:18 2022Table Table用来定义entity主表的name,ca ... -
Overview
2008-07-07 19:33 9471 Overview Apache OpenJPA是J ... -
Metadata
2008-07-07 19:32 13443 Metadata 通过javax.p ... -
EntityManagerFactory
2008-07-07 19:30 95564 EntityManagerFactory 4.1 Over ... -
Object Locking
2008-07-07 19:27 13508 Object Locking 8.1 Configurin ... -
Query
2008-07-07 19:26 15956 Query 6.1 JPQL Queries 6.1.1Q ... -
jpa继承关系详解
2008-07-07 19:07 82327 Inheritance 对象使用引用以便关联到其它 ... -
JNDI简介
2008-05-29 17:03 1709JNDI简介 & 简单示例 ... -
ejb2 和 ejb3的区别
2008-03-31 13:39 4248EJB 3 和EJB 2.1 的区别 从整个EJB 规范的 ...
相关推荐
l Other miscellaneous features 译:其他各种特性 CSLA .NET的关键技术: l Remoting l 串行化 l Enterprise Services(COM+) l 反射 l 属性 l .NET基于角色的安全性 l ADO.NET CSLA .NET组件设计图及其...
| **Miscellaneous Features** | | | | | Capes/Expansion Boards | Yes | Yes | No | #### Building Minix on ARM To build Minix on ARM, follow these steps: 1. **Checkout the Code** - Create a directory...
另外,通过“Miscellaneous features”模块的学习,用户可以掌握PreScan的一些高级功能,如动态天气条件的模拟、行人行为的模拟、以及与硬件在环(HIL)系统的集成等。 PreScan软件还有专门的模块用于模拟主动安全...
##### 2.7 Miscellaneous Features - **额外特性**:包括各种附加功能,如工具箱等。 #### 三、Metalink的使用方法 ##### 3.1 如何登录Metalink - **网址**:访问metalink.oracle.com进行登录。 - **新用户**:...
Reference pages for Xlib-related Xmu functions (miscellaneous utilities) Four single-page reference aids for the GC and window attributes Features in the third edition include: Over 100 new man ...
Reference pages for Xlib-related Xmu functions (miscellaneous utilities) Four single-page reference aids for the GC and window attributes Features in the third edition include: Over 100 new man ...
Reference pages for Xlib-related Xmu functions (miscellaneous utilities) Four single-page reference aids for the GC and window attributes Features in the third edition include: Over 100 new man ...
Miscellaneous - capture data review of raide VEC buttons Digital excample - dpinvecblockread, dpinvecblockwrite, capture data with PSQ Digital Example - dpintimeset:unique timesets per site ...
Chapter 8: Miscellaneous Goodies Chapter 9: Java 7 Features That You May Have Missed Book Details Title: Java SE 8 for the Really Impatient Author: Cay S. Horstmann Length: 240 pages Edition: 1 ...
Miscellaneous Specifications of Interest 258 Other References 259 Web Sites 259 Chapter 7 Evolution of Mobile Communication Networks 261 Review of 3G Requirements [1]-[4] 262 Network Evolution 264 ...
New Features QTZ-196 - New trigger type 'DailyTimeIntervalTrigger' QTZ-186 - Improvements for interrupting executing jobs Miscellaneous Performance improvements, including: Now Implemented In JDBC-...
Get more comprehension with Code Visualizer. Save your time from reading and understanding from text source codes. Code Visualizer provides various point of views from...*Fixed and updated Miscellaneous.
Code formatting options, custom type & member replacements, custom string replacements, and miscellaneous options. (可以指定转换规则) 5. File comparison feature: After converting a project or folder,...
- **Miscellaneous**: Includes additional functionalities such as test modes and detailed pin descriptions. #### Functional Description ##### Overview The TW8816 is designed to process and display ...
Chapter 22Miscellaneous Utilitiescovers the rest of the utility classes such as bit sets, formatted output, text scanning, and random number generation. Chapter 23System Programmingleads you through ...