Blazebit / blaze-persistence

Rich Criteria API for JPA providers
https://persistence.blazebit.com
Apache License 2.0
745 stars 91 forks source link

Query annotations for EntityViews in EntityViewRepository does not work #1869

Open mj-p opened 9 months ago

mj-p commented 9 months ago

Hi, I was under the impression the @Query annotation would also work for EntityViews when using EntityViewRepository. When trying the following example while debugging the SQL statements I can see the I expected is executed and only containing the fields defined in my EntityView but then in the same Thread also another SQL is following which seems like default Hibernate Query. Followed by a ClassCastException from Node to NodeView. From the exception it seems there are 2 proxies chained for the forRoot() but I dont know if thats normal.

@Transactional(readOnly = true)
public interface NodeViewRepository extends EntityViewRepository<NodeView, Long> {

    @Query("SELECT n FROM Node n WHERE n.name = 'root'")
    NodeView findRoot();
}
java.lang.ClassCastException: class test.domain.jpa.Node cannot be cast to class test.api.blaze.view.node.NodeView (test.domain.jpa.Node and test.api.blaze.view.node.NodeView are in unnamed module of loader org.springframework.boot.loader.launch.LaunchedClassLoader @f6f4d33)
        at jdk.proxy2/jdk.proxy2.$Proxy310.findRoot(Unknown Source)
        at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
        at java.base/java.lang.reflect.Method.invoke(Method.java:580)
        at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:351)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
        at org.springframework.validation.beanvalidation.MethodValidationInterceptor.invoke(MethodValidationInterceptor.java:174)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
        at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:220)
        at jdk.proxy2/jdk.proxy2.$Proxy311.findRoot(Unknown Source)
        at test.api.blaze.service.NodeViewService.findRoot(NodeViewService.java:54)
        at test.api.blaze.controller.NodeViewController.findRoot(NodeViewController.java:64)

Also I am using @EnableJpaRepositories and @EnableBlazeRepositories together but scanning different packages if that matters.

Environment

version 1.6.11 integration-spring-data-3.1 Hibernate 6.4

beikov commented 9 months ago

Hey, it is not possible to use the @Query annotation along with entity views. You will have to write that query with JPA Criteria e.g.

@Transactional(readOnly = true)
public interface NodeViewRepository extends EntityViewRepository<NodeView, Long> {

    default NodeView findRoot() {
        return findOne( ( root, query, cb ) -> cb.equal( root.get("name"), cb.literal("root") ) );
    }

    NodeView findOne(Specification<Node> spec);
}
mj-p commented 9 months ago

After digging a bit more through the issue it makes sense this wont work. Maybe the idea for our own Query annotation seems a bit overkill but should be doable I think? I'd like to hear your thoughts on what we would need and if that's even something interesting to have.

beikov commented 9 months ago

It would be interesting, but that depends on https://github.com/Blazebit/blaze-persistence/issues/252 which is not so easy to implement. If https://github.com/jakartaee/persistence/issues/29 were already available, I could just reuse the parser of the JPA provider instead, but having to implement a custom parser requires a lot of work and integration with the parsers of the JPA providers is probably even more work.