Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/333.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 我应该在这个JPQL查询中包含distinct吗? 背景_Java_Hibernate_Jpa_Jpql - Fatal编程技术网

Java 我应该在这个JPQL查询中包含distinct吗? 背景

Java 我应该在这个JPQL查询中包含distinct吗? 背景,java,hibernate,jpa,jpql,Java,Hibernate,Jpa,Jpql,我在这里和许多流行的博客上看到了关于JPQLJOIN FETCH查询中使用distinct关键字的必要性以及关于PASS\u distinct\u THROUGH查询提示的多个答案和问题 例如,请看这两个问题 还有这些博客帖子 我错过了什么 现在我的问题是,我无法完全理解JPQL查询中何时必须包含distinct关键字。更具体地说,如果它取决于用于执行查询的方法(getResultList或getSingleResult) 下面是一个例子来阐明我的意思 从现在开始,我写的所有东

我在这里和许多流行的博客上看到了关于JPQL
JOIN FETCH
查询中使用
distinct
关键字的必要性以及关于
PASS\u distinct\u THROUGH
查询提示的多个答案和问题

例如,请看这两个问题

还有这些博客帖子

我错过了什么 现在我的问题是,我无法完全理解JPQL查询中何时必须包含
distinct
关键字。更具体地说,如果它取决于用于执行查询的方法(
getResultList
getSingleResult

下面是一个例子来阐明我的意思

从现在开始,我写的所有东西都在UbuntuLinux18.04、Java8、Hibernate5.4.13和内存H2数据库(版本1.4.200)上进行了测试

假设我有一个
部门
实体,它与
部门主管
实体有一个惰性双向一对多关系:

//Department.java
@实体
公共课系{
// ...
私人董事;
@OneToMany(mappedBy=“department”,fetch=FetchType.LAZY)
公共集getDirectors(){
返回董事;
}
// ...
}
//DepartmentDirector.java
@实体
公共课系主任{
// ...
私人部门
@许多酮
@JoinColumn(name=“department\u fk”)
公共部门{
退货部;
}
// ...
}
假设我的数据库当前包含一个部门(
department1
)和两个与其关联的主管

现在,我想通过uuid(主键)及其所有主管检索部门。这可以通过以下
joinfetch
JPQL查询完成:

String query=“从部门左侧加入获取中选择部门”
+“department.directors,其中department.uuid=:uuid”;
由于前面的查询对子集合使用了
join fetch
,因此我希望它在发出时返回两个重复的部门:但是,这仅在使用
getResultList
方法进行查询时发生,而在使用
getSingleResult
方法时不会发生。这在某种程度上是合理的,但我发现
getSingleResult
的Hibernate实现在幕后使用了
getResultList
,因此我希望抛出
ununiqueresultexception

我还简要介绍了JPA2.2规范,但没有提到两种方法在处理重复项方面的区别,并且与此问题相关的每个代码示例都使用
getResultList
方法

结论 在我的示例中,我发现使用
getSingleResult
执行的
JOIN-FETCH
查询不会遇到我在Background一节中链接的参考资料中解释的复制实体问题

如果上述声明正确,则意味着如果使用
getResultList
执行相同的
JOIN-FETCH
查询,则需要
distinct
,但使用
getSingleResult
执行时不需要它

我需要有人向我解释,如果这是预期的或如果我误解了什么


附录 两项查询的结果:

  • 使用
    getResultList
    方法运行查询。我得到了两个重复的部门(这只是为了测试查询的行为,应该使用
    getSingleResult
    ):

    List resultList=entityManager.createQuery(查询,Department.class)
    .setParameter(“uuid”,department1.getUuid())
    .getResultList();
    资产(结果列表)。实际包含(部门1,部门1);//通行证
    
  • 使用
    getSingleResult
    方法运行查询。我希望检索相同的重复部门,从而抛出
    ununiqueresultexception
    。取而代之的是,只检索一个部门,一切正常:

    Department singleResult=entityManager.createQuery(查询,Department.class)
    .setParameter(“uuid”,department1.getUuid())
    .getSingleResult();
    资产(单一结果)。isEqualTo(部门1);//通行证
    
  • 有趣的问题

    首先,让我指出,
    getSingleResult()
    用于由于其性质而总是返回单个结果的查询(意思是:大多数聚合查询,如
    SELECT SUM(e.id)FROM Entity e
    )。您认为基于某个特定于业务领域的规则的查询应该返回一个结果,但实际上并不符合条件

    也就是说,JPA规范规定当查询返回多个结果时,
    getSingleResult()
    应该抛出
    ununiqueresultException

    当调用
    Query.getSingleResult
    TypedQuery.getSingleResult
    时,持久性提供程序将引发
    UnuniqueresultException
    ,并且查询中有多个结果。如果当前事务处于活动状态,此异常不会导致标记为回滚

    但是,看看Hibernate实现:

        @Override
        public R getSingleResult() {
            try {
                final List<R> list = list();
                if ( list.size() == 0 ) {
                    throw new NoResultException( "No entity found for query" );
                }
                return uniqueElement( list );
            }
            catch ( HibernateException e ) {
                if ( getProducer().getFactory().getSessionFactoryOptions().isJpaBootstrap() ) {
                    throw getExceptionConverter().convert( e );
                }
                else {
                    throw e;
                }
            }
        }
    
        public static <R> R uniqueElement(List<R> list) throws NonUniqueResultException {
            int size = list.size();
            if ( size == 0 ) {
                return null;
            }
            R first = list.get( 0 );
            for ( int i = 1; i < size; i++ ) {
                if ( list.get( i ) != first ) {
                    throw new NonUniqueResultException( list.size() );
                }
            }
            return first;
        }
    
    @覆盖
    公共R getSingleResult(){
    试一试{
    最终列表=列表();
    if(list.size()==0){
    抛出新的NoResultException(“未找到用于查询的实体”);
    }
    返回uniquelement(列表);
    }
    捕获(休眠异常e){
    if(getProducer().getFactory().getSessionFactoryOptions().isJpaBootstrap()){
    抛出getExceptionConverter().convert(e);
    }
    否则{
    投掷e;
    }
    }
    }