代码之家  ›  专栏  ›  技术社区  ›  Powertieke

对于JavaJPA的查询“层”,什么是好的设计

  •  2
  • Powertieke  · 技术社区  · 16 年前

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

    在我当前的应用程序中,我的基本设计总是使用基于序列的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>();
    }
    

    所以:

    1. 我真的讨厌在EJB中使用这些方法,因为它们似乎属于实体本身,而EJB本地接口让我恼火。

    2. 我讨厌在每个方法中用“尝试,CeaTeaQueY,GETReultStEnLee,catch,log,返回”(主要是没有闭包或“带语句”或在Java中使用SUMESUCH)的重复。

    是否有人建议更好地与解决我的一个或两个问题的实体和数据库进行交互?

    我目前正在考虑用泛型和反射来做一些基本方法,以获得一些通用查询方法来减少重复(第2期)(我将在稍后发布一个原型以供审阅)。

    谢谢, 安德斯

    6 回复  |  直到 11 年前
        1
  •  4
  •   Sietse    16 年前

    试试接缝。这个 Query Objects 为你做大部分的工作,它们很容易扩展。或者,您可以始终实现类似的模式。

    一般来说,Seam做了很多有用的工作来弥合JPA与视图和业务层之间的鸿沟。为了使Seam有用,不必使用JSF。

        2
  •  3
  •   cletus    16 年前

    你说得太冗长了。首先,当没有返回任何行时(至少不在Eclipse或TopLink中),getResultList()不会抛出异常——我无法想象另一个提供程序会有什么不同。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();
    }
    

    如果有结果列表,则返回结果列表;如果没有结果列表,则返回空列表。需要注意的两件事:

    1. @SuppressWarnings(“unchecked”)是不必要的,但在将非泛型列表结果从getResultList()强制转换为泛型列表时,它会消除其他不可避免的警告;以及

    2. 用myent上的@namedquery(通常)替换createquery()调用可能是值得的。首先,这将启用部署时验证和其他有用的功能。

    它相当简洁和完整。

        3
  •  1
  •   Shimi Bandiel    16 年前

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

        4
  •  1
  •   Powertieke    16 年前

    我实际上在使用Seam。查询对象建议引导我找到休眠 Criteria queries (示例查询) functionality . 这似乎非常接近我正在寻找的。

    可能是在一个基类中,并且 dash of generics ……?

        5
  •  1
  •   Aljoscha Rittner    15 年前

    莫恩!

    这是我的单一结果版本(我在我的桌面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;
        }
      }
    }
    

    用法:

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

    最好的问候, 乔希。

        6
  •  0
  •   Rafal Rusin    14 年前

    我更喜欢使用Spring的jpadaosupport,这有助于处理jpa。这里有一个很好的例子 http://github.com/rafalrusin/jpaqb/blob/master/src/test/java/jpaqb/CarDao.java .

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