JPA/Hibernate (3.5.3) のセットアップで問題が発生しました。このエンティティには、子エンティティのリストである「連絡先」インスタンスを持つ「アカウント」クラスがあります。Contact のインスタンスを Account の List<Contact> プロパティに追加/削除できるようにしようとしています。
セットに新しいインスタンスを追加し、saveOrUpdate(account) を呼び出すと、すべてが適切に保持されます。その後、連絡先をリストから削除して再度 saveOrUpdate を呼び出すと、SQL Hibernate によって account_id 列が null に設定され、データベースの制約に違反しているように見えます。
私は何を間違っていますか?
以下のコードは明らかに単純化された要約ですが、別のコードで同じ結果が見られるので、問題をカバーしていると思います。これは本当に単純なことです。
SQL:
CREATE TABLE account ( INT account_id );
CREATE TABLE contact ( INT contact_id, INT account_id REFERENCES account (account_id) );
ジャワ:
@Entity
class Account {
@Id
@Column
public Long id;
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
@JoinColumn(name = "account_id")
public List<Contact> contacts;
}
@Entity
class Contact {
@Id
@Column
public Long id;
@ManyToOne(optional = false)
@JoinColumn(name = "account_id", nullable = false)
public Account account;
}
Account account = new Account();
Contact contact = new Contact();
account.contacts.add(contact);
saveOrUpdate(account);
// some time later, like another servlet request....
account.contacts.remove(contact);
saveOrUpdate(account);
結果:
UPDATE contact SET account_id = null WHERE contact_id = ?
編集#1:
これは実際にはバグである可能性があります http://opensource.atlassian.com/projects/hibernate/browse/HHH-5091
編集#2:
うまくいくように見える解決策がありますが、Hibernate API を使用する必要があります
class Account {
@SuppressWarnings("deprecation")
@OneToMany(cascade = CascadeType.ALL, mappedBy = "account")
@Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
@JoinColumn(name = "account_id", nullable = false)
private Set<Contact> contacts = new HashSet<Contact>();
}
class Contact {
@ManyToOne(optional = false)
@JoinColumn(name = "account_id", nullable = false)
private Account account;
}
Hibernate CascadeType.DELETE_ORPHAN は非推奨であるため、JPA2 バージョンに取って代わられたと想定する必要がありますが、実装には何かが欠けています。