Utilice menos columnas en la consulta SQL a través de las Proyecciones de Hibernate en la entidad con una relación ManyToOne

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

Pregunta

Estoy tratando de construir un SQL más pequeño, para evitar que " seleccione * de A " que se está construyendo de forma predeterminada para los criterios de hibernación.

Si uso campos simples (sin relación), a través de " Transformers " ;, puedo administrar este SQL:

select description, weight from Dog;

Hola, tengo esta Entidad:

@Entity
public class Dog
{
   Long id;
   String description;
   Double weight;
   @ManyToOne(fetch = FetchType.LAZY)
   @JoinColumn(name = "person_id", nullable = false)
   Person owner;
}

@Entity
public class Person
{
   Long id;
   String name;
   Double height;
   Date birthDate;
}

Mi objetivo es tener esto:

select description, weight, owner.name from Dog

Intenté esto con Criterios (y subcriterios):

Criteria dogCriteria = sess.createCriteria(Dog.class);
ProjectionList proList = Projections.projectionList();
proList.add(Projections.property("description"), description);
proList.add(Projections.property("weight"), weigth);
dogCriteria.setProjection(proList);

Criteria personCriteria = dogCriteria.createCriteria("owner");
ProjectionList ownerProList = Projections.projectionList();
ownerProList.add(Projections.property("name"), description);    
dogCriteria.setProjection(ownerProList);  //After this line,  debugger shows that the
                                          //projection on dogCriteria gets overriden
                                          //and the query fails, because "name" is
                                          //not a field of Dog entity.

¿Cómo debo usar las Proyecciones para obtener un SQL más pequeño, menos columnas? Gracias de antemano.

¿Fue útil?

Solución

En primer lugar,

select description, weight, owner.name from Dog

no es válido SQL. Tendría que ser algo así como

select description, weight, Person.name
 from Dog join Person on Dog.person_id = Person.id

en su lugar. En segundo lugar, ¿por qué? Si bien es posible hacer lo que quieras (ver más abajo), es extremadamente detallado hacerlo a través de Criteria API y no obtienes nada que mostrar. Los ahorros en la transferencia de datos para un par de columnas son insignificantes, a menos que dichas columnas sean enormes manchas o esté seleccionando cientos de miles de registros. En cualquier caso, hay mejores formas de tratar este problema.

En cualquier caso, para hacer lo que quiere para los criterios, debe unirse a la tabla vinculada (Persona) a través de un alias y especificar la proyección en los criterios main utilizando dicho alias:

Criteria criteria = session.createCriteria(Dog.class, "dog")
 .createAlias("owner", "own")
 .setProjection( Projections.projectionList()
   .add(Projections.property("dog.description"))
   .add(Projections.property("dog.weight"))
   .add(Projections.property("own.name"))
 );

Hay una descripción y un ejemplo de lo anterior en documentación de Proyecciones de criterios . Tenga en cuenta que, cuando se ejecute, los criterios anteriores devolverían una lista de matrices de objetos. Deberá especificar un ResultTransformer para que los resultados se conviertan en objetos reales.

Otros consejos

No lo probé por mi cuenta, pero creo que también puedes usar otro constructor en tu Entidad (Pojo) y pasar las columnas allí. Consulte https://www.thoughts-on-java.org/hibernate- mejores prácticas / capítulo " 1.2 Pojo " para una instrucción detallada. Aunque, para mí, aún no está claro si esto también funciona para las relaciones ManyToOne. Voy a tener una oportunidad.

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