Pregunta

¿Hay alguna manera de cambiar el tipo de búsqueda JPA en un solo método sin editar el objeto de entidad?

Tengo una capa ORM compartida que consta de clases de entidad JPA. A esta capa ORM se accede por dos capas DAO. Un DAO necesita una recuperación lenta, como lo es para mi aplicación web, el otro necesita una recuperación ansiosa, ya que necesito que sea seguro para subprocesos.

Aquí hay un método de ejemplo de mi DAO seguro para hilos,

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

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

¿Cómo haría que este método (o toda la clase) use la búsqueda ansiosa?

¿Fue útil?

Solución

Supongo que las asociaciones de su entidad (@OneToOne, @OneToMany, @ManyToOne) se consideran perezosas (FetchType.Lazy)

Entonces puedo pensar en dos formas:

A. escriba dos consultas jpa, una que busque la asociación de los perezosos (esa es la forma predeterminada de hibernación) y una segunda consulta que explícitamente fuerce la carga entusiasta de la asociación (vea la palabra clave "buscar" en la 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. use Hibernate.initialize (entidad) para forzar la carga ansiosa de relaciones perezosas de una entidad después de haberla recuperado (por ejemplo, a través del buscador ...)

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

Otros consejos

En JPA, el modo Fetch se especifica en cada atributo de persistencia, ya sea a través de una anotación o en un archivo de mapeo xml.

Entonces, una forma independiente de proveedor de JPA para lograr su objetivo es tener un archivo de mapeo separado para cada capa DAO. Desafortunadamente, esto requerirá una Unidad de persistencia separada para cada archivo de mapeo, pero al menos puede compartir las mismas clases de entidad y la misma consulta JPQL.

Siguen los esqueletos de código.

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>

Entonces es solo cuestión de crear una EntityManagerFactory para la unidad de persistencia apropiada en sus capas DAO.

En realidad, no necesita dos archivos de mapeo, podría especificar LAZY o EAGER como una anotación en la entidad y luego especificar lo contrario en un archivo de mapeo xml (aunque aún querrá dos unidades de persistencia).

Puede ser un poco más de código que la solución de Hibernate anterior, pero su aplicación debe ser portátil para otros proveedores de JPA.

Además, OpenJPA proporciona una funcionalidad similar a la solución Hibernate anterior usando FetchGroups (un concepto tomado de JDO).

Una última advertencia, FetchType.LAZY es una pista en JPA, el proveedor puede cargar las filas con entusiasmo si es necesario.

Actualizado por solicitud.

Considere una entidad como esta:

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

En ese caso, aún necesitaría dos unidades de persistencia, pero solo necesitará orm-lazy.xml. Cambié el nombre del campo para reflejar un escenario más realista (solo las colecciones y los blobs usan FetchType.LAZY de forma predeterminada). Entonces el orm-lazy.xml resultante podría verse así:

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

Y persistence.xml se verá así:

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

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

Como nadie mencionó OpenJPA, pondré una respuesta aquí.

En OpenJPA, las colecciones y campos configurados anteriormente de forma diferida se pueden cargar con entusiasmo como se muestra a continuación

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

Referencia: http: //openjpa.apache.org/builds/1.0.3/apache-openjpa-1.0.3/docs/manual/ref_guide_fetch.html

En JPA2 utilizo EntityGraphs , que le permite definir qué entidades relacionadas desea recuperar:

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

Crea una NamedQuery como lo hizo y adjunta una sugerencia con la clave javax.persistence.loadgraph o javax.persistence.fetchgraph . Recuperará las entidades relacionadas que definió en el gráfico.

Puede encontrar los detalles de la diferencia entre " loadgraph " y "fetchgraph" aquí: ¿Cuál es la diferencia entre FETCH y LOAD para el gráfico de entidad de JPA?

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