如何使用弹簧数据jpa的投影和规格?

Sad*_*ath 11 hibernate jpql spring-data-jpa spring-boot

我无法一起使用Spring Data JPA投影和规范.我有以下设置:

实体:

@Entity
public class Country {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @Column(name = "NAME", nullable = false)
    private String name;

    @Column(name = "CODE", nullable = false)
    private String code;

    ---getters & setters---

}
Run Code Online (Sandbox Code Playgroud)

投影界面:

public interface CountryProjection {
    String getName();
}
Run Code Online (Sandbox Code Playgroud)

国家规格:

public class CountrySpecification {
    public static Specification<Country> predicateName(final String name) {
        return new Specification<Country>() {
            @Override
            public Predicate toPredicate(Root<Country> eventRoot, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                return criteriaBuilder.equal(eventRoot.get(Country_.name), name);
            }
        };
    }
}
Run Code Online (Sandbox Code Playgroud)

库:

public interface CountryRepository extends JpaRepository<Country, Long>, JpaSpecificationExecutor<Country> {
    List<CountryProjection> findByName(String name); // works fine
    List<CountryProjection> findAllProjectedBy(); // works fine
    List<CountryProjection> findAllProjectedBy(Specification<Country> specification); //throws Exception as shown below
}
Run Code Online (Sandbox Code Playgroud)

前两个方法findByName和findAllProjectedBy工作正常.而第三种方法findAllProjectedBy(规范规范)抛出以下异常 -

引起:java.util.NoSuchElementException:java.util.ArrayList中的null $ Itr.next(ArrayList.java:854)〜[na:1.8.0_102] at java.util.Collections $ UnmodifiableCollection $ 1.next(Collections.java :1042)〜[na:1.8.0_102] org.springframework.data.jpa.repository.query.CriteriaQueryParameterBinder.bind(CriteriaQueryParameterBinder.java:63)〜[spring-data-jpa-1.10.6.RELEASE.jar: na] org.springframework.data.jpa.repository.query.ParameterBinder.bind(ParameterBinder.java:100)〜[spring-data-jpa-1.10.6.RELEASE.jar:na] org.springframework.data. org.springframework.data.jpa.repository.query.ParameterBinder.bindAndPrepare中的jpa.repository.query.ParameterBinder.bindAndPrepare(ParameterBinder.java:160)〜[spring-data-jpa-1.10.6.RELEASE.jar:na] (ParameterBinder.java:151)〜[spring-data-jpa-1.10.6.RELEASE.jar:na] at org.springframework.data.jpa.repository.query.PartTreeJpaQuery $ QueryPreparer.invokeBinding(PartTreeJpaQuery.java:218) 〜[spring-data-jpa-1.10.6.RELEASE.jar:na] org.springframework.data.jpa.r epository.query.PartTreeJpaQuery $ QueryPreparer.createQuery(PartTreeJpaQuery.java:142)〜[spring-data-jpa-1.10.6.RELEASE.jar:na] at org.springframework.data.jpa.repository.query.PartTreeJpaQuery.doCreateQuery (PartTreeJpaQuery.java:78)〜[spring-data-jpa-1.10.6.RELEASE.jar:na] at org.springframework.data.jpa.repository.query.AbstractJpaQuery.createQuery(AbstractJpaQuery.java:190)~ [ spring-data-jpa-1.10.6.RELEASE.jar:na] at org.springframework.data.jpa.repository.query.JpaQueryExecution $ CollectionExecution.doExecute(JpaQueryExecution.java:118)~ [spring-data-jpa-1.10 .6.RELEASE.jar:na] at org.springframework.data.jpa.repository.query.JpaQueryExecution.execute(JpaQueryExecution.java:82)〜[spring-data-jpa-1.10.6.RELEASE.jar:na]在org.springframework.data.jpa.repository.query.AbstractJpaQuery.doExecute(AbstractJpaQuery.java:116)〜[spring-data-jpa-1.10.6.RELEASE.jar:na] org.springframework.data.jpa. repository.query.AbstractJpaQuery.execute(AbstractJpaQuery.java:106)〜[spring-data-jpa-1.10.6.R ELEASE.jar:na] at org.springframework.data.repository.core.support.RepositoryFactorySupport $ QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:482)〜[spring-data-commons-1.12.6.RELEASE.jar:na] at org.springframework.data.repository.core.support.RepositoryFactorySupport $ QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:460)〜[spring-data-commons-1.12.6.RELEASE.jar:na] org.springframework.aop.framework .ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)〜[spring-aop-4.3.5.RELEASE.jar:4.3.5.RELEASE] org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:61) 〜[spring-data-commons-1.12.6.RELEASE.jar:na] org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)〜[spring-aop-4.3.5.RELEASE.jar :4.3.5.RELEASE] at org.springframework.transaction.interceptor.TransactionInterceptor $ 1.proceedWithInvocation(Transaction Interceptor.java:99)〜[spring-tx-4.3.5.RELEASE.jar:4.3.5.RELEASE] org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:282)〜[spring-tx -4.3.5.RELEASE.jar:4.3.5.RELEASE] at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)〜[spring-tx-4.3.5.RELEASE.jar:4.3. 5.RELEASE]在org.springframework.dao的org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)〜[spring-aop-4.3.5.RELEASE.jar:4.3.5.RELEASE]. org.springframework.aop.framework.ReflectiveMethodInvocation.proceed中的support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136)〜[spring-tx-4.3.5.RELEASE.jar:4.3.5.RELEASE](ReflectiveMethodInvocation.java:179 )〜[spring-aop-4.3.5.RELEASE.jar:4.3.5.RELEASE] org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor $ CrudMethodMetadataPopulating 在Org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)〜[spring]的MethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:133)〜[spring-data-jpa-1.10.6.RELEASE.jar:na] -aop-4.3.5.RELEASE.jar:4.3.5.RELEASE]在org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)〜[spring-aop-4.3.5.RELEASE.jar: 4.3.5.RELEASE]在org.springframework的org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)〜[spring-aop-4.3.5.RELEASE.jar:4.3.5.RELEASE].在com.sun.proxy上的aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)〜[spring-aop-4.3.5.RELEASE.jar:4.3.5.RELEASE.$ Proxy82.findAllProjectedBy(Unknown Source)〜 [na:na] at com.mmp.data.jpa.DataJpaApplication.run(DataJpaApplication.java:42)[classes /:na] at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:800)[spring- boot-1.4.3.RELEASE.jar:1.4.3.RELEASE]...省略了11个常用帧

怎么能实现这一目标?有任何想法吗?

mpp*_*dev 16

目前尚不支持混合投影和规格的功能.有一个错误跟踪这个.


Nas*_*aso 9

我发现这个https://github.com/pramoth/specification-with-projection,它似乎工作正是你正在寻找的.我把它包含在我自己的项目中,到目前为止没有任何问题.非常感谢Pramoth.

基本上你扩展JpaSpecificationExecutorWithProjection而不是JpaSpecificationExecutor.

public interface DocumentRepository extends JpaRepository< Country,Long>,JpaSpecificationExecutorWithProjection<Country,Long>
Run Code Online (Sandbox Code Playgroud)

并且你得到了带有投影和规范的findall()方法

<R> Page<R> findAll(Specification<T> spec, Class<R> projectionClass, Pageable pageable);
Run Code Online (Sandbox Code Playgroud)

  • 这种解决方案很不幸,因为它会选择数据库中的所有内容,而不仅仅是“映射”到投影中。 (8认同)
  • 该解决方案违背了使用投影的目的。 (2认同)

小智 8

从 Spring Data 3.0 开始,支持混合投影和规范。我们可以使用以下JpaSpecificationExecutor.findBy 方法

Specification<Country> specification = CountrySpecification.predicateName("Austria");
List<CountryProjection> result = countryRepository.findBy(specification, q -> q
        .project("name")                    // query hint (not required)
        .as(CountryProjection .class)       // projection result class
        .all()                              
);
Run Code Online (Sandbox Code Playgroud)

确保检查FetchableFluentQuery类的计数、分页、排序和其他选项

  • 生成SQL仍然查询所有列 (4认同)

Alm*_*zak 5

所以这个问题在 spring data github 中仍然活跃。正如@Naso所说,您可以将另一个依赖项引入您的项目(https://github.com/pramoth/specation-with-projection),或者没有什么可以阻止您创建两个指向同一个表的实体类。例如

@Entity
@Table("country")
public class Country {
  String code;
  String name;

}
@Entity
@Table("country")
public class CountryName {

 String name;
}

public interface CountryRepository extends JpaRepository<CountryName, Long>, JpaSpecificationExecutor<Country> {

    List<CountryName> findAllProjectedBy(Specification<Country> specification); //throws Exception as shown below
}



Run Code Online (Sandbox Code Playgroud)

  • +1指出(经常被遗忘)使用单独的轻量级实体作为投影手段的可能性 (2认同)