Fix Native Query projections mapping to DTOs.

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
This commit is contained in:
Mark Paluch
2024-12-03 10:53:35 +01:00
parent 4384fb5633
commit 7998ec79e1
4 changed files with 47 additions and 3 deletions

View File

@@ -93,8 +93,15 @@ final class NativeJpaQuery extends AbstractStringBasedJpaQuery {
return result;
}
return returnedType.isProjecting() && !getMetamodel().isJpaManaged(returnedType.getReturnedType()) //
? Tuple.class
: result;
if (returnedType.isProjecting()) {
if (returnedType.getReturnedType().isInterface()) {
return Tuple.class;
}
return returnedType.getReturnedType();
}
return result;
}
}

View File

@@ -67,6 +67,7 @@ import org.springframework.data.jpa.domain.sample.QUser;
import org.springframework.data.jpa.domain.sample.Role;
import org.springframework.data.jpa.domain.sample.SpecialUser;
import org.springframework.data.jpa.domain.sample.User;
import org.springframework.data.jpa.repository.sample.NameOnlyRecord;
import org.springframework.data.jpa.repository.sample.SampleEvaluationContextExtension.SampleSecurityContextHolder;
import org.springframework.data.jpa.repository.sample.UserRepository;
import org.springframework.data.jpa.repository.sample.UserRepository.NameOnly;
@@ -2979,6 +2980,19 @@ class UserRepositoryTests {
assertThat(result.getLastname()).isEqualTo(user.getLastname());
}
@Test // GH-2757
void supportsRecordsWithNativeQueries() {
flushTestUsers();
User user = repository.findAll().get(0);
NameOnlyRecord result = repository.findRecordProjectionByNativeQuery(user.getId());
assertThat(result.firstname()).isEqualTo(user.getFirstname());
assertThat(result.lastname()).isEqualTo(user.getLastname());
}
@Test // DATAJPA-1248
void supportsProjectionsWithNativeQueriesAndCamelCaseProperty() {

View File

@@ -0,0 +1,20 @@
/*
* Copyright 2018-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.jpa.repository.sample;
public record NameOnlyRecord(String firstname, String lastname) {
}

View File

@@ -561,6 +561,9 @@ public interface UserRepository extends JpaRepository<User, Integer>, JpaSpecifi
@Query(value = "SELECT firstname, lastname FROM SD_User WHERE id = ?1", nativeQuery = true)
NameOnly findByNativeQuery(Integer id);
@NativeQuery("SELECT firstname, lastname FROM SD_User WHERE id = ?1")
NameOnlyRecord findRecordProjectionByNativeQuery(Integer id);
// GH-3155
@NativeQuery(value = "SELECT emailaddress, secondary_email_address FROM SD_User WHERE id = ?1",
sqlResultSetMapping = "emailDto")