0

マップされた複合識別子なしで複合 ID を宣言するオブジェクトのセッションで get を実行しようとしています。
使用される Hibernate のバージョンは 3.5.5 です。

コードのフェッチは一般的であり、実際のデータをラップするコンテナー オブジェクトを読み取ります。

ClassMetadata metadata = 
          session.getSessionFactory().getClassMetadata(wrapper.getDomainClass());
Serializable id = metadata.getIdentifier(wrapper, EntityMode.POJO);
return session.get(wrapper.getDomainClass(), id, LockOptions.UPGRADE);

コードは実際のマッピングについて何も知らないため、ID に関するメタデータを参照する必要があります。

マッピングが次のように定義されている場合:

<hibernate-mapping default-access="field">
  <class name="Wrapper"
      entity-name="Data"
      table="DATA">
    <composite-id>
      <key-property name="identifier" column="identifier" />
      <key-property name="version" column="version" />
    </composite-id>

    <component name="domainObject" class="Data">
      <property name="source" column="source" />
    </component>                    
  </class>
</hibernate-mapping>

複合識別子クラスがない場合、id はオブジェクト自体と等しく、ラッパー参照と等しくなります。
データベースからオブジェクトをフェッチする代わりに session.get() を実行すると、id で渡されたのと同じオブジェクトが返されます (等しいオブジェクトではなく、オブジェクトの同じインスタンス)。
Upd:実際、session.get() はin、id オブジェクトが渡したデータベースからオブジェクトをロードし、それを返します。最初は読み込みをスキップすると思っていました。

これまでに見つけた解決策は、マップされた複合識別子を導入し、マッピングを次のように変更することです。

<hibernate-mapping default-access="field">
  <class name="Wrapper"
      entity-name="Data1"
      table="DATA_1">
    <composite-id  class="SurrogateKey" mapped="true">
      <key-property name="identifier" column="identifier" />
      <key-property name="version" column="version" />
    </composite-id>

    <component name="domainObject" class="Data">
      <property name="source" column="source" />
    </component>                    
  </class>
</hibernate-mapping>

SurrogateKey は、必要に応じて 2 つのフィールドと equals/hashcode を持つオブジェクトとして定義されます。
この変更により、metadata.getIdentifier() によって返される id は SurrogateKey のインスタンスであり、session.get() はデータベースからオブジェクトをフェッチします (存在する場合)。

マッピング修正の問題は、基準と HQL のプロパティ名が識別子からid.identifierに変更され、実際には多くの既存のコードが壊れていることです。

私が現在調査していることは次のとおりです。

  1. Id クラスを宣言せずに session.get() を機能させる方法はありますか?
  2. 別の方法として、id を追加せずに、以前と同じようにプロパティを扱うように hibernate に指示することもできます。彼らの前では?
  3. hibernate を v4 にアップグレードしますか (依存プロジェクトと承認プロセスのために簡単ではありません)?
  4. 他に利用可能なオプション/回避策はありますか?

これまでのところ、上記の解決策しかできていませんが、邪魔にならないものを探しており、手がかり、提案、関連ドキュメントへのポインタをいただければ幸いです。

4

2 に答える 2

1

wrapper最初のコード スニペットには何が含まれていますか? それが添付されたエンティティである場合(そうであると思われます)、明らかにsession.get()、同じ識別子を持つ添付されたエンティティを返します。識別子はエンティティ自体であるため、指定された添付されたエンティティを返します。セッション内の特定のエンティティのインスタンスは常に 1 つだけです。

さて、あなたの質問に答えるために:

  1. AFAIK、期待どおりに動作します。
  2. いいえ。
  3. これは質問ですか?
  4. 最善の回避策は、正しいことを行い、複合識別子の使用をやめることです。Hibernate のアドバイスに従って、単一列の自動生成 ID を使用すると、すべてがはるかに簡単になります。
于 2012-07-05T09:49:07.020 に答える
0

この問題は、意味のあるオブジェクトを session.get() メソッドの ID として使用することから発生していました。

session.get() には副作用があり、その引数を変更することが判明しました (これは PojoInstantiator.instantiate() の奥深くで発生します)。ロード時に、id クラスがマッピング クラスと等しいことを hibernate が検出すると、インスタンスの作成がスキップされ、新しいインスタンスをインスタンス化する代わりに、メソッドに渡された id オブジェクトが使用されます。このオブジェクトは、既存のフィールドを上書きするデータベースからハイドレートされます。

解決策は、キーがマップされていないときに metadata.getIdentifier() がオブジェクトを返す場合、オブジェクトのクローンを作成することです。そのクローンはハイドレートされ、get() によって返されます。

于 2012-07-05T11:49:31.460 に答える