2016-06-22 16 views
2

私はhibernate + JPAで遊んでいます。コレクションの結果を制限するためにクエリを実行しようとしています。目的は、クエリを継承レベルに制限し、すべてのテーブルに対して結合しないことです。JPA OneToMany特定のサブクラスに継承制限を持つコレクション

マイコード:今

@Entity 
    public static class Holder { 

     @Id 
     String holderId = UUID.randomUUID().toString(); 

     @OneToMany(cascade=CascadeType.ALL) 
     @JoinColumn(name="subclassID") 
     List<A> elements; 
    } 

    @Entity 
    @Inheritance(strategy=InheritanceType.JOINED) 
    public static class A { 

     @Id 
     String pkey = UUID.randomUUID().toString(); 

     String type = "a"; 

     String subclassID; 
     @Override 
     public String toString() { 
      return "Class A, pkey: " + pkey + " Subclass " + subclassID; 
     } 
    } 

    @Entity 
    public static class B extends A { 

     String test; 

     String type = "b"; 

     @Override 
     public String toString() { 
      return "Class B, pkey: " + pkey + " Subclass " + subclassID + " Test: " + test; 
     } 
    } 

    @Entity 
    public static class C extends A { 
     String ello; 

     String type = "c"; 

     @Override 
     public String toString() { 
      return "Class C, pkey: " + pkey + " Subclass " + subclassID + " ello: " + ello; 
     } 
    } 

、このコードで:

 EntityManager em = createEntityManagerFactory.createEntityManager(); 

     em.getTransaction().begin(); 
     Holder h = new Holder(); 
     h.holderId = "hid"; 
     h.elements = new ArrayList<>(); 
     A e = new A(); 
     e.subclassID = h.holderId; 
     h.elements.add(e); 

     B b = new B(); 
     b.subclassID = h.holderId; 
     b.test = "test"; 
     h.elements.add(b); 

     C c = new C(); 
     c.subclassID = h.holderId; 
     c.ello = "Ello"; 
     h.elements.add(c); 

     em.persist(h); 
     em.getTransaction().commit(); 

     em.getTransaction().begin(); 
     Holder find = em.find(Holder.class, "hid"); 
     em.getTransaction().commit(); 


     find.elements.forEach(x -> System.err.println(x)); 

、それはすべてのサブクラスを印刷し、それらを正しく取得します。だから私はこれを取得:

Class A, pkey: 5074ec45-5917-47aa-9ce7-b904fbb78a54 Subclass hid 
Class B, pkey: a8afc689-1314-4253-8d20-4751526c0d00 Subclass hid Test: test 
Class C, pkey: f57137cc-32fd-473c-8310-0f83c7dad2ed Subclass hid ello: Ello 

これ、私が参加した戦略を持っているので、いくつかの点で非常に多くの可能性があり、すべてのサブクラスのテーブルを結合する必要があります。

現在、ほとんどの場合、どのような種類のサブクラスをクエリしているのか分かります。私はA、またはAとBのみを必要としますが、Cは必要ありません。

これを考慮し、不要なサブクラスに参加しないクエリを作成する方法を理解するのは難しいです。サブクラスには、異なるサブクラスを識別する "type"プロパティがあります(Aを参照)。

あなたはより多くの情報が必要な場合は、私に教えてください、

ありがとう!

はEDIT:タイプ別の

  1. 問合せ:私はアプローチがここで提案してやってみました

    は結果です。

これは機能しません。怠惰なフェッチは、私が選択したフェッチ戦略(怠け者か熱心なもの)にかかわらず、リスト内のすべてのオブジェクトを依然として照会します。コード:

Query xx = em.createQuery("SELECT h FROM TestApp$Holder h LEFT JOIN h.elements e where TYPE(e) = TestApp$B", Holder.class); 

    System.out.println(" -- -- -- -- -"); 
    List<Holder> resultList = xx.getResultList(); 
    resultList.stream().forEach(x -> { 
     x.elements.forEach(x2 -> System.err.println(x2)); 
    }); 

出力:

14:17:44.466 [main] DEBUG org.hibernate.SQL - select testapp_ho0_.holderId as holderId1_0_ from holder testapp_ho0_ left outer join TestApp$A elements1_ on testapp_ho0_.holderId=elements1_.subclassID left outer join TestApp$B elements1_1_ on elements1_.pkey=elements1_1_.pkey left outer join TestApp$C elements1_2_ on elements1_.pkey=elements1_2_.pkey where case when elements1_1_.pkey is not null then 1 when elements1_2_.pkey is not null then 2 when elements1_.pkey is not null then 0 end=1 
Hibernate: select testapp_ho0_.holderId as holderId1_0_ from holder testapp_ho0_ left outer join TestApp$A elements1_ on testapp_ho0_.holderId=elements1_.subclassID left outer join TestApp$B elements1_1_ on elements1_.pkey=elements1_1_.pkey left outer join TestApp$C elements1_2_ on elements1_.pkey=elements1_2_.pkey where case when elements1_1_.pkey is not null then 1 when elements1_2_.pkey is not null then 2 when elements1_.pkey is not null then 0 end=1 
14:17:44.468 [main] DEBUG org.hibernate.loader.Loader - Result set row: 0 
14:17:44.469 [main] DEBUG org.hibernate.loader.Loader - Result row: EntityKey[io.test.TestApp$Holder#hid] 
14:17:44.471 [main] DEBUG o.h.engine.internal.TwoPhaseLoad - Resolving associations for [io.test.TestApp$Holder#hid] 
14:17:44.472 [main] DEBUG o.h.engine.internal.TwoPhaseLoad - Done materializing entity [io.test.TestApp$Holder#hid] 
14:17:44.473 [main] DEBUG o.h.l.c.p.AbstractLoadPlanBasedCollectionInitializer - Loading collection: [io.test.TestApp$Holder.elements#hid] 
14:17:44.473 [main] DEBUG org.hibernate.SQL - select elements0_.subclassID as subclass2_1_0_, elements0_.pkey as pkey1_1_0_, elements0_.pkey as pkey1_1_1_, elements0_.subclassID as subclass2_1_1_, elements0_.type as type3_1_1_, elements0_1_.test as test1_2_1_, elements0_1_.type as type2_2_1_, elements0_2_.ello as ello1_3_1_, elements0_2_.type as type2_3_1_, case when elements0_1_.pkey is not null then 1 when elements0_2_.pkey is not null then 2 when elements0_.pkey is not null then 0 end as clazz_1_ from TestApp$A elements0_ left outer join TestApp$B elements0_1_ on elements0_.pkey=elements0_1_.pkey left outer join TestApp$C elements0_2_ on elements0_.pkey=elements0_2_.pkey where elements0_.subclassID=? 
Hibernate: select elements0_.subclassID as subclass2_1_0_, elements0_.pkey as pkey1_1_0_, elements0_.pkey as pkey1_1_1_, elements0_.subclassID as subclass2_1_1_, elements0_.type as type3_1_1_, elements0_1_.test as test1_2_1_, elements0_1_.type as type2_2_1_, elements0_2_.ello as ello1_3_1_, elements0_2_.type as type2_3_1_, case when elements0_1_.pkey is not null then 1 when elements0_2_.pkey is not null then 2 when elements0_.pkey is not null then 0 end as clazz_1_ from TestApp$A elements0_ left outer join TestApp$B elements0_1_ on elements0_.pkey=elements0_1_.pkey left outer join TestApp$C elements0_2_ on elements0_.pkey=elements0_2_.pkey where elements0_.subclassID=? 
14:17:44.475 [main] DEBUG o.h.l.p.e.p.i.ResultSetProcessorImpl - Preparing collection intializer : [io.test.TestApp$Holder.elements#hid] 
14:17:44.477 [main] DEBUG o.h.l.p.e.p.i.ResultSetProcessorImpl - Starting ResultSet row #0 
14:17:44.478 [main] DEBUG o.h.l.p.e.p.i.CollectionReferenceInitializerImpl - Found row of collection: [io.test.TestApp$Holder.elements#hid] 
14:17:44.479 [main] DEBUG o.h.l.p.e.p.i.ResultSetProcessorImpl - Starting ResultSet row #1 
14:17:44.479 [main] DEBUG o.h.l.p.e.p.i.CollectionReferenceInitializerImpl - Found row of collection: [io.test.TestApp$Holder.elements#hid] 
14:17:44.480 [main] DEBUG o.h.l.p.e.p.i.ResultSetProcessorImpl - Starting ResultSet row #2 
14:17:44.480 [main] DEBUG o.h.l.p.e.p.i.CollectionReferenceInitializerImpl - Found row of collection: [io.test.TestApp$Holder.elements#hid] 
14:17:44.480 [main] DEBUG o.h.engine.internal.TwoPhaseLoad - Resolving associations for [io.test.TestApp$A#c9b6a82a-eed7-48f5-824e-c591537a6be6] 
14:17:44.480 [main] DEBUG o.h.engine.internal.TwoPhaseLoad - Done materializing entity [io.test.TestApp$A#c9b6a82a-eed7-48f5-824e-c591537a6be6] 
14:17:44.480 [main] DEBUG o.h.engine.internal.TwoPhaseLoad - Resolving associations for [io.test.TestApp$B#c73dd9ae-9e4e-483e-96cc-4ab802f5dc59] 
14:17:44.480 [main] DEBUG o.h.engine.internal.TwoPhaseLoad - Done materializing entity [io.test.TestApp$B#c73dd9ae-9e4e-483e-96cc-4ab802f5dc59] 
14:17:44.480 [main] DEBUG o.h.engine.internal.TwoPhaseLoad - Resolving associations for [io.test.TestApp$C#729f2528-18f5-44da-9dca-2b399b66e183] 
14:17:44.480 [main] DEBUG o.h.engine.internal.TwoPhaseLoad - Done materializing entity [io.test.TestApp$C#729f2528-18f5-44da-9dca-2b399b66e183] 
14:17:44.480 [main] DEBUG o.h.e.l.i.CollectionLoadContext - 1 collections were found in result set for role: io.test.TestApp$Holder.elements 
14:17:44.481 [main] DEBUG o.h.e.l.i.CollectionLoadContext - Collection fully initialized: [io.test.TestApp$Holder.elements#hid] 
14:17:44.481 [main] DEBUG o.h.e.l.i.CollectionLoadContext - 1 collections initialized for role: io.test.TestApp$Holder.elements 
14:17:44.481 [main] DEBUG o.h.r.j.i.ResourceRegistryStandardImpl - HHH000387: ResultSet's statement was not registered 
14:17:44.481 [main] DEBUG o.h.l.c.p.AbstractLoadPlanBasedCollectionInitializer - Done loading collection 
Class A, pkey: c9b6a82a-eed7-48f5-824e-c591537a6be6 Subclass hid 
Class B, pkey: c73dd9ae-9e4e-483e-96cc-4ab802f5dc59 Subclass hid Test: test 
Class C, pkey: 729f2528-18f5-44da-9dca-2b399b66e183 Subclass hid ello: Ello 

2. Fetch in query 

仕事はタイプが明確に任意の結果を排除ものの、しかし、それはまだ、すべてのテーブルを結合され、クエリはその時点で自動的にサービスの作品をフェッチ持つために何をされました不要な結合。 これは次のようになります。

Query xx = em.createQuery("SELECT h FROM TestApp$Holder h LEFT JOIN fetch h.elements e where TYPE(e) = TestApp$B", Holder.class); 

     System.out.println(" -- -- -- -- -"); 
     List<Holder> resultList = xx.getResultList(); 
     resultList.stream().forEach(x -> { 
      x.elements.forEach(x2 -> System.err.println(x2)); 
     }); 

出力:

14:20:25.063 [main] DEBUG org.hibernate.SQL - select testapp_ho0_.holderId as holderId1_0_0_, elements1_.pkey as pkey1_1_1_, elements1_.subclassID as subclass2_1_1_, elements1_.type as type3_1_1_, elements1_1_.test as test1_2_1_, elements1_1_.type as type2_2_1_, elements1_2_.ello as ello1_3_1_, elements1_2_.type as type2_3_1_, case when elements1_1_.pkey is not null then 1 when elements1_2_.pkey is not null then 2 when elements1_.pkey is not null then 0 end as clazz_1_, elements1_.subclassID as subclass2_1_0__, elements1_.pkey as pkey1_1_0__ from holder testapp_ho0_ left outer join TestApp$A elements1_ on testapp_ho0_.holderId=elements1_.subclassID left outer join TestApp$B elements1_1_ on elements1_.pkey=elements1_1_.pkey left outer join TestApp$C elements1_2_ on elements1_.pkey=elements1_2_.pkey where case when elements1_1_.pkey is not null then 1 when elements1_2_.pkey is not null then 2 when elements1_.pkey is not null then 0 end=1 
Hibernate: select testapp_ho0_.holderId as holderId1_0_0_, elements1_.pkey as pkey1_1_1_, elements1_.subclassID as subclass2_1_1_, elements1_.type as type3_1_1_, elements1_1_.test as test1_2_1_, elements1_1_.type as type2_2_1_, elements1_2_.ello as ello1_3_1_, elements1_2_.type as type2_3_1_, case when elements1_1_.pkey is not null then 1 when elements1_2_.pkey is not null then 2 when elements1_.pkey is not null then 0 end as clazz_1_, elements1_.subclassID as subclass2_1_0__, elements1_.pkey as pkey1_1_0__ from holder testapp_ho0_ left outer join TestApp$A elements1_ on testapp_ho0_.holderId=elements1_.subclassID left outer join TestApp$B elements1_1_ on elements1_.pkey=elements1_1_.pkey left outer join TestApp$C elements1_2_ on elements1_.pkey=elements1_2_.pkey where case when elements1_1_.pkey is not null then 1 when elements1_2_.pkey is not null then 2 when elements1_.pkey is not null then 0 end=1 
14:20:25.066 [main] DEBUG org.hibernate.loader.Loader - Result set row: 0 
14:20:25.067 [main] DEBUG org.hibernate.loader.Loader - Result row: EntityKey[io.test.TestApp$Holder#hid], EntityKey[io.test.TestApp$A#3c5b7de6-1658-49ab-b90b-eacde31276c3] 
14:20:25.071 [main] DEBUG org.hibernate.loader.Loader - Found row of collection: [io.test.TestApp$Holder.elements#hid] 
14:20:25.077 [main] DEBUG o.h.engine.internal.TwoPhaseLoad - Resolving associations for [io.test.TestApp$Holder#hid] 
14:20:25.077 [main] DEBUG o.h.engine.internal.TwoPhaseLoad - Done materializing entity [io.test.TestApp$Holder#hid] 
14:20:25.077 [main] DEBUG o.h.engine.internal.TwoPhaseLoad - Resolving associations for [io.test.TestApp$B#3c5b7de6-1658-49ab-b90b-eacde31276c3] 
14:20:25.077 [main] DEBUG o.h.engine.internal.TwoPhaseLoad - Done materializing entity [io.test.TestApp$B#3c5b7de6-1658-49ab-b90b-eacde31276c3] 
14:20:25.077 [main] DEBUG o.h.e.l.i.CollectionLoadContext - 1 collections were found in result set for role: io.test.TestApp$Holder.elements 
14:20:25.077 [main] DEBUG o.h.e.l.i.CollectionLoadContext - Collection fully initialized: [io.test.TestApp$Holder.elements#hid] 
14:20:25.078 [main] DEBUG o.h.e.l.i.CollectionLoadContext - 1 collections initialized for role: io.test.TestApp$Holder.elements 
Class B, pkey: 3c5b7de6-1658-49ab-b90b-eacde31276c3 Subclass hid Test: test 

答えて

1
  1. あなたが直接エンティティ階層を選択している場合は、返されるタイプを制限するために、以下を使用することができます。

    SELECT a FROM A a WHERE TYPE(a) = A OR TYPE(a) = B 
    
  2. これは私が推測している場合です。この場合、次のことがうまくいくかもしれない(しかし、私は自分自身をテストしていません):なし関連するelementsがデータベースに存在しない場合は、そうでない場合、Holderのための何かを得ることはありませんので、

    SELECT h FROM Holder h LEFT JOIN h.elements e WHERE TYPE(e) IN (A, B) 
    

私はここLEFt JOINを使用しました。

注:TYPE(e) = Bでは、Bは文字列ではなくエンティティの名前です。

+0

こんにちは - 私は(私はSQLなしでそれを行う方法があるかどうか疑問に思っていた以外は)2番目のだろう。しかし、これはまた、私のためのすべての型を解決します(クエリがコンパイルされている間)。元の投稿のfindメソッドと同じ出力を表示します – pandaadb

+0

クエリから 'TYPE(e)= A'を削除するとどうなりますか?それは 'B'型のインスタンスだけを返すべきですか? – ujulu

+0

こんにちは - 問題は、クエリは、 "フェッチ"キーワードが必要と思われる。それ以外の場合、コレクションは遅延して初期化され、後ですべてを照会します(どこを無視するか)。 fetchを使って "正しいこと"をしていますが、まだすべてのサブクラステーブルに参加しています。私は、Hibernateが、サブクラスを制限すれば、テーブルに参加する必要がないことを知るのに十分にスマートになることを望んでいました。 – pandaadb

関連する問題