spring-projects / spring-data-relational

Spring Data Relational. Home of Spring Data JDBC and Spring Data R2DBC.
https://spring.io/projects/spring-data-jdbc
Apache License 2.0
737 stars 339 forks source link

Class based Projections - projection class doesn't optimizes the query execution #1821

Open alesky78 opened 2 weeks ago

alesky78 commented 2 weeks ago

i have an aggregate that internally has two 1 to M relationship

@Getter
@Setter
@AllArgsConstructor
@Builder
@EqualsAndHashCode(of = {"id"})
@Table("TOOL")
public class AgrTool {

    private @Id Long id;

    private @Version Long version;

    private String status;

    //my flat parameters...
    private LocalDate creationDate;
    private LocalDate acquireDate;
    private String serialNo;
    ................
    ................

     //my two  1-to-M 
    private List<VoDefinitionCalibrationInternal> calibrationInternalDefinitions = new ArrayList<>();

    private List<VoDefinitionCalibrationExternal> calibrationExternalDefinitions = new ArrayList<>();

}

based on our business logic we need to inquery just the TOOL table returing a list of object. Pratically we don't want to fetch the two relationship (calibrationInternalDefinitions and calibrationExternalDefinitions) we need to show a table wiht the miminal set of attribute of the TOOL table

as defined in the documentation we apply the projections expecting, that the query is limited to the field exposed by the consrtuctor of the Projection Class: (official documentation) --> If the store optimizes the query execution by limiting the fields to be loaded, the fields to be loaded are determined from the parameter names of the constructor that is exposed.

then we implemented the minimal value object without the two relationships

@Getter
@Setter
@AllArgsConstructor
@Builder
public class PrjTool{

    private Long id;

    private String status;

    //my flat parameters...
    private LocalDate creationDate;
    private LocalDate acquireDate;
    private String serialNo;
    ................
    ................

}

and in our repository we add two methods:

public interface RepositoryTool extends ListCrudRepository<AgrTool,Long> {

    <T> Page<T> findAllByCustomerAndEnvironment(Long customer, Long environment, Pageable pageable , Class<T> type);

    <T> Collection<T> findAllByCustomerAndEnvironment(Long customer, Long environment, Class<T> type);

analisyng the result of our Unit test where we call this two methods:

        Page<PrjTool> result = null;
        result = repository.findAllByCustomerAndEnvironment(-160L, -160L, pageRequest, PrjTool.class);
        result.forEach(p -> log.info("element:" + p));
        assertThat(result.getNumberOfElements()).isEqualTo(2);

        Collection<PrjTool> result = null;
        result = repository.findAllByCustomerAndEnvironment(-160L, -160L, PrjTool.class);
        result.forEach(p -> log.info("element:" + p));
        assertThat(result.isEmpty()).isEqualTo(false);

activating the trace of the query from the log we see that the query generate continue to do select in the relasionsip also if no define in the projection object,

o.s.jdbc.core.JdbcTemplate               : Executing prepared SQL query
.....
.....
o.s.jdbc.core.JdbcTemplate               : Executing prepared SQL statement [SELECT "TOOL"."ID" AS "ID", "TOOL"."AREA" AS "AREA"... 
.....
.....
o.s.jdbc.core.JdbcTemplate               : Executing prepared SQL statement [SELECT "DEFINITION_CALIBRATION_INTERNAL"."ID" AS... 
.....
......
o.s.jdbc.core.JdbcTemplate               : Executing prepared SQL statement [SELECT "DEFINITION_CALIBRATION_EXTERNAL"."ID" AS... 

Expectation only the table TOOL table should be analyzed if required I can create a test to show the behavior

mp911de commented 2 weeks ago

Related to #1803