-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Description
Hello,
Summary
Atm, using projection with specifications doesn't change the generated SQL query, the JPA entity is still loaded under the hood.
Could we expect query optimization in the future when using Projections with Specifications ? (limiting the fields to be loaded to those of the projection interface/class ?)
Detailed issue
I just tried SB 3.0 Projection support with Specifications:
@Test
void testProjectionBySpecification() {
repository.save(new Customer("victor"));
List<CustomerProjectionInterfaceBased> result = repository.findBy(
customerHasFirstnameLike("v"),
q -> q.as(CustomerProjectionInterfaceBased.class).all()
);
assertThat(result).hasSize(1);
}
private interface CustomerProjectionInterfaceBased {
String getFirstname();
}
This works nicely, bu when I look at the sql, I see:
select c1_0.id,c1_0.firstname,c1_0.lastname from customer c1_0 where cast(c1_0.firstname as varchar(2147483647)) like ?
I would have expected the SQL to fetch only the properties from the projection, i.e.:
select c1_0.firstname from customer c1_0 where cast(c1_0.firstname as varchar(2147483647)) like ?
Even if I use project(<property>)
:
List<CustomerProjectionInterfaceBased> result = repository.findBy(
customerHasFirstnameLike("v"),
q -> q.as(CustomerProjectionInterfaceBased.class)
.project("firstname")
.all()
);
I still get the same sql.
Looking at the source code, I see in FetchableFluentQueryBySpecification:
The project(property)
method updates the properties
attribute. This attribute is only used to set the fetchgraph
if (!properties.isEmpty()) {
query.setHint(EntityGraphFactory.HINT, EntityGraphFactory.create(entityManager, entityType, properties));
}
The as(Class)
method is used after executing the jpa query to convert the jpa entity to the projection type, hence this one doesn't change the sql query generation behaviour atm.
So, to optimize the generated query, the only way I found atm would be to rely on project(String)
, activate bytecode enhacement and annotate each basic attribute with @Basic(fetch=LAZY)
.
But setting @basic(fetch=LAZY) seems to me to be too much hassle because it impacts all the queries I already have in my application.