2008-10-07 71 views
2

在JPA中,实体是很好的注释的普通旧Java对象。但是我还没有找到一个与它们和数据库交互的好方法。什么是针对Java的查询“图层”的好设计JPA

在我目前的应用程序中,我的基本设计总是有一个基于序列的id作为主键,所以我通常必须通过除PK之外的其他属性来查找实体。

并为每个实体我有

@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:

  1. 我真的很讨厌有这些EJB中的方法,因为它们似乎属于实体本身,EJB本地接口a不要把我当作垃圾。我讨厌在每个方法中使用“try,createQuery,getResultList,catch,log,return”(主要是没有关闭或者“with语句”或某些Java语言中的结果)的重复。

有没有人有更好的方式与实体和数据库进行交互,以解决我的一个或两个问题的建议?

我目前正在考虑用泛型和反射做一些基本方法,以获得一些通用查询方法来减少重复(问题2)(我将把原型放到稍后查看)。

感谢, 安德斯

回答

4

尝试缝。 Query Objects为你做了大部分工作,而且它们很容易扩展。或者,你总是可以实现类似的模式。

一般来说,Seam在弥合JPA与您的视图和业务层之间的差距方面做了很多有用的工作。您不必使用Seam的JSF就很有用。

1

如果你做了很多文字搜索,也许你还应该考虑一些索引框架,如Compass
我不知道它是否适合您的应用程序,但如果是这样,它可以改善代码设计和性能。

3

你不必要的冗长。首先,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(); 
} 

应足以返回结果的列表,如果有任何或者有没有空List。有两点需要注意:

  1. @SuppressWarnings(“未登记”)是不必要的,但它摆脱铸造从getResultList()的泛型列表非泛型列表的结果时,否则不可避免的警告的;和

  2. 这可能是值得用MyEnt上的@NamedQuery替代createQuery()调用(通常)。首先,这将启用部署时间验证和其他有用的事情。

它的合理简洁和完整。

1

Moin!

这里是我的版本为单一结果(我用的TopLink要领用它在我的桌面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)); 

最好的问候, 乔希。