什么是查询“层的好设计” for Java JPA
题
在JPA中,实体是带有标注的Plain Old Java Objects。但我没有找到与他们和数据库进行交互的好方法。
在我当前的应用程序中,我的基本设计始终是将基于序列的id作为主键,因此我通常必须使用除PK之外的其他属性来查找实体。
对于每个实体,我都有一个
的无状态EJB@Stateless
public class MyEntApiBean implements MyEntApi {
@PersistenceContext(unitName = "xxx") @Inject EntityManager entityManager;
查询方法都是一些变异
/**
* @return A List of all MyEnts that have some property
* @param someProp some property
*/
public List<MyEnt> getAllMyEntsFromProp(final String someProp) {
try {
final Query query = entityManager.createQuery("select me from MyEnt me where me.someProp = :someProp");
query.setParameter("someProp", someProp);
return query.getResultList();
} catch(final NoResultException nre) {
log.warn("No MyEnts found");
}
return new ArrayList<MyEnt>();
}
所以:
-
我真的很讨厌在EJB中使用这些方法,因为它们似乎属于实体本身,并且EJB本地接口惹恼了我。
-
我讨厌在每个方法中使用“try,createQuery,getResultList,catch,log,return”复制。 (主要是没有关闭或“带有声明”或Java中的某些内容的结果)。
醇>
是否有人建议更好地与实体和数据库进行交互以解决我的一个或两个问题?
我目前正在考虑使用泛型和反射来做一些基本方法,以获得一些通用的查询方法来减少重复(问题2)(我将把原型放到后面进行审查)。
谢谢, 安德斯
解决方案
尝试接缝。 查询对象做得最多为你工作,他们很容易扩展。或者,您可以始终实现类似的模式。
一般来说,Seam做了很多有用的工作来弥合JPA与你的视图和业务层之间的差距。您不必使用JSF for Seam有用。
其他提示
你是不必要的冗长。首先,当没有返回任何行时,getResultList()不会抛出异常(至少在Eclipse或Toplink中没有 - 我无法想象另一个提供者有什么不同)。 getSingleResult()可以,getResultList()没有。此外,您可以使用构建器模式:
@SuppressWarnings("unchecked")
public List<MyEnt> getAllMyEntsFromProp(final String someProp) {
return entityManager.createQuery("select me from MyEnt me where me.someProp = :someProp")
.setParameter("someProp", someProp);
.getResultList();
}
应足以返回结果列表(如果有)或空列表(如果没有)。有两点需要注意:
-
@SuppressWarnings(&quot; unchecked&quot;)是不必要的,但是当将getResultList()的非泛型List结果转换为泛型List时,它会消除一个不可避免的警告;以及
-
在MyEnt(通常)上使用@NamedQuery替换createQuery()调用可能是值得的。首先,这将启用部署时验证和其他有用的东西。
醇>
它相当简洁和完整。
如果您进行了大量的文本搜索,也许您还应该考虑一些索引框架,例如指南针。
我不知道它是否适合您的应用程序,但如果是这样,它可以改善代码设计和性能。
我实际上在使用Seam。并且Query对象建议引导我找到Hibernates Criteria queries (按示例查询)功能。这似乎与我正在寻找的非常接近。
也许在基类中,并使用破折号泛型的....?
莫因!
以下是我的单个结果版本(我在使用TopLink essentials的桌面JPA应用程序中使用它):
public class JPA {
@SuppressWarnings ("unchecked")
public static <T> T querySingle(
EntityManager em,
Class<T> clazz,
String namedQuery,
Pair... params)
{
Query q = em.createNamedQuery(namedQuery);
for (Pair pair : params) {
q.setParameter(pair.key, pair.value);
}
List<T> result = q.getResultList();
if ( result.size() == 0 ) {
return null;
}
if ( result.size() == 1 ) {
return result.get(0);
}
throw new
IllegalStateException(
"To many result rows for query: "
+ namedQuery
+ " where "
+ Arrays.toString(params));
}
public static class Pair {
String key;
Object value;
public static Pair param (String key, Object value) {
return new Pair (key, value);
}
public Pair (String key, Object value) {
this.key = key;
this.value = value;
}
@Override
public String toString() {
return key + "=" + value;
}
}
}
用法:
import static org.sepix.JPA.*;
...
String id = ...
Customer customer = querySingle (em, Customer.class,
"Customer.findByID", Pair.param ("id", id));
或:
String inquiryID = ...
Boolean current = Boolean.TRUE;
Inquiry inq = querySingle (em, Inquiry.class,
"Inquiry.findCurrent",
Pair.param ("inquiry", inquiryID),
Pair.param ("current", current));
最好的问候, 约什
我更喜欢使用Spring的JpaDaoSupport,它有助于处理JPA。一个很好的例子是 http:// github的.com / rafalrusin / jpaqb /斑点/主/ SRC /测试/ JAVA / jpaqb / CarDao.java 。
良好的逻辑分离是拥有DAO类(数据访问对象)和DTO(数据传输对象)。 DAO通常包含所有必需的查询,DTO是具有字段的实体。