継承とポリモーフィックな関連付けの場合に、@ForceDiscriminator
またはそれに相当するものが必要なのはなぜですか? @DiscriminatorOptions(force=true)
それが仕事を成し遂げる唯一の方法のようです。使用しない理由はありますか?
4 に答える
これを何度も繰り返しているので、明確にするのに役立つと思います。まず、JOINED_TABLE
マッピングを使用するときに Hibernate が差別を必要としないことは事実です。ただし、使用する場合は必要ですSINGLE_TABLE
。さらに重要なことに、他の JPA プロバイダーはほとんどの場合、それを必要とします。
JOINED_TABLE
ポリモーフィッククエリを実行するときに Hibernate が実際に行うことclazz
は、継承ツリーに含まれるすべてのテーブルを外部結合した後、具体的なサブクラスに固有のフィールドの存在をチェックするケース スイッチを使用して、オンザフライで名前が付けられた識別子を作成することです。"hibernate.show_sql"
にプロパティを含めると、これがはっきりとわかりますpersistence.xml
。私の見解では、これはおそらくJOINED_TABLE
クエリの完璧なソリューションなので、Hibernate 関係者が自慢するのは正しいことです。
更新と削除を実行する場合、問題は多少異なります。ここで、hibernate は最初にステートメントの where 句に一致するキーについてルートテーブルにクエリを実行pkTable
し、結果から仮想を作成します。次に"DELETE FROM / UPDATE table WHERE pk IN pkTable"
、継承ツリーで具体的なクラスを実行します。IN 演算子により、O(log(N))
スキャンされたテーブル エントリごとにサブクエリが発生しますが、メモリ内にある可能性が高いため、パフォーマンスの観点からはそれほど悪くはありません。
特定の質問に答えるために、Hibernate は単にここで問題を認識しておらず、特定の観点からは正しいと言えます。彼らが実際にそれらを使用していない場合でも@DiscriminatorValue
、識別子の値を挿入することにより、アノテーションを単に尊重することは信じられないほど簡単です。entityManager.persist()
ただし、識別子の列を尊重しないJOINED_TABLE
ことは (Hibernate にとって) ベンダー ロックインの軽度のケースを作成する利点があり、優れたテクノロジを指摘することで防御することさえできます。
@ForceDiscriminator
または@DiscriminatorOptions(force=true)
確かに痛みを少し軽減するのに役立ちますが、最初のエンティティが作成される前にそれらを使用するか、SQL ステートメントを使用して不足している識別子の値を手動で追加する必要があります。あえて Hibernate から離れようとすると、これらの Hibernate 固有の注釈を削除するためにコードを変更する必要があり、移行に対する抵抗が生じます。この場合、Hibernate が気にかけているのは明らかにそれだけです。
私の経験では、ベンダー ロックインはすべてのマーケット リーダーの夢の楽園です。したがって、顧客が反撃して、得られる利益よりも高い価格をベンダーに押し付けない限り、いつでも実行されます。オープンソースの世界が違うと誰が言いましたか?
ps、混乱を避けるために:私はJPAの実装者とはまったく関係がありません。
pps: 私が通常行うことは、移行時まで問題を無視することです。SQL UPDATE ... FROM
次に、 Hibernate が不足している識別子の値を埋めるために使用するのと同じ case-switch-with-outer-joins トリックを使用してステートメントを作成できます。基本的な原理を理解すれば、実際には非常に簡単です。
これは私の意見だと思いますが、私に同意する人もいると思います。私は、Hibernate がディスクリミネータを使用しないようにできるという事実を好みます。場合によっては、弁別子は必要ありません。
たとえばPerson
、名前や生年月日などを含むエンティティがあります。このエンティティは、やなどの他のいくつかのエンティティで使用できEmployee
ますCustomer
。Person
他のエンティティから参照するのではなく、 Employee
orを参照する場合Customer
、Hibernate はいずれかを取得するように指示されるため、識別子は使用されません。
@yannisf ForceDiscriminator は、この問題を解決する唯一のソリューションではありません。
子クラスごとに instanceof テストを実行できます。これは、コード内でクラスをハードコーディングするようなものですが、ディスクリミネーター列にデータが入力されていない場合に問題を解決するためのよりクリーンな方法です。
これにより、コードで jpa と hibernate アノテーションが混在するのを回避することもできます。
yannisf が指摘したように、instanceOf は OO の世界では一種のアンチパターンです。
別の解決策は、エンティティ マッピングを変更することです。エンティティー A がスーパークラス B への参照を持ち、B が型 C1 と C2 の子クラスを持つとします。A が B を指す代わりに、C1 と C2 が A を指す外部キーを持つことができます。アノテーションが混在しないようにエンティティを設計します。
ありがとう