2017-03-02 57 views
3

我的要求是檢索所有圖像(WAHImage)對象,無論標本(SpecimenImpl)是否爲空,分類名稱(WACensusImpl)是否爲空,以及排序如果可用的話,標本名稱或分類名稱的結果,以及首先顯示具有空標本和無分類名稱的圖像對象。通過QueryDSL中可爲空的子對象的屬性來排序模型對象

使用下面的代碼,我得到一個錯誤No property coalesce(wAHimage found for type WAHImage

很明顯,我的用例是not (yet) fully supported in QueryDSL,即查詢實體並通過其可空子對象的屬性對結果對象進行排序的功能。這是因爲QueryDSL使用CROSS JOIN而不是LEFT JOIN,並且您無法通過CROSS JOIN按子對象屬性進行排序。這似乎是我沮喪的根源,現在我正在尋找其他解決方案,而不是堅持使用QueryDSL。

春數據倉庫JPA:

public interface ImageRepository extends JpaRepository<WAHImage, Long>, 
     QueryDslPredicateExecutor<WAHImage> { 
    Page<WAHImage> findAllByIsDeleted(boolean isDeleted, Pageable page); 
} 

春季啓動(1.5.1)服務,其中有ImageRepository在其構造函數自動裝配:

@Service 
public class ImageService { 
    private ImageRepository imageRepository; 
    public Page<WAHImage> get(Pageable pageable) { 
     return imageRepository.findAllByIsDeleted(false, ImagePredicates.orderByName(pageable)); 
    } 

ImagePredicates.orderByName(可分頁):

static QPageRequest orderByName(Pageable page) { 

    QWAHImage image = QWAHImage.wAHImage; 
    QWACensusImpl name = image.census; 
    QSpecimenImpl specimen = image.specimen; 
    OrderSpecifier genus = name.name1.coalesce(specimen.genus).asc(); 
    OrderSpecifier species = name.name2.coalesce(specimen.species).asc(); 
    OrderSpecifier rank = name.rank4.coalesce(
      name.rank3.coalesce(specimen.rank)).asc(); 
    OrderSpecifier infraspecies = name.name4.coalesce(
      name.name3.coalesce(specimen.infraspecies)).asc(); 

    OrderSpecifier[] sort = new OrderSpecifier[] { 
      genus, species, rank, infraspecies 
    }; 

    return new QPageRequest(page.getPageNumber(), page.getPageSize(), sort); 
} 

控制器:

@Controller 
public class ImageController { 
    @GetMapping("/list") 
    public String list(Pageable pageable, Model model) { 
     Page<WAHImage> searchResult = imageService.get(pageable); 
    } 
} 

錯誤:

org.springframework.data.mapping.PropertyReferenceException: No property coalesce(wAHImage found for type WAHImage! 
at org.springframework.data.mapping.PropertyPath.<init>(PropertyPath.java:77) 
at org.springframework.data.mapping.PropertyPath.create(PropertyPath.java:329) 
at org.springframework.data.mapping.PropertyPath.create(PropertyPath.java:309) 
at org.springframework.data.mapping.PropertyPath.from(PropertyPath.java:272) 
at org.springframework.data.mapping.PropertyPath.from(PropertyPath.java:243) 
at org.springframework.data.jpa.repository.query.QueryUtils.toJpaOrder(QueryUtils.java:542) 
at org.springframework.data.jpa.repository.query.QueryUtils.toOrders(QueryUtils.java:496) 
at org.springframework.data.jpa.repository.query.JpaQueryCreator.complete(JpaQueryCreator.java:195) 
at org.springframework.data.jpa.repository.query.JpaQueryCreator.complete(JpaQueryCreator.java:143) 
at org.springframework.data.jpa.repository.query.JpaQueryCreator.complete(JpaQueryCreator.java:52) 
at org.springframework.data.repository.query.parser.AbstractQueryCreator.createQuery(AbstractQueryCreator.java:88) 
at org.springframework.data.jpa.repository.query.PartTreeJpaQuery$QueryPreparer.createQuery(PartTreeJpaQuery.java:144) 
at org.springframework.data.jpa.repository.query.PartTreeJpaQuery.doCreateQuery(PartTreeJpaQuery.java:79) 
at org.springframework.data.jpa.repository.query.AbstractJpaQuery.createQuery(AbstractJpaQuery.java:190) 
at org.springframework.data.jpa.repository.query.JpaQueryExecution$PagedExecution.doExecute(JpaQueryExecution.java:184) 
at org.springframework.data.jpa.repository.query.JpaQueryExecution.execute(JpaQueryExecution.java:85) 
at org.springframework.data.jpa.repository.query.AbstractJpaQuery.doExecute(AbstractJpaQuery.java:116) 
at org.springframework.data.jpa.repository.query.AbstractJpaQuery.execute(AbstractJpaQuery.java:106) 
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:483) 
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:461) 
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) 
at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:61) 
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) 
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99) 
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:282) 
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96) 
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) 
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136) 
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) 
at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:133) 
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) 
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92) 
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) 
at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:57) 
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) 
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213) 
at com.sun.proxy.$Proxy143.findAllByIsDeleted(Unknown Source) 
at x.y.z.image.ImageService.get(ImageService.java:120) 
at x.y.z.image.ImageService$$FastClassBySpringCGLIB$$6d3a7999.invoke(<generated>) 
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) 
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:652) 
at x.y.z.image.ImageService$$EnhancerBySpringCGLIB$$21037cfe.get(<generated>) 
at x.y.z.controller.image.ImageController.list(ImageController.java:132) 
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
at java.lang.reflect.Method.invoke(Method.java:498) 
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205) 
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:133) 
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:116) 
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827) 
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738) 
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85) 
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:963) 
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:897) 
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970) 
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861) 

WAHImage模型類的相關部分。

@Entity 
@Table(name = "image") 
public class WAHImage extends PersistentImpl { 
    private WACensusImpl census = new WACensusImpl(); 
    private SpecimenImpl specimen = new SpecimenImpl(); 
    private boolean isDeleted = Boolean.FALSE; 

    @ManyToOne(fetch = FetchType.LAZY) 
    @JoinColumn(name = "census_id", nullable = true) 
    public WACensusImpl getCensus() { 
     return census; 
    } 

    public void setCensus(WACensusImpl census) { 
     this.census = census; 
    } 

    @ManyToOne(fetch = FetchType.LAZY) 
    @JoinColumn(name = "specimen_id", nullable = true) 
    public SpecimenImpl getSpecimen() { 
     return specimen; 
    } 

    public void setSpecimen(SpecimenImpl specimen) { 
     this.specimen = specimen; 
    } 

    @Column(name = "is_deleted") 
    public boolean getIsDeleted() { 
     return isDeleted; 
    } 

    public void setIsDeleted(boolean isDeleted) { 
     this.isDeleted = isDeleted; 
    } 

} 

QWAHImage QueryDSL類的相關部分。

/** 
* QWAHImage is a Querydsl query type for WAHImage 
*/ 
@Generated("com.querydsl.codegen.EntitySerializer") 
public class QWAHImage extends EntityPathBase<WAHImage> { 

    public static final QWAHImage wAHImage = new QWAHImage("wAHImage"); 

    public final x.y.z.db.impl.QPersistentImpl _super = new x.y.z.db.impl.QPersistentImpl(this); 

    public final x.y.z.reference.census.impl.QWACensusImpl census; 

    //inherited 
    public final NumberPath<Long> id = _super.id; 

    public final BooleanPath isDeleted = createBoolean("isDeleted"); 

    public final x.y.z.reference.specimen.impl.QSpecimenImpl specimen; 
} 

QWACensusImpl的相關部分:

/** 
* QWACensusImpl is a Querydsl query type for WACensusImpl 
*/ 
@Generated("com.querydsl.codegen.EntitySerializer") 
public class QWACensusImpl extends EntityPathBase<WACensusImpl> { 

    public static final QWACensusImpl wACensusImpl = new QWACensusImpl("wACensusImpl"); 

    public final x.y.z.db.impl.QPersistentWithIDImpl _super = new x.y.z.db.impl.QPersistentWithIDImpl(this); 

    //inherited 
    public final NumberPath<Long> id = _super.id; 

    public final StringPath name1 = createString("name1"); 

    public final StringPath name2 = createString("name2"); 

    public final StringPath name3 = createString("name3"); 

    public final StringPath name4 = createString("name4"); 

    // extraneous parts omitted. 
} 
+0

請暴露你的'Pageable'模型和'findAllByIsDeleted(...)'方法實現。 –

+0

'Pageable'是一個標準的'org.springframework.data.domain。由Spring提供給我的'ImageController'的Pageable',它通常是一個Spring'PageRequest'實例。 'ImageRepository'是一個[Spring Data JpaRepository](http://docs.spring.io/spring-data/jpa/docs/1.11.1.RELEASE/reference/html/#repositories.core-concepts),它是一個通過設計實現,Spring Data自動生成一個具體的類。 – ben3000

+0

放置完整的實體代碼,也用於QWACensusImpl實體。 –

回答

0

一些廣泛的背景調查後,看來我的使用情況下,有a long history並保持一個common one

爲了解決這個問題,我可以(一)get access to the EntityManagerSpring Data JPA,並從那裏與LEFT JOINs構建查詢,在那之後我應該能夠使用COALESCE關鍵字ImagePredicates.orderByName(Pageable)

另外,(我已經決定要使用的方法),我使用彈簧數據@Query上ImageRepository.findAllByIsDeleted(boolean, Pageable)

public interface ImageRepository extends JpaRepository<WAHImage, Long>, 
     QueryDslPredicateExecutor<WAHImage> { 
    @Query("select i from WAHImage i " + 
      "left join i.specimen s " + 
      "left join i.census c " + 
      "left join i.author a " + 
      "left join i.copyright co " + 
      "left join i.allowedUse au " + 
      "where i.isDeleted = ?1 " + 
      "order by coalesce(s.genus, c.name1) asc, " + 
      "coalesce(s.species, c.name2) asc, " + 
      "coalesce(s.infraspecies, c.name4, c.name3) asc") 
    Page<WAHImage> findAllByIsDeleted(boolean isDeleted, Pageable page); 
}