Pergunta

Existe uma maneira de mudar o JPA tipo de busca em um único método sem editar o objeto de entidade?

Eu tenho uma camada ORM compartilhada consistindo de classes de entidade JPA. Esta camada ORM é acessado por duas camadas de DAO. Um DAO precisa de busca preguiçosa, como é para minha aplicação web, a outras necessidades buscar ansioso, como eu preciso que ele seja threadsafe.

Aqui é um método exemplo de minha threadsafe DAO,

@PersistenceContext(unitName = "PersistenceUnit", type = PersistenceContextType.TRANSACTION)
private EntityManager em;

public ErrorCode findErrorCodeById(short id) {
    return (ErrorCode) em.createNamedQuery("ErrorCode.findById").
            setParameter("id", id).getSingleResult();
}

Como eu faria este método (ou toda classe) use buscar ansioso?

Foi útil?

Solução

Eu assumo que suas associações de entidade (@OneToOne, @OneToMany, @ManyToOne) são fechted preguiçoso (FetchType.Lazy)

Então eu posso pensar de duas maneiras:

A. Escreva dois consulta jpa um que buscar a associação do preguiçoso (que é a maneira padrão para hibernação) e uma segunda consulta que força de carga ansioso explícito de associação (ver "fetch" palavra-chave em consulta).

        Query q = HibernateUtil.getSessionFactory().getCurrentSession()
                .createQuery("select c from Category as c" +
                        " left join fetch c.categorizedItems as ci" +
                        " join fetch ci.item as i");


B. uso Hibernate.initialize (entidade) para forçar o carregamento ansioso das relações preguiçosos de uma entidade depois de ter recolhido-lo (por exemplo, através de localizador ...)

ErrorCode lazyCode = findErrorCodeById(1);
// eager load associations
Hibernate.initialize(lazyCode);

Outras dicas

Em JPA o modo de busca é especificado em cada atributo de persistência, seja através de uma anotação ou em um arquivo de mapeamento XML.

Assim, uma maneira fornecedor JPA agnóstico para realizar seu objetivo é ter arquivo de mapeamento separado para cada camada DAO. Infelizmente, isso vai exigir um PersistenceUnit separado para cada arquivo de mapeamento, mas pelo menos você pode compartilhar as mesmas classes de entidade e a mesma consulta JPQL.

esqueletos Código seguir.

persistence.xml:

<persistence>
    <persistence-unit name="dao-eager">
        <mapping-file>orm-eager.xml</mapping-file>
    </persistence-unit>

    <persistence-unit name="dao-lazy">
        <mapping-file>orm-lazy.xml</mapping-file>
    </persistence-unit>
</persistence>

ORM-eager.xml:

<entity-mappings>
    <entity class="ErrorCode">
        <attributes>
            <basic name="name" fetch="EAGER"/>
        </attributes>
    </entity> 
</entity-mappings>

ORM-lazy.xml:

<entity-mappings>
    <entity class="ErrorCode">
        <attributes>
            <basic name="name" fetch="LAZY"/>
        </attributes>
    </entity> 
</entity-mappings>

Então é só uma questão de criar um EntityManagerFactory para a persistência unidade apropriada em suas camadas DAO.

Na verdade, você não precisa de dois arquivos de mapeamento, você pode especificar preguiçosos ou EAGER como uma anotação na Entidade e especifique o contrário em um arquivo de mapeamento XML (você ainda vai querer dois persistência-unidades embora).

Pode ser um pouco mais código do que a solução Hibernate acima, mas a sua aplicação deve ser portável para outros fornecedores da APP.

Como um aparte, OpenJPA proporciona uma funcionalidade semelhante à solução de hibernação acima utilizando FetchGroups (um conceito emprestado de JDO).

Uma última ressalva, FetchType.LAZY é uma dica em JPA, o provedor pode carregar as linhas ansiosamente, se necessário.

Atualizado por pedido.

Considere uma entidade como esta:

@Entity 
public class ErrorCode { 
    //  . . . 
    @OneToMany(fetch=FetchType.EAGER)  // default fetch is LAZY for Collections
    private Collection myCollection; 
    // . . .
}

Nesse caso, você ainda precisa de duas unidades de persistência, mas você só vai precisar ORM-lazy.xml. Mudei o nome do campo para refletir um cenário mais realista (apenas coleções e blobs usar FetchType.LAZY por padrão). Assim, o ORM-lazy.xml resultante pode ter esta aparência:

<entity-mappings>
    <entity class="ErrorCode">
        <attributes>
            <one-to-many name="myCollection" fetch="LAZY"/>
        </attributes>
    </entity> 
</entity-mappings>

E persistence.xml será parecido com este:

<persistence>
    <persistence-unit name="dao-eager">
       <!--
          . . .
         -->
    </persistence-unit>

    <persistence-unit name="dao-lazy">
        <!--
           . . . 
          -->
        <mapping-file>orm-lazy.xml</mapping-file>
    </persistence-unit>
</persistence>

Uma vez que ninguém mencionou OpenJPA, vou colocar uma resposta aqui.

OpenJPA, os anteriormente preguiçoso configurados colecções e os campos podem ser avidamente carregado como abaixo

    OpenJPAEntityManager kem = OpenJPAPersistence.cast(em);
    kem.getFetchPlan().addField(Order.class, "products");
    TypedQuery<Order> query = kem.createQuery(yourQuery, Order.class);

Referência: http: //openjpa.apache.org/builds/1.0.3/apache-openjpa-1.0.3/docs/manual/ref_guide_fetch.html

Em JPA2 Eu uso EntityGraphs , que lhe permite definir o que entidades relacionadas você deseja recuperar:

https://docs.oracle.com/javaee/7 /tutorial/persistence-entitygraphs002.htm https://docs.oracle.com/javaee/7/tutorial/ persistência-entitygraphs003.htm

Você cria um NamedQuery como você fez, e você anexar uma dica com javax.persistence.loadgraph chave ou javax.persistence.fetchgraph. Ele vai recuperar as entidades relacionadas que você definiu no gráfico.

Você pode encontrar os detalhes de diferença entre "loadgraph" e "fetchgraph" aqui: Qual é o diffenece entre buscar e carga para Entity gráfico da JPA?

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