Java JPA查询“层”的良好设计是什么

Java JPA查询“层”的良好设计是什么,java,hibernate,jpa,ejb,Java,Hibernate,Jpa,Ejb,在JPA中,实体是带注释的普通Java对象。但我还没有找到一种与它们和数据库交互的好方法 在我当前的应用程序中,我的基本设计总是将基于序列的id作为主键,因此我通常必须按PK以外的其他属性查找实体 对于每个实体,我都有一个 @Stateless public class MyEntApiBean implements MyEntApi { @PersistenceContext(unitName = "xxx") @Inject EntityManager entityManager; 所

在JPA中,实体是带注释的普通Java对象。但我还没有找到一种与它们和数据库交互的好方法

在我当前的应用程序中,我的基本设计总是将基于序列的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中使用这些方法,因为它们似乎属于实体本身,EJB本地接口让我很恼火

我讨厌try、createQuery、getResultList、catch、log、return等方法中的重复,这主要是因为Java中没有闭包或with语句之类的东西

是否有人对如何更好地与实体和数据库进行交互提出了建议,以解决我的一个或两个问题

我目前正在考虑使用泛型和反射的一些基本方法来获得一些泛型查询方法,以减少重复问题2。我将在稍后提交一个原型供审查

谢谢, 安德斯

试试接缝。它们可以为您完成大部分工作,并且易于扩展。或者,您可以始终实现类似的模式


总的来说,Seam做了很多有用的事情来弥合JPA和您的视图和业务层之间的鸿沟。您不必使用JSF来实现SEAM是有用的。

如果您做了大量的文本搜索,也许您也应该考虑一些索引框架。我不知道它是否适合您的应用程序,但如果适合,它可以改进代码设计和性能。

我实际上使用的是Seam。查询对象建议引导我通过示例查找Hibernates查询。这似乎和我想要的非常接近


可能是在基类中,并且使用了….?

您不必要地冗长了。首先,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();
}
应足以返回结果列表(如果有),或返回空列表(如果没有)。有两点需要注意:

@SuppressWarningUnchecked是不必要的,但在将非泛型列表结果从getResultList强制转换为泛型列表时,它消除了在其他方面不可避免的警告;及

在MyEnt上用@NamedQuery替换createQuery调用可能是值得的。首先,这将启用部署时验证和其他有用的功能

它相当简洁和完整。

Moin

这是我的单一结果版本,我在桌面JPA应用程序和TopLink essentials中使用它:

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;
    }
  }
}
或:

致以最良好的祝愿,
josh.

我更喜欢使用Spring的JpaDaoSupport,它有助于处理JPA。这里有一个很好的例子

一个很好的逻辑分离是有一个DAO类数据访问对象和DTO数据传输对象。DAO通常包含所有必需的查询,DTO是带有字段的实体

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));