JPQLのdistinct

気になったのでちょっと調査。

部署(Department)と従業員(Employee)のエンティティが多対1のときで考えてみます。
JPQLでdistinctつけてDepartmentからEmployeeをfetch joinします。

JPQL
List<Department> list = entityManager
        .createQuery(
                "select distinct d from Department d left outer join fetch d.employees")
        .getResultList();

すると、こんなSQLに変換されます。

SQL
  select
        distinct department0_.deptno as deptno0_0_,
        employees1_.empno as empno1_1_,
        department0_.dname as dname0_0_,
        department0_.loc as loc0_0_,
        department0_.versionNo as versionNo0_0_,
        department0_.active as active0_0_,
        employees1_.ename as ename1_1_,
        employees1_.job as job1_1_,
        employees1_.mgr as mgr1_1_,
        employees1_.hiredate as hiredate1_1_,
        employees1_.sal as sal1_1_,
        employees1_.comm as comm1_1_,
        employees1_.tstamp as tstamp1_1_,
        employees1_.deptno as deptno1_1_,
        employees1_.city as city1_1_,
        employees1_.zip as zip1_1_,
        employees1_.deptno as deptno0__,
        employees1_.empno as empno0__ 
    from
        Dept department0_ 
    left outer join
        Emp employees1_ 
            on department0_.deptno=employees1_.deptno

SQLにもdistinctがつくので、ResultSet上からの重複はなくなるわけですが、Departmentだけを見ると何度も同じものが登場します。
イメージとしてはこんな感じ。

deptno empno
1 1
2 2
1 3
2 4
3 5

なのでこのままResultSetをDepartmentエンティティに変換すると重複するエンティティが存在することになっちゃいます。

Hibernateはどうしているかというと、distinctがついているときはちゃんとJavaのロジックで重複を取り除いていますね。
(QueryTranslatorImplのlistメソッド)