jpa - Is there a way to eager fetch a lazy relationship through the Predicate API in QueryDSL? -


i using querydslpredicateexecutor spring data jpa project, , facing need eager fetch lazy relation. know can use native jpa-ql query in repository interface, or used jpaqlquery query dsl, intrigued if possible in order facilitate building queries future needs.

i had similar problem had fetch join collection while using predicates , querydslpredicateexecutor.

what did create custom repository implementation add method allowed me define entities should fetched.

don't daunted amount of code in here, it's simple , need few changes use on application

this interface of custom repository

@norepositorybean public interface joinfetchcapablerepository<t, id extends serializable> extends     jparepository<t, id>, querydslpredicateexecutor<t> {      page<t> findall(predicate predicate, pageable pageable, joindescriptor... joindescriptors); } 

joindescriptor

public class joindescriptor {     public final entitypath path;     public final jointype type;      private joindescriptor(entitypath path, jointype type) {         this.path = path;         this.type = type;     }      public static joindescriptor innerjoin(entitypath path) {         return new joindescriptor(path, jointype.innerjoin);     }      public static joindescriptor join(entitypath path) {         return new joindescriptor(path, jointype.join);     }      public static joindescriptor leftjoin(entitypath path) {         return new joindescriptor(path, jointype.leftjoin);     }      public static joindescriptor rightjoin(entitypath path) {         return new joindescriptor(path, jointype.rightjoin);     }      public static joindescriptor fulljoin(entitypath path) {         return new joindescriptor(path, jointype.fulljoin);     } } 

implementation of custom repository

public class joinfetchcapablerepositoryimpl <t, id extends serializable> extends querydsljparepository<t, id> implements joinfetchcapablerepository<t, id> {      private static final entitypathresolver default_entity_path_resolver = simpleentitypathresolver.instance;      private final entitypath<t> path;     private final pathbuilder<t> builder;     private final querydsl querydsl;      public joinfetchcapablerepositoryimpl(jpaentityinformation<t, id> entityinformation, entitymanager entitymanager) {         this(entityinformation, entitymanager, default_entity_path_resolver);     }      public joinfetchcapablerepositoryimpl(jpaentityinformation<t, id> entityinformation, entitymanager entitymanager, entitypathresolver resolver) {         super(entityinformation, entitymanager, resolver);         this.path = resolver.createpath(entityinformation.getjavatype());         this.builder = new pathbuilder<>(path.gettype(), path.getmetadata());         this.querydsl = new querydsl(entitymanager, builder);     }      @override     public page<t> findall(predicate predicate, pageable pageable, joindescriptor... joindescriptors) {         jpqlquery countquery = createquery(predicate);         jpqlquery query = querydsl.applypagination(pageable, createfetchquery(predicate, joindescriptors));          long total = countquery.count();         list<t> content = total > pageable.getoffset() ? query.list(path) : collections.<t> emptylist();          return new pageimpl<>(content, pageable, total);     }      protected jpqlquery createfetchquery(predicate predicate, joindescriptor... joindescriptors) {         jpqlquery query = querydsl.createquery(path);         for(joindescriptor joindescriptor: joindescriptors)             join(joindescriptor, query);         return query.where(predicate);     }      private jpqlquery join(joindescriptor joindescriptor, jpqlquery query) {         switch(joindescriptor.type) {             case default:                 throw new illegalargumentexception("cross join not supported");             case innerjoin:                 query.innerjoin(joindescriptor.path);                 break;             case join:                 query.join(joindescriptor.path);                 break;             case leftjoin:                 query.leftjoin(joindescriptor.path);                 break;             case rightjoin:                 query.rightjoin(joindescriptor.path);                 break;             case fulljoin:                 query.fulljoin(joindescriptor.path);                 break;         }         return query.fetch();     } } 

factory create custom repositories, replacing default querydsljparepository

public class joinfetchcapablequerydsljparepositoryfactorybean<r extends jparepository<t, i>, t, extends serializable>         extends jparepositoryfactorybean<r, t, i> {      protected repositoryfactorysupport createrepositoryfactory(entitymanager entitymanager) {          return new joinfetchcapablequerydsljparepositoryfactory(entitymanager);     }     private static class joinfetchcapablequerydsljparepositoryfactory<t, extends serializable> extends jparepositoryfactory {          private entitymanager entitymanager;          public joinfetchcapablequerydsljparepositoryfactory(entitymanager entitymanager) {             super(entitymanager);             this.entitymanager = entitymanager;         }          protected object gettargetrepository(repositorymetadata metadata) {             return new joinfetchcapablerepositoryimpl<>(getentityinformation(metadata.getdomaintype()), entitymanager);         }          protected class<?> getrepositorybaseclass(repositorymetadata metadata) {             return joinfetchcapablerepository.class;         }     } } 

last step change jpa configuration uses factory instead of default one:

<jpa:repositories base-package="com.mycompany.repository"                       entity-manager-factory-ref="entitymanagerfactory"                       factory-class="com.mycompany.utils.spring.data.joinfetchcapablequerydsljparepositoryfactorybean" /> 

then can use service layer this:

public page<eticket> list(eticketsearch eticket, pageable pageable) {     return eticketrepository.findall(like(eticket), pageable, joindescriptor.leftjoin(qeticket.eticket.order)); } 

by using joindescriptor able specify want join based on service needs.

i able murali's response here: spring data jpa , querydsl fetch subset of columns using bean/constructor projection please take look.


Comments

Popular posts from this blog

java - Jmockit String final length method mocking Issue -

asp.net - Razor Page Hosted on IIS 6 Fails Every Morning -

c++ - wxwidget compiling on windows command prompt -