¿Qué es un buen diseño para una consulta & # 8220; layer & # 8221; para Java JPA

StackOverflow https://stackoverflow.com/questions/177927

  •  05-07-2019
  •  | 
  •  

Pregunta

En JPA, las Entidades son agradables Objetos de Java Antiguo Lisos. Pero no he encontrado una buena manera de interactuar con ellos y con la base de datos.

En mi aplicación actual, mi diseño básico siempre es tener una identificación basada en secuencia como clave principal, por lo que generalmente tengo que buscar entidades por otras propiedades que no sean PK.

Y para cada Entidad tengo un EJB sin estado de

@Stateless
public class MyEntApiBean implements MyEntApi {


@PersistenceContext(unitName = "xxx") @Inject EntityManager entityManager;

con métodos de consulta que todos son algunas variaciones

/**
 * @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>();
}

Entonces:

  1. Realmente odio tener estos métodos en un EJB porque parecen pertenecer a las entidades mismas, y las interfaces locales de EJB me molestan mucho.

  2. Odio la duplicación que tengo en cada método con " try, createQuery, getResultList, catch, log, return " (principalmente una consecuencia de que no haya cierres o " con una declaración " o algo en Java).

¿Alguien tiene alguna sugerencia para una mejor manera de interactuar con las Entidades y la Base de datos que aborda uno o ambos de mis problemas?

Actualmente estoy pensando en hacer algunos métodos básicos con genéricos y reflexión para obtener algunos métodos de consulta genéricos para reducir la duplicación (problema 2) (pondré un prototipo para su revisión más adelante).

Gracias, Anders

¿Fue útil?

Solución

Prueba Seam. Los Objetos de consulta hacen la mayoría del trabajo para usted, y son fácilmente extensibles. O, siempre podría implementar un patrón similar.

En general, Seam hace un montón de cosas útiles para cerrar la brecha entre JPA y las capas de vista y negocio. No tiene que usar JSF para que Seam sea útil.

Otros consejos

Estás siendo innecesariamente detallado. Por un lado, getResultList () no lanza una excepción cuando no se devuelven filas (al menos no en Eclipse o Toplink; no puedo imaginar que otro proveedor sea diferente). getSingleResult () hace, getResultList () no. Además, puedes usar el patrón de construcción para:

@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();
}

debería ser suficiente para devolver una Lista de resultados si hay alguno o una Lista vacía si no hay ninguno. Dos cosas a tener en cuenta:

  1. @SuppressWarnings (" unchecked ") es innecesario pero elimina una advertencia que de otra manera sería inevitable cuando se convierte el resultado de la Lista no genérica de getResultList () a una Lista genérica; y

  2. Probablemente valga la pena reemplazar la llamada a createQuery () con @NamedQuery en MyEnt (normalmente). Por un lado, esto permitirá la validación en tiempo de implementación y otras cosas útiles.

Es razonablemente conciso y completo.

Si realiza una gran cantidad de búsquedas textuales, quizás también debería considerar algún marco de indexación como Compass .
No sé si se adapta a su aplicación, pero si es así, puede mejorar el diseño y el rendimiento del código.

En realidad estoy usando Seam. Y la sugerencia de búsqueda de objetos me llevó a encontrar Hibernates consultas de criterios (Consulta por ejemplo) funcionalidad . Eso parece muy parecido a lo que estaba buscando.

Tal vez en una clase base, y con un dash de genéricos ....?

Moin!

Aquí está mi versión para resultados únicos (lo uso en las aplicaciones JPA de mi escritorio con elementos esenciales de TopLink):

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

Y el uso:

import static org.sepix.JPA.*;
...

String id = ...
Customer customer = querySingle (em, Customer.class, 
                      "Customer.findByID", Pair.param ("id", id));

o:

String inquiryID = ...
Boolean current = Boolean.TRUE;
Inquiry inq = querySingle (em, Inquiry.class, 
                      "Inquiry.findCurrent", 
                      Pair.param ("inquiry", inquiryID),
                      Pair.param ("current", current));

saludos cordiales,   josh.

Prefiero usar Spring's JpaDaoSupport, que ayuda a lidiar con JPA. Un buen ejemplo es aquí http: // github .com / rafalrusin / jpaqb / blob / master / src / test / java / jpaqb / CarDao.java .

Una buena separación de la lógica es tener una clase DAO (objeto de acceso a datos) y DTO (objeto de transferencia de datos). Generalmente, DAO contiene todas las consultas requeridas y los DTO son entidades con campos.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top