2010-07-21 3 views
12
@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; 

    ... 
} 

_이 설정은 기존 activePolicyRules가 자신의 category_policy_id가에 널 (null)로 설정 한 업데이트됩니다고아는 일대 다 관계 (JPA/최대 절전 모드)

@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; 

    ... 
} 

에 심지어 orphanRemoval와 데이터베이스 = 충실 데이터베이스와 새로운 데이터베이스가 삽입됩니다. 나는 원래의 것들을 삭제하고 싶습니다.

나는 orphanRemoval = true를 추가하는 것이 좋다고 생각했으나 그렇지 않았습니다. 필자가 보았던 다른 질문으로는 양방향 관계가 있고 부모를 null로 설정하면 문제가 해결되지만 양방향 관계가 아닙니다.

제안 사항? 기존 AbstractPolicyRule이 데이터베이스에 존재하는 경우 에만 발생, 나는 목록에서 제거 후 다시 분류를 저장합니다

편집 최대 절전 모드 3.5.3을 사용하여

. 외래 키인 category_policy_id가 삭제되는 대신 null로 설정됩니다.

@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; 

    ... 
} 

이 같은 문제를 가지고 : 최대 절전 모드 문서는 이전 방법을 낙담하기 때문에

[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 

또한 조인 테이블을 시도했다. 매핑 테이블의 행은 삭제되지만 AbstractPolicyRule에는 제거 된 항목이 계속 포함됩니다.

+0

테스트 한 시나리오는 실제로 편집과 매우 비슷했습니다. 나는 다른 것을 추가하지 않고 컬렉션에서 기존 요소를 제거하기 위해 테스트를 변경했으며 여전히 삭제됩니다. 내가 상속을 사용하지는 않는다는 것에 유의하십시오 (나는 당신이있을 것이라고 생각합니다). –

답변

9

orphanRemoval=true을 단방향 일대 다 연관으로 아무런 문제없이 사용하고 있습니다. 예상대로

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()); 

그냥 작동합니다

그리고 사실, 난 당신의 코드와 (AbstractPolicyRule 제대로 equals/hashCode 구현) 다음과 같은 시나리오를 테스트했다. 생성 된 추적 아래 :

 
22:54:30.817 [main] DEBUG org.hibernate.SQL - insert into Category (id, category_name) values (null, ?) 
Hibernate: insert into Category (id, category_name) values (null, ?) 
22:54:30.824 [main] TRACE org.hibernate.type.StringType - binding null to parameter: 1 
22:54:30.844 [main] DEBUG o.h.id.IdentifierGeneratorHelper - Natively generated identity: 1 
... 
22:54:30.872 [main] DEBUG org.hibernate.SQL - insert into AbstractPolicyRule (id, name) values (null, ?) 
Hibernate: insert into AbstractPolicyRule (id, name) values (null, ?) 
22:54:30.873 [main] TRACE org.hibernate.type.StringType - binding 'foo' to parameter: 1 
22:54:30.874 [main] DEBUG o.h.id.IdentifierGeneratorHelper - Natively generated identity: 1 
... 
22:54:30.924 [main] DEBUG org.hibernate.SQL - update AbstractPolicyRule set category_policy_id=? where id=? 
Hibernate: update AbstractPolicyRule set category_policy_id=? where id=? 
22:54:30.927 [main] TRACE org.hibernate.type.LongType - binding '1' to parameter: 1 
22:54:30.928 [main] TRACE org.hibernate.type.LongType - binding '1' to parameter: 2 
22:54:30.929 [main] DEBUG o.h.p.c.AbstractCollectionPersister - done inserting collection: 1 rows inserted 
22:54:30.929 [main] DEBUG org.hibernate.jdbc.AbstractBatcher - Executing batch size: 1 
... 
22:54:30.945 [main] DEBUG org.hibernate.SQL - insert into AbstractPolicyRule (id, name) values (null, ?) 
Hibernate: insert into AbstractPolicyRule (id, name) values (null, ?) 
22:54:30.948 [main] TRACE org.hibernate.type.StringType - binding 'bar' to parameter: 1 
22:54:30.948 [main] DEBUG o.h.id.IdentifierGeneratorHelper - Natively generated identity: 2 
... 
22:54:30.990 [main] DEBUG org.hibernate.SQL - update AbstractPolicyRule set category_policy_id=null where category_policy_id=? and id=? 
Hibernate: update AbstractPolicyRule set category_policy_id=null where category_policy_id=? and id=? 
22:54:30.991 [main] TRACE org.hibernate.type.LongType - binding '1' to parameter: 1 
22:54:30.992 [main] TRACE org.hibernate.type.LongType - binding '1' to parameter: 2 
22:54:30.993 [main] DEBUG o.h.p.c.AbstractCollectionPersister - done deleting collection rows: 1 deleted 
22:54:30.993 [main] DEBUG o.h.p.c.AbstractCollectionPersister - Inserting rows of collection: [com.stackoverflow.q3304092.Category.activePolicyRules#1] 
22:54:30.994 [main] DEBUG org.hibernate.jdbc.AbstractBatcher - Executing batch size: 1 
... 
22:54:30.996 [main] DEBUG org.hibernate.SQL - update AbstractPolicyRule set category_policy_id=? where id=? 
Hibernate: update AbstractPolicyRule set category_policy_id=? where id=? 
22:54:30.997 [main] TRACE org.hibernate.type.LongType - binding '1' to parameter: 1 
22:54:30.998 [main] TRACE org.hibernate.type.LongType - binding '2' to parameter: 2 
22:54:31.002 [main] DEBUG o.h.p.c.AbstractCollectionPersister - done inserting rows: 1 inserted 
... 
22:54:31.015 [main] DEBUG org.hibernate.SQL - delete from AbstractPolicyRule where id=? 
Hibernate: delete from AbstractPolicyRule where id=? 
22:54:31.017 [main] TRACE org.hibernate.type.LongType - binding '1' to parameter: 1 

첫 번째 정책 규칙이 삭제됩니다.

이것이 대표하는 것이 아니라면 더 많은 코드를 제공해야합니다.

업데이트

: 영업 이익에서 코멘트 응답 ...

와우 난 그냥 병합 될 saveOrUpdate 호출을 변경하고 지금은 적절하게 제거합니다. 왜 그게 통찰력 있니?

그냥 추측 : orphanRemoval는 JPA 일 이후 saveOrUpdate가 (실제로, 나는 당신이 JPA를 언급 한 이후로는 EntityManager API를 사용하여 줄 알았는데)에 적절하게 대처한다면, 나는 궁금하다.

+0

답장을 보내 주셔서 감사합니다. 희망에 부합하는 추가 정보로 내 게시물을 업데이트했습니다. – Josh

+0

어쩌면 "equals/hash code를 정확히 설정했는지"가 무엇인지 이해하지 못할 수도 있습니다. 지금 equals/hash 코드는 테이블의 유일한 식별자를 사용하고 있습니다 (그러나 id는 사용하지 않습니다). – Josh

+0

@Josh 좋은 구현입니다. (그리고 문제를 재현하려고 시도 할 때 위의 구현을 사용했습니다). –

3

먼저 클래스가 hashCode()equals() 메서드를 구현하는지 확인하십시오. 따라서 최대 절전 모드에서는 이러한 항목이 세트에서 정확하게 제거되었음을 알 수 있습니다.

그런 다음 hibernate @Cascade 주석을 정의하고 거기에 delete-orphan cascade 유형을 지정하고 동일하게 발생하는지 관찰합니다. 원하는대로 작동하는 경우 - 최대 절전 모드에서 버그를보고하고 독점 주석을 일시적으로 사용하십시오. 그렇지 않으면 - 질문을 세부 사항으로 업데이트하십시오.

+0

답장을 보내 주셔서 감사합니다. 내 정보를 더 많이 업데이트했습니다. – Josh