14
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@Table(name = "company_policies")
@DiscriminatorColumn(name = "rule_name")
public abstract class AbstractPolicyRule implements Serializable {

  @Transient
  private static final long serialVersionUID = 1L;

  @Id
  @GeneratedValue
  private Long id;
  private String value;

  ...
}

_

@Entity
public class Category implements Serializable {

  @Transient
  private static final long serialVersionUID = 1L;

  @Id
  @GeneratedValue
  private Long id;
  @Column(name = "category_name")
  private String name;

  @OneToMany(fetch = FetchType.EAGER, cascade = { CascadeType.ALL }, orphanRemoval = true)
  @JoinColumn(name = "category_policy_id", referencedColumnName = "id")
  private Set<AbstractPolicyRule> activePolicyRules;

  ...
}

このセットが更新されると、データベース内で既存の activePolicyRules の category_policy_id が null に設定され、新しいものが挿入されます。元ネタは削除していただきたいです。

orphanRemoval = true を追加するとそれができると思いましたが、そうではありません。これについて私が見た他の質問には双方向の関係があるようで、親を null に設定すると解決しますが、これは双方向の関係ではありません。

助言がありますか?

休止状態 3.5.3 の使用

編集:これは、既存の AbstractPolicyRule がデータベースに存在する場合にのみ発生します。リストから削除してから、カテゴリを再度保存します。その外部キー、category_policy_id は、削除される代わりに null に設定されます。

[DEBUG] Collection found: [domain.category.Category.activePolicyRules#1], was: 
[<unreferenced>] (initialized)
[DEBUG] Flushed: 0 insertions, 2 updates, 0 deletions to 2 objects
[DEBUG] Flushed: 1 (re)creations, 0 updates, 1 removals to 1 collections
...
[DEBUG] Deleting collection: [domain.category.Category2.activePolicyRules#1]
[DEBUG] about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
[DEBUG] update company_policies set category_policy_id=null where category_policy_id=?
[DEBUG] done deleting collection

Hibernate のドキュメントでは以前の方法が推奨されていないため、結合テーブルも試しました。

@Entity
public class Category implements Serializable {

  @Transient
  private static final long serialVersionUID = 1L;

  @Id
  @GeneratedValue
  private Long id;
  @Column(name = "category_name")
  private String name;

  @OneToMany(fetch = FetchType.EAGER, cascade = { CascadeType.ALL }, orphanRemoval = true)
  @JoinTable(name = "policy_rule_mapping", 
    joinColumns = @JoinColumn(name = "category_id"), 
    inverseJoinColumns = @JoinColumn(name = "rule_id"))
  private Set<AbstractPolicyRule> activePolicyRules;

  ...
}

これには同じ問題があります。マッピング テーブルの行は削除されますが、AbstractPolicyRule には削除された項目がまだ含まれています。

4

2 に答える 2

9

orphanRemoval=true問題なく一方向の一対多の関連付けで使用しています。

そして実際に、私はあなたのコードと次のシナリオをテストしました(AbstractPolicyRule実装equals/hashCode正しく):

Category category = new Category();
AbstractPolicyRule policyRule1 = new AbstractPolicyRule("foo");

category.addToActivePolicyRules(policyRule1);
em.persist(category);
em.flush();

assertNotNull(category.getId());
assertNotNull(category.getActivePolicyRules());
assertEquals(1, category.getActivePolicyRules().size());

category.removeFromActivePolicyRules(policyRule1);
category.addToActivePolicyRules(new AbstractPolicyRule("bar"));
// category = em.merge(category); // works with or without
em.flush();
assertEquals(1, category.getActivePolicyRules().size());

期待どおりに動作します。生成されたトレースの下:

22:54:30.817 [main] DEBUG org.hibernate.SQL - カテゴリ (id、category_name) 値に挿入 (null、?)
Hibernate: カテゴリ (id、category_name) 値 (null、?) に挿入
22:54:30.824 [main] TRACE org.hibernate.type.StringType - null をパラメーターにバインド: 1
22:54:30.844 [main] DEBUG ohid.IdentifierGeneratorHelper - ネイティブに生成された ID: 1
...
22:54:30.872 [main] DEBUG org.hibernate.SQL - AbstractPolicyRule (id、name) 値に挿入 (null、?)
Hibernate: AbstractPolicyRule (id、name) 値 (null、?) に挿入します
22:54:30.873 [メイン] TRACE org.hibernate.type.StringType - 'foo' をパラメーターにバインド: 1
22:54:30.874 [main] DEBUG ohid.IdentifierGeneratorHelper - ネイティブに生成された ID: 1
...
22:54:30.924 [メイン] DEBUG org.hibernate.SQL - AbstractPolicyRule を更新して、category_policy_id=? を設定します。id=?
Hibernate: AbstractPolicyRule を更新して、category_policy_id=? を設定します。id=?
22:54:30.927 [メイン] TRACE org.hibernate.type.LongType - '1' をパラメーターにバインド: 1
22:54:30.928 [メイン] TRACE org.hibernate.type.LongType - '1' をパラメーターにバインド: 2
22:54:30.929 [main] DEBUG ohpcAbstractCollectionPersister - コレクションの挿入が完了しました: 1 行が挿入されました
22:54:30.929 [メイン] DEBUG org.hibernate.jdbc.AbstractBatcher - 実行バッチ サイズ: 1
...
22:54:30.945 [main] DEBUG org.hibernate.SQL - AbstractPolicyRule (id、name) 値に挿入 (null、?)
Hibernate: AbstractPolicyRule (id、name) 値 (null、?) に挿入します
22:54:30.948 [main] TRACE org.hibernate.type.StringType - 'bar' をパラメーターにバインド: 1
22:54:30.948 [main] DEBUG ohid.IdentifierGeneratorHelper - ネイティブに生成された ID: 2
...
22:54:30.990 [main] DEBUG org.hibernate.SQL - AbstractPolicyRule を更新して、category_policy_id=null を設定します。category_policy_id=? そしてid=?
Hibernate: AbstractPolicyRule を更新して、category_policy_id=null を設定します。category_policy_id=? そしてid=?
22:54:30.991 [メイン] TRACE org.hibernate.type.LongType - '1' をパラメーターにバインド: 1
22:54:30.992 [メイン] TRACE org.hibernate.type.LongType - '1' をパラメーターにバインド: 2
22:54:30.993 [main] DEBUG ohpcAbstractCollectionPersister - コレクション行の削除が完了しました: 1 削除されました
22:54:30.993 [main] DEBUG ohpcAbstractCollectionPersister - コレクションの行を挿入しています: [com.stackoverflow.q3304092.Category.activePolicyRules#1]
22:54:30.994 [メイン] DEBUG org.hibernate.jdbc.AbstractBatcher - 実行バッチ サイズ: 1
...
22:54:30.996 [メイン] DEBUG org.hibernate.SQL - AbstractPolicyRule を更新して、category_policy_id=? を設定します。id=?
Hibernate: AbstractPolicyRule を更新して、category_policy_id=? を設定します。id=?
22:54:30.997 [main] TRACE org.hibernate.type.LongType - '1' をパラメーターにバインド: 1
22:54:30.998 [main] TRACE org.hibernate.type.LongType - '2' をパラメーターにバインド: 2
22:54:31.002 [main] DEBUG ohpcAbstractCollectionPersister - 行の挿入が完了しました: 1 が挿入されました
...
22:54:31.015 [main] DEBUG org.hibernate.SQL - AbstractPolicyRule から削除します。ここで id=?
Hibernate: id=? の AbstractPolicyRule から削除します。
22:54:31.017 [メイン] TRACE org.hibernate.type.LongType - '1' をパラメーターにバインド: 1

最初のポリシー ルールが削除されます。

これがあなたが行っていることの代表ではない場合は、より多くのコードを提供する必要があります。

更新: OPからのコメントに回答しています...

うわー、saveOrUpdate 呼び出しをマージに変更したところ、適切に削除されるようになりました。それがなぜなのか、何か洞察がありますか?

推測ですorphanRemovalが、JPAのことなので、saveOrUpdate適切に対処するのだろうかと思います(実際、EntityManagerJPAについて言及したので、APIを使用していると思いました)。

于 2010-07-21T23:15:11.880 に答える
4

最初に、クラスがhashCode()andequals()メソッドを実装していることを確認して、これらのアイテムがセットから削除されたことを hibernate が正確に認識できるようにします。

次に、hibernate@Cascadeアノテーションを定義して、delete-orphan カスケード タイプを指定し、同じことが起こるかどうかオブザーバーを指定してみてください。希望どおりに動作する場合は、休止状態のバグを報告し、一時的に独自の注釈を使用してください。それ以外の場合 - 質問を詳細で更新します

于 2010-07-21T22:34:20.510 に答える