query queries name mkyong jparepository example data crudrepository java spring-data spring-data-jpa

java - queries - spring data jpa join query example



Spring Data JPA Proyección de campos seleccionados desde el DB (1)

Estaba probando Spring Data 1.10.4.RELEASE, siguiendo el ejemplo en Spring Data Docs http://docs.spring.io/spring-data/jpa/docs/current/reference/html/#projections

y noté algunos problemas para los cuales tengo 2 preguntas.

Primero supongamos que tengo estas 2 entidades:

@Entity public class Person { @Id @GeneratedValue private Long id; private String firstName, lastName; @OneToOne private Address address; } @Entity public class Address { @Id @GeneratedValue private Long id; private String street, state, country; }

  • Pregunta 1:

Para las siguientes proyecciones:

interface PersonLimited { String getFirstName(); AddressLimited getAddress(); } interface AddressLimited { String getCountry(); }

cuando ejecuto findPersonByFirstNameProjectedForLimitedData

interface PersonRepository extends CrudRepository<Person, Long> { @Query("select p from Person p where p.firstName = ?1") PersonLimited findPersonByFirstNameProjectedForLimitedData(String firstName); }

devuelve exactamente lo que esperaba:

{ firstName: ''Homer'', address: { country: ''USA'' } }

Ahora si miro el SQL generado, esto es lo que tengo:

SELECT person0_.firstName AS col_0_0_, address1_.id AS id1_13_, address1_.street AS street2_13_, address1_.state AS state3_13_, address1_.country AS country4_13_ FROM person person0_ LEFT OUTER JOIN address address1_ ON person0_.addressId = address1_.id WHERE person0_.firstName = ?

La proyección para la entidad "Persona" está seleccionando solo "fistName", que es 100% correcto porque en la interfaz de PersonLimited solo he definido "getFirstName".

Pero para la entidad "Dirección", selecciona todos los campos, lo cual es incorrecto porque en la interfaz AddressLimited solo he definido "getCountry", solo debería seleccionar "país".

La consulta generada debe ser algo como:

SELECT person0_.firstName AS col_0_0_, address1_.country AS country4_13_ FROM person person0_ LEFT OUTER JOIN address address1_ ON person0_.addressId = address1_.id WHERE person0_.firstName = ?

Entonces, la pregunta es, ¿por qué no está seleccionando solo el campo "país" para la "entidad" de Dirección? ¿Por qué necesita seleccionar todos los campos? ¿Es un error en primavera?

  • Pregunta 2:

para la misma proyección que arriba,

cuando ejecuto findAllPersonsProjectedForLimitedData

interface PersonRepository extends CrudRepository<Person, Long> { @Query("select p from Person p") List<PersonLimited> findAllPersonsProjectedForLimitedData(); }

devuelve exactamente lo que esperaba:

[ { firstName: ''Homer'', address: { country: ''USA'' } }, { firstName: ''Maggie'', address: { country: ''USA'' } } ]

Ahora si miro el SQL generado, esto es lo que tengo:

SELECT person0_.id AS id1_18_, person0_.firstName AS firstName2_18_, person0_.lastName AS lastName3_18_, person0_.addressid AS company4_18_ FROM person person0_ SELECT address0_.id AS id1_13_0_, address0_.street AS street2_13_0_, address0_.state AS state3_13_0_, address0_.country AS country4_13_0_ FROM address address0_ WHERE address0_.id = ?

Aquí, la proyección para las entidades Persona y Dirección está seleccionando todos los campos que están mal, solo debe seleccionar "nombre" y "país".

La consulta generada debe ser algo como:

SELECT person0_.firstName AS firstName2_18_ FROM person person0_ SELECT address0_.country AS country4_13_0_ FROM address address0_ WHERE address0_.id = ?

¿Es este el comportamiento normal, no deberíamos seleccionar solo los campos que necesitamos?

Gracias,


Si desea usar la anotación @Query con Spring Data Projections, debe usar un alias de campo y debe asegurarse de que alias los proyectos que coincidan con los campos de proyección. El siguiente código debería funcionar para la pregunta 1:

interface PersonRepository extends CrudRepository<Person, Long> { @Query("select p.firstName as firstname, p.address as address from Person p where p.firstName = ?1") PersonLimited findPersonByFirstNameProjectedForLimitedData(String firstName); }

Otra alternativa que puede usar es definir sus consultas con Expresiones de Propiedad . siempre que sea posible:

interface PersonRepository extends CrudRepository<Person, Long> { List<PersonLimited> findByFirstName(String firstName); }