0

やや奇妙な問題が発生しています。次の JPA マッピングがあります。

@Entity
public class Location {

  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  @Column(name = "LOCATION_ID")
  private Long id;

  @OneToMany( cascade = { CascadeType.ALL }, fetch = FetchType.EAGER )
  @JoinTable( joinColumns = { @JoinColumn( name = "LOCATION_ID" ) },
  inverseJoinColumns = { @JoinColumn( name = "ATTRIBUTE_ID"  ) } )
  private Set<Attribute> attributes;

と:

@Entity
public class Attribute implements IAttributeSupport {

  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  @Column(name = "ATTRIBUTE_ID")
  private Long id;

  @Column(nullable = false) private String name;
  @Column(nullable = false) private String value;
  ...

そして、私は簡単なテストを行っています:

  • いくつかの属性を持つ場所を永続化する
  • これらの属性のいずれかの名前を変更します
  • Location をマージして戻します (変更された属性を使用)

私の期待 (伝播を考慮して) は、場所をマージすると、更新される属性に単純に伝播されるということです。これは (広く) 発生します。変更された属性の値は実際に更新されますが、マッピングが既に存在する結合テーブルで新しい INSERT が試行されます。この新しく不要な挿入のため、(予想どおり) 失敗は次のとおりです。

Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry '1-1' for key 'PRIMARY'

現在、犯人は方法のようhashCodeでありequals、実装されているようです-属性のセットがHibernateによって永続化されると、コレクションの永続化は各エントリ(各属性)を挿入する必要があるかどうかを確認します:

if ( collection.needsInserting( entry, i, elementType ) )

したがって、属性の 1 つの名前が変更されたため、これは挿入する必要があると見なされます (これは実際には正しくありません - 挿入は必要なく、更新のみが必要です) - したがって、結合テーブルでの挿入操作です。もちろん、equals と hashcode に id を使用することもできますが、それは Hibernate が推奨する方法ではありません。これにつながる可能性のあるマッピングで何かが欠けていますか? これは非常に標準的なマッピングです。単純な 1 対多で単純なマージ操作です。動作させるための提案はありますか?

どんな助けでも大歓迎です。

ありがとう。

オイゲン。

4

1 に答える 1

1

JoinTable最初のポイント: OneToMany では、子エンティティが親への ManyToOne 関係を保持するため、実際には は必要ありません。私はそれを取り出します。

いくつかの注釈が欠落している可能性があります。親クラスで、注釈に追加mappedByして、子クラスのどのメンバーが親への関連付けを保持しているかを示します。@OneToManyあなたの場合、それはおそらく

@OneToMany(fetch = FetchType.EAGER, mappedBy = "location")

さらに、Hibernate が標準の JPA カスケード アノテーションでうまく動作しない場合があります (私はこれと同じ問題を扱っていて、ストレート JPA から Hibernate カスケード アノテーションに移行しました)。完全な補数は次のようになります。

@Cascade(value = { org.hibernate.annotations.CascadeType.ALL, 
        org.hibernate.annotations.CascadeType.DELETE_ORPHAN })
@OneToMany(fetch = FetchType.EAGER, mappedBy = "location")
private Set<Attribute> attributes;

次に、子では、親への参照が必要です。

@ManyToOne
@JoinColumn(name = "location_id")
private Location location;

その後、カスケードは正しく機能するはずです。

于 2012-07-18T13:16:54.153 に答える