web-dev-qa-db-ja.com

JPAとHibernateを使用して2つの無関係なエンティティを結合する方法

私は2つのテーブルを持っています-1つは住所を含み、もう1つは写真を含みます。それらの間の唯一の共通フィールドはPersonIDです。これらは、2つのPOJOクラスのアドレスと写真にマップされました。条件を作成し、フィールドに制限を追加することで、これらのテーブルの詳細を取得することができました。 2つのテーブルに結合をどのように記述すればよいですか。住所と写真の2つのオブジェクトとして結果を取得することは可能ですか?.

写真のない人の記録も取れるように、左結合をしたいです。これはhqlを使用してのみ可能であると読みましたが、基準を使用してこれを行うこともできますか?

14
juan

シータ結合を使用して、結果を2つのオブジェクトとして返すHQLクエリを簡単に記述できます(エイドリアンが指摘したように)。次に例を示します。

String queryText = "select address, photo from Address address, Photo photo " 
                 + " where address.personID=photo.personId";
List<Object[]> rows = session.createQuery(queryText).list();

for (Object[] row: rows) {
    System.out.println(" ------- ");
    System.out.println("Address object: " + row[0]);
    System.out.println("Photo object: " + row[1]);
}

ご覧のとおり、クエリはフェッチされた各行を表すObject []配列のリストを返します。この配列の最初の要素には、1つのオブジェクトと2番目の要素(別の要素)が含まれます。

編集:

左結合の場合、ネイティブSQLクエリ(HQLクエリではない)を使用する必要があると思います。これを行う方法は次のとおりです。

String queryText = "select address.*, photo.* from ADDRESS address 
                    left join PHOTO photo on (address.person_id=photo.person_id)";

List<Object[]> rows = sess.createSQLQuery(queryText)
                          .addEntity("address", Address.class)
                          .addEntity("photo", Photo.class)
                          .list();

これはあなたのケースでうまくいくはずです。

16
dimas

この記事 で説明したように、2つのオプションがあります。

  1. Hibernate 5.1以降、無関係のエンティティには アドホック結合 を使用できます。

    Tuple postViewCount = entityManager.createQuery(
        "select p as post, count(pv) as page_views " +
        "from Post p " +
        "left join PageView pv on p.slug = pv.slug " +
        "where p.title = :title " +
        "group by p", Tuple.class)
    .setParameter("title", "High-Performance Java Persistence")
    .getSingleResult();
    
  2. Hibernate 5.1より前は、シータスタイルの結合しか使用できませんでした。ただし、シータスタイルの結合は等結合と同等であるため、エミュレートできるのは内部結合のみであり、外部結合はエミュレートできません。

    List<Tuple> postViewCount = entityManager.createQuery(
        "select p as post, count(pv) as page_views " +
        "from Post p, PageView pv " +
        "where p.title = :title and " +
        "      ( p.slug = pv.slug ) " +
        "group by p", Tuple.class)
    .setParameter("title", "Presentations")
    .getResultList();
    

詳細については、 この記事 をご覧ください。

10
Vlad Mihalcea

最後に12年後、Hibernateチームは そのような機能を実装しました

From Hibernate docs

FROM句には、joinキーワードを使用した明示的な関係結合を含めることもできます。これらの結合は、内側または左外側のスタイルの結合にすることができます。

List<Person> persons = entityManager.createQuery(
    "select distinct pr " +
    "from Person pr " +
    "join pr.phones ph " +
    "where ph.type = :phoneType", Person.class )
.setParameter( "phoneType", PhoneType.MOBILE )
.getResultList();


List<Person> persons = entityManager.createQuery(
    "select distinct pr " +
    "from Person pr " +
    "left join pr.phones ph " +
    "where ph is null " +
    "   or ph.type = :phoneType", Person.class )
.setParameter( "phoneType", PhoneType.LAND_LINE )
.getResultList();

または、WITHおよびONキーワードを使用できます。それらについての意見

重要な違いは、HQL/JPQL条件がWHEREの一部になっているこのセクションの他のクエリとは対照的に、生成されたSQLではWITH/ON句の条件が生成されたSQLのON句の一部になっていることです。生成されたSQLの句。

List<Object[]> personsAndPhones = session.createQuery(
    "select pr.name, ph.number " +
    "from Person pr " +
    "left join pr.phones ph with ph.type = :phoneType " )
.setParameter( "phoneType", PhoneType.LAND_LINE )
.list();

私は現在、新機能を試してみたいと思っています。

Hibernate 5.1では、関連のない2つのエンティティを結合できます。

例:

select objA from ObjectA objA   
JOIN ObjectB objB on objB.variable = objA.variable    
where objA.id = 1
3
rex roy

あなたが探しているのは

  1. HQL
  2. 関係としてモデル化していないフィールドに参加する
  3. 左結合

(質問が最初に行われ、この回答が与えられたとき) Hibernateは、1を実行できるThetaJoinをサポートしています。 &2。ただし、シータ結合スタイルで使用できるのは内部結合のみです。

個人的には、適切な関係をモデル化することをお勧めします。そのため、HQLで十分にサポートされている1と3が必要です。

(別の回答は、実際にそのような機能を提供する新しいHibernate機能の更新を提供しました。これは単に参照することができます)

0
Adrian Shum

参加したいクラスを含むクラスを作成して、それらをすべてまとめることをお勧めします。

ただし、たまにしかこれらのテーブルを結合しない場合は、基準を使用して、各テーブルからデータを手動でロードし、それらをまとめることができます。 (はい、住所と写真に2つの別々のクラスとテーブルがある場合は、これらのテーブルのデータを別々に持つことができます)

0
Matin Kh