2017-11-08 4 views
5

クラスおよび@DiscriminatorValueで@DiscriminatorColumnをサブクラスで使用する場合、Hibernateが生成するSQLは、ディスクリミネータ列を含む句のリテラルとしてディスクリミネータ値を使用します。Hibernate discriminatorの値にリテラルの代わりにバインド変数を使用する

例:

select this_.person_id as y0_ from name this_ where this_.part_type='GIV' 

これはあなたまで、それほど悪いわけではない:私はクラス以外には基準とシンプルな基準クエリを作成する場合

@Entity 
@Inheritance(strategy = InheritanceType.SINGLE_TABLE) 
@DiscriminatorColumn(name = "PART_TYPE") 
@Table(name = "NAME") 
public class NamePartEntity implements Comparable<NamePartEntity> { 
    // Stuff 
} 

@Entity 
@DiscriminatorValue(value = "GIV") 
public class GivenNameEntity extends NamePartEntity { 
    // stuff 
} 

が、私はSQLは、のように生成さになるだろういくつかの識別器の値を持ち、テーブルを複数回選択して、以下のようなクエリを得ることができます。

SELECT this_.person_id AS y0_ 
FROM name this_ 
WHERE this_.part_type='FAM' 
AND this_.value_u =:8 
AND this_.tenant_id =:9 
AND this_.person_id IN 
    (SELECT this_.person_id AS y0_ 
    FROM name this_ 
    WHERE this_.part_type='GIV' 
    AND this_.value_u =:10 
    AND this_.tenant_id =:11 
    AND this_.person_id IN 
    (SELECT this_.person_id AS y0_ 
    FROM name this_ 
    WHERE this_.part_type='GIV' 
    AND this_.value_u =:12 
    AND this_.tenant_id =:13 
    AND this_.person_id IN 
     (SELECT this_.person_id AS y0_ 
     FROM name this_ 
     WHERE this_.part_type='PFX' 
     AND this_.value_u =:14 
     AND this_.tenant_id =:15 
    ) 
    ) 
) 

は、リテラル(この場合は 'FAM'、 'GIV'、 'PFX')に基づいて、さまざまなSQL IDと実行計画を持つことができますが、それらは異なる可能性があります。ただし、これらのディスクリミネータ値リテラルの代わりにバインド変数が使用されている場合は、同じSQL IDで同じ実行計画が適用されます。

したがって、Hibernateでリテラルの代わりにバインド変数が使用されるように、discriminatorのcolumn/valueアノテーションを使用することは可能ですか?これを避けるためにエンティティを書き換えることは可能ですが、既存のアノテーションでバインド変数の機能を何らかの方法で取得できるかどうかを確認したいと考えました。

また、ディスクリミネータ値を使用せずに拡張クラスを使用する方法はありますか?それを試して、各拡張クラスに@Entity注釈を付けると、それは、弁別子注釈がない場合でも、識別子タイプの欠落について苦情を言います。

+0

これはすべて生成(動的)SQLですか?そうでなければ、cursor_sharing = FORCEを設定して、すべてのリテラルをシステム・バインドに変換することができます。 – sandman

+0

これがOracleの場合、cursor_sharing = FORCEは機能しますが、一般的には推奨されません。本番環境で実装する前に2回考えてください! – user2612030

+0

@sandmanこれは動的クエリであり、これはOracleであるが、とにかく移動していく予定である。しかし、誰かが役に立つと思うかもしれないので、入力に感謝します。 – AHungerArtist

答えて

1

いいえ、箱から取り出してはいけません。

私の心に来る最も近い回避策は、基本クラスから選択して、明示的にサブクラスによってフィルタリングすることである。

entityManager.createQuery("select gne from NamePartEntity gne where type(gne) = :subclass") 
    .setParameter("subclass", GivenNameEntity.class) 
    .getResultList(); 
0

代わりに、私はまだ使用しなくても、私の拡張クラス を使用することができる方法があります弁別者の値?私はそれを試してみて、各拡張クラスに@Entity 注釈を持っている場合、それは何の弁別注釈

ので、あなたが使用した InheritanceType.SINGLE_TABLE戦略である

が存在しない場合でも、 弁別タイプの欠落について文句を言います。最も頻繁にクエリする内容に応じて、InheritanceType.JOINEDのような他の戦略を常に使用することができます。

他にも、多くのタイプのNamesは、サブタイプではなくリレーションとしてタイプする必要があることを示す指標ですか?

+0

JOINEDはすべて1つのテーブルにあるので機能しません。すべてのエンティティは同じパーツタイプを持ち、異なる値を持ちます。 JOINED戦略は、エンティティ間に異なるフィールドが存在する場合と同じように見えます。 2番目のコメントについては、SQLを生成する責任があるので、Hibernateがそれを制御すると思います。私は現在、エンティティを使用しているので、パーツタイプを指定する必要はありません。もちろん、単にNamePartEntityを設定してパーツタイプを設定することもできますが、私はJavaコードを記述するときに異なるエンティティを使用することをお勧めしました。 – AHungerArtist

+0

はい、それが同じテーブルにある場合、 'JOINED'はあなたを助けません。しかし、その単一の列であれば、大体は 'NamePartEntity'の' type'プロパティにできるプロパティに変換されます。あなたがJavaで異なるクラスを持つことができるとしたら(純粋に望みます)、それぞれのNamePartEntityが他のものとはかなり異なる振る舞いをしていても、エンティティ(状態情報)である必要はありません。 'クラス'(オブジェクト指向の構築物)。ちょうど私が実際にあなたが探している答えを持っていないとして提案: – anchreg

関連する問題