2013-02-11 57 views
2

我用hibernate的spring-data JPA。我很難讓我的繼承和關係映射正常工作。休眠:繼承和關係映射+泛型

@Entity 
@Inheritance(strategy = InheritanceType.SINGLE_TABLE) 
@Table(name="compound") 
@DiscriminatorColumn(name="compound_type") 
@DiscriminatorOptions(force=true) 
public abstract class Compound<T extends Containable> { 

    @OneToMany(fetch = FetchType.EAGER, mappedBy = "pk.compound", 
     cascade = CascadeType.ALL, orphanRemoval = true) 
    @LazyCollection(LazyCollectionOption.FALSE)  
    private List<CompoundComposition> compositions = new ArrayList<>(); 

    @OneToMany(fetch = FetchType.EAGER, mappedBy="compound", 
     targetEntity=Containable.class, cascade = CascadeType.ALL) 
    @LazyCollection(LazyCollectionOption.FALSE)  
    private Set<T> containables = new HashSet<T>(); 

} 

@Entity 
@Inheritance(strategy = InheritanceType.SINGLE_TABLE) 
@Table(name="containable") 
@DiscriminatorColumn(name="containable_type") 
@DiscriminatorOptions(force=true) 
public abstract class Containable<T extends Compound> {  

    @ManyToOne(optional=true, fetch = FetchType.EAGER, cascade = CascadeType.ALL) 
    private T compound; 
} 

想法是AbstractCompound的某個實現只能與Containable的一個特定實現關聯(反之亦然)。這導致以下implementaions:

@Entity 
@DiscriminatorValue("TestCompound") 
public class TestCompound extends AbstractCompound<TestContainable> { 
} 

@Entity 
@DiscriminatorValue("RegistrationCompound") 
public class RegistrationCompound extends AbstractCompound<Batch> { 

    @Column(name = "reg_number", unique = true) 
    private String regNumber; 
} 

@Entity 
@DiscriminatorValue("TestContainable") 
public class TestContainable extends Containable<TestCompound> { 
} 

@Entity 
@DiscriminatorValue("Batch")  
public class Batch extends Containable<RegistrationCompound>{ 

    @Column(name = "batch_number") 
    private Integer batchNumber; 
} 

我所有的繼承戰略和複合的層次結構的單臺周圍打是唯一一個至少部分地工作。如果JOINED或表_per_class hibernate創建不一致和錯誤!外鍵,即從test_containable到registration_compound(但不是從批處理到test_compound,這裏它正確映射到registration_compound)。

在可接受的一面,它似乎並不關心我使用什麼策略。

現在到我的測試中的實際問題。具體的測試類。有3個測試。所有對「TestCompound」實例進行特定搜索。事情是這三個測試用例中的第一個執行總是通過,另外兩個總是失敗。運行的順序似乎是隨機的(JUnit + @RunWith(SpringJUnit4ClassRunner.class))。這意味着任何測試通過,如果它是第一個運行。

失敗拋出測試以下異常:下列正確的選擇用於提取的Containables

Hibernate: select containabl0_.compound_id as compound8_1_1_, containabl0_.id as id0_1_, 
containabl0_.id as id0_0_, containabl0_.created as created0_0_, 
containabl0_.created_by as created4_0_0_, containabl0_.last_modified as last5_0_0_, 
containabl0_.last_modified_by as last6_0_0_, containabl0_.compound_id as compound8_0_0_, 
containabl0_.batch_number as batch7_0_0_, containabl0_.containable_type as containa1_0_0_ 
from containable containabl0_ where containabl0_.containable_type in ('Batch', 'TestContainable') 
and containabl0_.compound_id=? 

List<CompoundComposition> compositions

org.hibernate.WrongClassException: Object with id: 1000 was not of the specified 
    subclass: RegistrationCompound (loaded object was of wrong class class TestCompound) 

在第一次測試的情況下,休眠問題,另一個選擇是選擇聲明。所以他們總共有3條語句:獲取複合詞,獲得可容納詞,獲得作曲。

對於第二次和第三次測試,用於提取容器的SQL與用於提取合成的on合併,並且以某種方式構建,以便它試圖選擇RegistrationCompound而不是TestCompound,例如它包含

registrati1_.reg_number as reg10_1_0_, 

和reg_number只是RegistrationCompound的一個屬性。在這兩種情況下,其選擇的實際化合物的第一個SELECT語句正確包含以下where子句:

testcompou0_.compound_type='TestCompound' 

所以這是非常混亂。爲什麼它取決於測試運行的順序?爲什麼它會嘗試選擇RegistrationCompound?

這裏是3次測試的最簡單的測試:如果測試運行作爲第二

@Test 
@Transactional 
public void testFindByCompositionPkStructureId() { 
    System.out.println("findByCompositionPkStructureId"); 

    Long structureId = 1000L; 

    TestCompound compound = new TestCompound(); 
    compound.setId(1000L); 
    compound.setCas("9999-99-9"); 
    compound.setCompoundName("Test Compound"); 

    List<TestCompound> result = 
     testCompoundRepository.findByCompositionsPkStructureId(structureId); 
    assertEquals(compound, result.get(0)); 
} 

或第三次,我得到了錯誤的類異常!有誰知道這裏發生了什麼?解?

+0

您的測試是否回滾? – willome 2013-02-11 16:13:20

+0

不是那些不改變任何東西的人。然而事實證明,從所有實體中刪除@Cache Annotation解決了這個問題。但是現在我面對一個新的,但非常相似的。 – 2013-02-12 11:57:22

回答

5

的問題是映射之一:

@Entity 
@Inheritance(strategy = InheritanceType.SINGLE_TABLE) 
@Table(name="containable") 
@DiscriminatorColumn(name="containable_type") 
@DiscriminatorOptions(force=true) 
public abstract class Containable<T extends Compound> {  

    @ManyToOne(optional=true, fetch = FetchType.EAGER, cascade = CascadeType.ALL) 
    private T compound; 
} 

此映射缺少目標實體。正確的是

@ManyToOne(optional=true, fetch = FetchType.EAGER, cascade = CascadeType.ALL, targetEntity = Compound.class) 

出於某種原因冬眠只是假定目標是RegistrationCompound,而不是拋出異常。相當煩人,因爲否則它會很容易找到問題。但是像這樣幾乎讓我發瘋。