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

Support for DTO projections in derived query methods #2363

Closed
odrotbohm opened this issue Nov 24, 2021 · 2 comments
Closed

Support for DTO projections in derived query methods #2363

odrotbohm opened this issue Nov 24, 2021 · 2 comments
Assignees
Labels
in: repository Repositories abstraction type: enhancement A general enhancement

Comments

@odrotbohm
Copy link
Member

Currently, projecting a query result into a DTO requires the query to be defined explicitly so that the constructor expression to assemble the instances can be declared explicitly. The projection execution of derived query methods currently only supports interface-based projections by reading the required input properties into a JPA Tuple.

It would be nice if we could create the query to use a constructor expression without that explicit declaration.

Related tickets:

@odrotbohm odrotbohm self-assigned this Nov 24, 2021
@odrotbohm odrotbohm added in: repository Repositories abstraction type: enhancement A general enhancement labels Nov 24, 2021
@odrotbohm odrotbohm changed the title Support for DTO projections in query methods without @Query Support for DTO projections in derived query methods Nov 24, 2021
@odrotbohm odrotbohm added this to the 2.7 M1 (2022.0.0) milestone Nov 24, 2021
@odrotbohm odrotbohm assigned odrotbohm and schauder and unassigned odrotbohm Nov 24, 2021
schauder pushed a commit that referenced this issue Dec 3, 2021
In case a derived query uses a DTO, we now create a select clause that uses a constructor expression for the DTO type. This wasn't supported before and expexted either an interface-based projection or an explicit query using a constructor expression.

Fixes #2363.
odrotbohm added a commit that referenced this issue Jan 25, 2022
With the commit for GH-2363, we introduced an unguarded call to ReturnedType.getTypeToRead(), which could return null under certain conditions. Unfortunately Spring Data JPA dod not contain a test case that triggered that scenario.

This commit switches to ReturnedType.getReturnedType() which is non-nullable and lets us inspect the calls results for interfaces, which we need to create the JPA query properly.

Fixes GH-2408
odrotbohm added a commit that referenced this issue Jan 25, 2022
With the commit for GH-2363, we introduced an unguarded call to ReturnedType.getTypeToRead(), which could return null under certain conditions. Unfortunately Spring Data JPA dod not contain a test case that triggered that scenario.

This commit switches to ReturnedType.getReturnedType() which is non-nullable and lets us inspect the calls results for interfaces, which we need to create the JPA query properly.

Fixes GH-2408
odrotbohm added a commit that referenced this issue Jan 25, 2022
With the commit for GH-2363, we introduced an unguarded call to ReturnedType.getTypeToRead(), which could return null under certain conditions. Unfortunately Spring Data JPA dod not contain a test case that triggered that scenario.

This commit switches to ReturnedType.getReturnedType() which is non-nullable and lets us inspect the calls results for interfaces, which we need to create the JPA query properly.

Fixes GH-2408
@nidhikaushal
Copy link

nidhikaushal commented May 18, 2023

@odrotbohm
I was trying to use projection with specification, but I am getting the error:
Caused by: org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [com.entity.ParticipationEntity] to type [com.entity.TenantOnly]

projection interface

public interface TenantOnly {
String getTenantId();
}

@DaTa
@entity
@table(name = "participation", schema = "public")
public class ParticipationEntity {

@Id
@Column(name = "id")
private Long id;

@Column(name = "programId")
private String programId;

@Column(name = "tenantId")
private String tenantId;

}

Spring Data repository
public interface ParticipationSpringDataRepository extends JpaRepository<ParticipationEntity, Long>, JpaSpecificationExecutor {
List findAll(Specification specification);
}

public List<String> getParticipatingTenants(List<String> tenantIds,  List<String> programIds, OffsetDateTime processedDate){
    List<TenantOnly> tenantOnlies = participationSpringDataRepository.findAll(
            Specification.where(tenantIdIn(tenantIds))
                    .and(programId(programIds)));

    return tenantOnlies.stream().map(tenantOnly -> tenantOnly.getTenantId()).toList();
}

private Specification<ParticipationEntity> tenantIdIn(List<String> tenantIds){
    return (root,  query, criteriaBuilder) -> {
        if(tenantIds == null || tenantIds.isEmpty()){
            return criteriaBuilder.conjunction();
        }
        return criteriaBuilder.in(root.get(ParticipationEntity_.TENANT_ID)).value(tenantIds);
    };
}

build versions
org.springframework.boot:spring-boot-starter-data-jpa:3.0.5
org.postgresql:postgresql:42.6.0

@nidhikaushal
Copy link

@odrotbohm
I have raised a bug here: #2959

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: repository Repositories abstraction type: enhancement A general enhancement
Projects
None yet
Development

No branches or pull requests

3 participants