Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Native query projection with records fail with ConverterNotFoundException #2757

Closed
ah1508 opened this issue Jan 9, 2023 · 5 comments
Closed
Assignees
Labels
theme: projections Refinements around DTO and interface projections type: bug A general bug

Comments

@ah1508
Copy link

ah1508 commented Jan 9, 2023

If the @Query is native, the results can only be projected with an interface.

Unlike jpa queries, there is not room for select new MyProjection(... . where MyProjection would be a record

Any chance to see support for record for native queries ?

Something like:

public interface Persons extends JpaRepository<Person, Long> {

    record PersonExcerpt(long id, String firstname, String lastname) {}

    @Query(nativeQuery = true, value = "select id, firstname, lastname from fts_persons(?)")
    List<PersonExcerpt> find(String name);
}

interface based projection are a little bit less expressive and cannot be used in Thymeleaf template engine, which does not like proxies.

Don't you think that

Session session = entityManager.unwrap(Session.class);
var mapper = DataClassRowMapper.newInstance(PersonExcerpt.class /*dynamically guessed*/);

var results = session.doReturningWork(connection -> {
    // get ResultSet from query and parameters, 
    // iterate on ResultSet and use mapper for each row to get the instances of the the record
    // return the list of instances
};

should work ?

@schauder
Copy link
Contributor

schauder commented Jan 17, 2023

This should work if you define the proper @SqlResultMapping. Unfortunately it doesn't as I discovered when I tried to produce an example.

Reproducer can be found here: https://github.com/schauder/issue-jpa-2757-sqlresultmapping

I guess the problem is that we ask for a Tuple but for native queries we should check if a result mapping is available and if so request the proper type directly.

@schauder schauder added the type: bug A general bug label Jan 17, 2023
@schauder schauder removed their assignment Jan 17, 2023
@schauder schauder removed the status: waiting-for-triage An issue we've not yet triaged label Jan 17, 2023
@ah1508
Copy link
Author

ah1508 commented Jan 17, 2023

It would be even better if it could work without @SqlResultMapping, like with spring-data-jdbc ? @SqlResultMapping usage is very verbose.

How about using entityManager.createNativeQuery if @SqlResultMapping exists, entityManager.unwrap(Session.class).doReturningWork otherwise ?

@schauder
Copy link
Contributor

While certainly possible, I'd vote against it in the general case. In Spring Data JPA, JPA does the mapping. If Spring Data starts to create DTOs you'll end up with a mixture of JPA mapping and Spring Data mapping, which is going to cause a lot of trouble.

One variant we could consider I guess, if we could create a @SqlResultMapping programmatically, based the target class.
But I'm not sure if the supported JPA implementations even offer an API for this.
In any case I would consider that a separate issue and leave this one for fixing, what really should already work.

@hpoettker
Copy link

As far as I understand, the mapping of projections (from e.g. native query results) to interface proxies is not a JPA feature but a Spring Data feature. And it's the ConversionService and not JPA that does the mapping here already.

The way I understand the issue is that it would feel more natural in today's Java if I could use records for the results of projections instead of interface proxies. Where the interface definitions are scanned for properties according to bean naming conventions of accessors, I could now consider the RecordComponents as the source of the mapping information.

Are there plans to add something like a RecordProjectionFactory as an alternative to the currently existing ProxyProjectionFactory?

@mp911de mp911de added the theme: projections Refinements around DTO and interface projections label Aug 13, 2024
@mp911de mp911de changed the title Native query projection with record Native query projection with records fail with ConverterNotFoundException Dec 3, 2024
@mp911de
Copy link
Member

mp911de commented Dec 3, 2024

For records, that map cleanly to the given query, it is possible to make these work by providing the target type to EntityManager.createNativeQuery(…) even without SqlResultSetMapping. The mapping is only necessary when the target type uses different property names.

@mp911de mp911de self-assigned this Dec 3, 2024
@mp911de mp911de added this to the 3.4.1 (2024.1.1) milestone Dec 3, 2024
mp911de added a commit that referenced this issue Dec 3, 2024
We now provide the target type to createNativeQuery(…) if we detect that a native query result type is a projection and not an interface.

Closes #2757
mp911de added a commit that referenced this issue Dec 3, 2024
Refine projection documentation.

See #2757
@mp911de mp911de closed this as completed in 7998ec7 Dec 3, 2024
mp911de added a commit that referenced this issue Dec 3, 2024
Refine projection documentation.

See #2757
mp911de added a commit that referenced this issue Dec 10, 2024
Disable records projection test with Hibernate 6.2.

See #2757
mp911de added a commit that referenced this issue Dec 10, 2024
Disable records projection test with Hibernate 6.2.

See #2757
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
theme: projections Refinements around DTO and interface projections type: bug A general bug
Projects
None yet
Development

No branches or pull requests

5 participants