Pergunta

Em JPA as Entidades são agradáveis ??anotada Plain Old Java Objects. Mas eu não encontrei uma boa maneira de interagir com eles e banco de dados.

Em meu aplicativo atual, o meu projeto básico é sempre ter um ID baseado seqüência como chave primária, então eu geralmente tem que olhar para cima entidades por outras propriedades do que PK.

E para cada Entidade Eu tenho um EJB sem estado de

@Stateless
public class MyEntApiBean implements MyEntApi {


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

com métodos de consulta que todos são alguma variação

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

Assim:

  1. Eu realmente odeio ter esses métodos em um EJB, porque eles parecem pertencer com as próprias entidades, e os EJB interfaces locais irritar o crap fora de mim.

  2. Eu odeio a duplicação que eu tenho em cada método com "tentativa, createQuery, getResultList, captura, log, retorno" (principalmente uma consequência do não fechamento ou "com a declaração" ou algo assim em Java).

Alguém tem uma sugestão para uma melhor maneira de interagir com as entidades e banco de dados que os endereços de um ou ambos dos meus problemas?

Atualmente, estou pensando em fazer alguns métodos de base com genéricos e reflexão para obter alguns métodos de consulta genéricos para reduzir a duplicação (edição 2) (Eu vou colocar um protótipo para revisão posterior).

Obrigado, Anders

Foi útil?

Solução

Tente Seam. A consultar objetos fazer mais do trabalho para você, e eles são facilmente extensível. Ou, você poderia sempre implementar um padrão semelhante.

Em geral, Costura faz um monte de coisas úteis para fazer a ponte entre APP e você ver e camadas de negócios. Você não tem que usar JSF para Seam para ser útil.

Outras dicas

Você está sendo desnecessariamente verbose. Por um lado, getResultList () não lançar uma exceção quando há linhas são retornadas (pelo menos não em Eclipse ou Toplink - Eu não posso imaginar outro provedor de qualquer ser diferente). getSingleResult () faz, getResultList () não. Além disso, você pode usar o padrão do construtor assim:

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

deve ser suficiente para retornar uma lista de resultados, se houver algum ou uma lista vazia se não houver nenhum. Duas coisas a nota:

  1. @SuppressWarnings ( "unchecked") é desnecessário, mas ele se livrar de um aviso de outra forma inevitável quando se molda o resultado Lista não-genérico de getResultList () para uma lista genérica; e

  2. É provavelmente vale a pena substituir a chamada createQuery () com um @NamedQuery em MyEnt (tipicamente). Por um lado, isso vai permitir a validação em tempo de implantação e outras coisas úteis.

Sua razoavelmente concisa e completa.

Se você fazer um monte de pesquisas textuais, talvez você deve considerar também alguma estrutura de indexação como Compass .
Eu não sei se ele se adapte a sua aplicação, mas se assim ele pode tanto melhorar o design do código e desempenho.

Na verdade, estou usando Seam. E a sugestão objeto de consulta me conduz para encontrar hiberna Critérios consultas (consulta por exemplo) funcionalidade . Isso parece muito próximo ao que eu estava procurando.

Talvez em uma classe base, e com uma pitada de genéricos ....?

Moin!

Aqui é a minha versão para resultados individuais (I usá-lo em minhas aplicações JPA de desktop com 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;
    }
  }
}

E o uso:

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

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

ou

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

Com os melhores cumprimentos, josh.

Eu prefiro usar JpaDaoSupport da Primavera, o que ajuda a lidar com JPA. Um bom exemplo é aqui http: // github .com / rafalrusin / jpaqb / blob / master / src / test / java / jpaqb / CarDao.java .

Uma boa separação da lógica é ter uma classe DAO (Data Access Object) e DTO (Transferência Data Object). DAO normalmente contém todas as consultas e DTOs necessários são entidades com campos.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top