spring-projects / spring-data-jpa

Simplifies the development of creating a JPA-based data access layer.
https://spring.io/projects/spring-data-jpa/
Apache License 2.0
2.93k stars 1.39k forks source link

Spring Data JPA projection to records using native queries does not work #3394

Open pashazadeh opened 3 months ago

pashazadeh commented 3 months ago

I have used Interface based projection using native queries for long time, but now according to Spring Data JPA reference documentstions record-based projections must work too, but it seems it does not support custom native queries.

As proxied interfaces are not so friendly during debugging, using records would be great, but it seems the conversion does not work with records.

Can this issue be solved?

By the way I am using Spring Data 3.2.3 (latest release till now)

mp911de commented 3 months ago

but it seems it does not support custom native queries.

Care to elaborate? If you would like us to spend some time helping you to diagnose the problem, please spend some time describing it and, ideally, providing a minimal yet complete sample that reproduces the problem. You can share it with us by pushing it to a separate repository on GitHub or by zipping it up and attaching it to this issue.

spring-projects-issues commented 3 months ago

If you would like us to look at this issue, please provide the requested information. If the information is not provided within the next 7 days this issue will be closed.

pashazadeh commented 3 months ago

Well I like to contribute, but not sure how to implement it.

I am thinking of a ConverterFactory<Tuple, Record>, but not sure how to implement it of the Record type has complex components (such as nested Records, nested interfaces, or objects).

For simple cases which Record just contains, primitives, wrappers, and simple types such as String, Date, java.time classes (anything Spring ConversionService can convert), it can be done.

pashazadeh commented 3 months ago

I digged more in Spring Data JPA sources in class org.springframework.data.jpa.repository.query.NamedQuery, method Class<?> getTypeToRead(ReturnedType returnedType) just returns tuple when ReturnType is an interface, and not a record, so now Hibernate returns an Object[] which is not suitable for extracting results columns by name.

Well I am using named queries, as in our project using queries in annotations is prohibited (as queries are usually so long).

pashazadeh commented 3 months ago

A mismatch between using native-named-queries and native-queries within annotation, when I put the query text in annotation, the return type is now a jakarta.persistence.Tuple (it occurs for annotation parameter nativeQuery = true).

But my named query was also native (and I have @Query annotation with nativeQuery=true), but in this case the expecting type from Hibernate is not a jakarta.persistence.Tuple, as em.createNamedQuery(queryName) is called instead of em.createNamedQuery(queryName, typeToRead)

pashazadeh commented 3 months ago

In Hibernate you can unwrap a jakarta.persistence.Query to org.hibernate.Query and then call setTupleTransformer(NativeQueryConstructorTransformer), it converts query result to an object using constructor arguments (which is suitable for Records). But as I have no experience with EclipseLink, don't know how to do that there.

By the way Hibernate's NativeQueryConstructorTransformer does not support proper conversion, a specific implementation of TupleTransformer which uses Spring ConversionService would be much nicer.

ah1508 commented 1 month ago

Answers to this "problem" from Spring team here: https://github.com/spring-projects/spring-data-jpa/issues/2757