web-dev-qa-db-ja.com

Spring Data JPA Select Distinct

_select distinct a.address from Person a_(addressはPerson内のAddressエンティティ)のようなクエリを作成する必要がある状況があります。

仕様を使用してwhere句を動的に構築し、findAll(Specification<T>)関数を使用して結果を取得しています。問題は、仕様を使用してselect句を作成できないため、findAll(Spcification)関数を使用できないことです。

このようなことをするための最良の方法は何でしょうか?

11
Nirav Shah

私は同じ問題に遭遇したので、それが誰かを助ける場合に備えて、これは私がしたことです:

仕様はwhere句に変換されており、findAll(Specification<T>)関数は独自のselect句を作成しています。したがって、findAll(Specification<T>)関数を使用してこれを修正する方法はありません。 SimpleJpaRepositoryを拡張するカスタムリポジトリがすでにあるので、新しいメソッドを追加しました。

@Override
    @Transactional(readOnly = true)
    public List<Object> findDistinctValues(Specifications<T> spec, String columnName) {
        return getQuery(spec, columnName).getResultList();
    }

    protected TypedQuery<Object> getQuery(Specification<T> spec, final String distinctColumnName) {

        CriteriaBuilder builder = em.getCriteriaBuilder();
        CriteriaQuery<Object> query = builder.createQuery(Object.class);
        Root<T> root = applySpecificationToCriteria(spec, query);

        if (null != distinctColumnName) {
            query.distinct(true);
            query.multiselect(root.get(distinctColumnName));
        }

        // We order by the distinct column, Asc
        query.orderBy(builder.asc(root.get(distinctColumnName)));

        return em.createQuery(query);
    }

applySpecificationToCriteriaSimpleJpaRepositoryクラスにあります。

これで、findDistinctValuesメソッドを使用できます。

5
yishaiz

グーグルの一番の質問なので、ここに答えを投稿します。

仕様では、クエリにアクセスできるため、次のことができます。

query.distinct(true);

そのようなSQLが発行される完全な例:

2015-04-27 12:03:39 EEST [7766-759] postgres @ salesログ:実行:SELECT DISTINCT t1.ID、t1.NAME、t1.WEBNAME、t1.WEBORDER、t1.PVGROUPPARENT_ID、t1.SITE_ID FROM PRODUCTVARIANT t0、PVGROUP t1 WHERE((t0.PRODUCTTYPE_ID = $ 1)AND(t0.PVGROUP_ID = t1.ID))2015-04-27 12:03:39 EEST [7766-760] postgres @ sales詳細:パラメーター:$ 1 = ' 4608bdc9-d0f2-4230-82fd-b0f776dc2cfd '

public static Specification<PVGroup> byProductType(final ProductType pt) {
        return (final Root<PVGroup> root, final CriteriaQuery<?> query, final CriteriaBuilder builder) -> {

            query.distinct(true);
            final CollectionJoin<PVGroup, ProductVariant> jPV = root.join(PVGroup_.productVariant);

            final Path<ProductType> ptPath = jPV.get(ProductVariant_.productType);

            return builder.equal(ptPath, pt);
        };
    }
}
5
Maxym

良い! distinctJPQLで使用でき、特定の列にも使用できます。すでに ここ です。参照 JPAでDISTINCTを使用

4
Zaw Than oo

迅速で汚い解決策は、Setを使用して結果をフィルタリングすることです。

_Set<...> set = new HashSet<...>( findAll( ... ) )
_

equals()hashCode()がドメインクラスに適切に実装されていることを確認してください:-)

乾杯、

3

これは機能しますか?

List<Person> findDistinctPeopleByAddress(String lastname, String firstname);

続いてリストを反復処理し、Person.getAddress()を使用しますか?

0
Ankit