2016-09-28 13 views
1

を働いていない削除私は、これらのエンティティを持っている:JPA/Hibernateのカスケードは

@Entity 
public class Item extends Unit 
{ 
    // @Id is in superclass 

    @OneToMany(mappedBy = "parent", cascade = CascadeType.ALL, orphanRemoval = true) 
    private Set<ItemRelation> lowerItemRelations = new LinkedHashSet<>(); 

    @OneToMany(mappedBy = "child", cascade = CascadeType.ALL, orphanRemoval = true) 
    private Set<ItemRelation> higherItemRelations = new LinkedHashSet<>(); 

    // this too is in superclass 
    @OneToMany(mappedBy = "unit", cascade = CascadeType.REMOVE, orphanRemoval = true) 
    @OrderBy("date") 
    protected Set<UnitRegistration> registrations = new LinkedHashSet<>(); 

    ... 
} 

@Entity 
@Table(name = "ITEM_RELATION", 
    indexes = @Index(columnList = "PARENT_ID, CHILD_ID", unique = true)) 
public class ItemRelation extends AbstractEntity 
{ 
    // @Id is in superclass 

    @ManyToOne(optional = false) 
    @JoinColumn(name = "PARENT_ID") 
    private Item parent; 

    @ManyToOne(optional = false) 
    @JoinColumn(name = "CHILD_ID") 
    private Item child; 

    @NotNull 
    @Min(0) 
    @Column(nullable = false, columnDefinition = "INT DEFAULT 1 NOT NULL") 
    private int quantity = 1; 

    ... 
} 

今、私はちょうど簡単なem.remove(item)を実行したいのですが、Hibernateは問題lowerItemRelations/higherItemRelationsための関連DELETE文をしません。

逆に、@OneToMany(mappedBy = "...", cascade = CascadeType.ALL/REMOVE, orphanRemoval=true)で注釈が付けられた他のすべてのフィールドについては、ステートメントが発行されます。ここで

は少しMySQLのログスニペットです:あなたが見ることができるように

2016-09-28T08:47:52.090453Z 13 Query update UNIT set CODE='CE13000003167', ... where ID=132241 and version=1 
2016-09-28T08:47:52.094971Z 13 Query delete from UNIT_ACTION where PARENT_ID=132241 
2016-09-28T08:47:52.134999Z 13 Query update AUTHORIZATION set UNIT_ID=null where UNIT_ID=132241 
2016-09-28T08:47:52.158014Z 13 Query delete from UNIT_DOCUMENT where PARENT_ID=132241 
2016-09-28T08:47:52.248074Z 13 Query delete from UNIT_PRODUCT where UNIT_ID=132241 
2016-09-28T08:47:52.315641Z 13 Query delete from UNIT_PROJECT where UNIT_ID=132241 
2016-09-28T08:47:52.586008Z 13 Query delete from ITEM_ALTERNATIVE where ITEM_ID=132241 
2016-09-28T08:47:52.853350Z 13 Query delete from AUTHORIZATION where ID=714491 
2016-09-28T08:47:52.910835Z 13 Query delete from UNIT_REGISTRATION where ID=173505 
2016-09-28T08:47:52.980887Z 13 Query delete from UNIT where ID=132241 and version=1 
2016-09-28T08:47:53.133290Z 13 Query rollback 

は、ITEM_RELATIONから削除するためのラインがない、と私はのようなものを期待しています:明らかに

0000-00-00T00:00:00.000000Z 13 Query delete from ITEM_RELATION where PARENT_ID=132241 
0000-00-00T00:00:00.000000Z 13 Query delete from ITEM_RELATION where CHILD_ID=132241 

トランザクションを次の理由によりロールバックされます。

com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Cannot delete or update a parent row: a foreign key constraint fails (`edea2`.`item_relation`, CONSTRAINT `FK_ITEM_RELATION_CHILD_ID` FOREIGN KEY (`CHILD_ID`) REFERENCES `unit` (`ID`)) 

もう1つ奇妙なことは、 rnateは、最初の文として(不要な?)UPDATEを実行します。

はしかし、

  • は、(異なるフィールド/列と異なる行であるが)同じエンティティタイプを参照lowerItemRelations/higherItemRelationsという事実に関連し、この異なる振る舞いのですか?

  • これはバグですか、このような動作の理由はありますか?

    私が試した何

  • はコレクション
  • を初期化(orphanRemovalをトリガするために)初期化して、コレクションをクリア
  • em.remove()各収集要素前em.remove(item)

なし成功。私が今まで見

ザ・唯一の作業方法の問題にある:私はWildfly 10.1.0.Finalに

おかげ


を休止5.2.2.Finalを使用してい

CriteriaBuilder builder = em.getCriteriaBuilder(); 
CriteriaDelete<ItemRelation> delete = builder.createCriteriaDelete(ItemRelation.class); 
Root<ItemRelation> rel = delete.from(ItemRelation.class); 
delete.where(builder.or(
    builder.equal(rel.get(ItemRelation_.parent), managedItem), 
    builder.equal(rel.get(ItemRelation_.child), managedItem))); 

em.flush(); 

em.remove(managedItem); 

ここではem.remove()が呼び出されます:

@Stateless 
@Local 
public class PersistenceService implements Serializable 
{  
    @PersistenceContext 
    private EntityManager em; 

    ... 

    @TransactionAttribute(TransactionAttributeType.REQUIRED) 
    public <T> void delete(T entity) 
    { 
     T managed; 

     if(!em.contains(entity)) 
     { 
      Class<T> entityClass = EntityUtils.getClass(entity); 
      Object entityId = EntityUtils.getIdentifier(entity); 

      managed = em.find(entityClass, entityId); 
     } 
     else 
     { 
      managed = entity; 
     } 

     em.remove(managed); 

     // em.flush(); // just for debugging 
    } 
} 
+0

あなたは 'em.remove(項目)は'失敗したコードの切り取らapendでし際

要するに

、これはどうなりますか? – Antoniossss

+0

更新を参照してください。 –

答えて

0

これはバグです。

私はこの現象が両方のコレクションの遅延初期化と結びついているので、問題HHH-11144を提出し、簡単なテストケースを作成しました(GitHubでも利用可能)。

EntityManager em = emf.createEntityManager(); 
EntityTransaction tx = em.getTransaction(); 

tx.begin(); 

Item item = em.createQuery("select x from Item x where x.code = 'first'", Item.class).getSingleResult(); 

Set<ItemRelation> lowerItemRelations = item.getLowerItemRelations(); 
Hibernate.initialize(lowerItemRelations); 

// initializing 'higherItemRelations' prevents orphanRemoval to work on 'lowerItemRelations' 
Set<ItemRelation> higherItemRelations = item.getHigherItemRelations(); 
Hibernate.initialize(higherItemRelations); 

lowerItemRelations.clear(); 

tx.commit(); 
em.close(); 
0

Unitは他のものをrefferencingしていて、あなたのルートには排他的ではありません。この場合、ItemRelationは削除できません。

マッピングではUnitに複数のItemRelationsを設定することができます最初に両側の相互参照を削除することで関係を「破壊」する必要があります(または、少なくともFKを保持するエンティティまたは結合テーブルが使用されている場合はそのいずれか)。

+0

あなたの答えを理解できません...ユニットが他のエンティティ(例えば、UnitRegistrationsのように)を参照していますが、実際には目的は削除することですそれらのすべてを一度に(カスケード接続して)アイテム<-> ItemRelationの間のマッピングはスニペット(@ OneToMany/@ ManyToOne with @JoinColumn)で完全に表現されていますが、@JoinTableはありません。してください、あなたは精巧にできますか? –

+0

私はアクションが上から下にカスケードできることを知っていますが、終わりには終わりですが、カスケードプロセスは下から上に戻って戻り、N個の関連するエンティティから始めます。 IMHO 'cascade'はこれを処理しませんが、間違っている可能性があります。 – Antoniossss

+0

いいえ、あなたは間違っています。関連アイテム*を削除したくないのですが、* managedItem *を削除し、2つのFKをUNITテーブルに保持する* lowerItemRelations *および* higherItemRelations * ItemRelationエンティティを削除したいだけです.ItはItemRelationを参照してください。 parentとItemRelation.childはカスケード属性を宣言していないので、完全なグラフ、ターゲットエンティティ、および即時ItemRelationネイバー(カスケードが宣言されている)を削除するようにhibernateに依頼していません:) –