Hibernate:继承和关系映射+泛型

beg*_*er_ 2 generics inheritance hibernate

我正在使用带有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;
}
Run Code Online (Sandbox Code Playgroud)

这个想法是AbstractCompound的某个实现只能与Containable的一个特定实现相关联(反之亦然).这导致以下实现:

@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;
}
Run Code Online (Sandbox Code Playgroud)

我已经玩过所有继承策略,而复合层次结构单表是唯一至少部分工作的表.如果JOINED或表_per_class hibernate创建不一致和错误!外键,即从test_containable到registration_compound(但不是从Batch到test_compound,这里它只是正确映射到registration_compound).

在可控制方面,我使用的策略似乎并不重要.

现在我的测试中的实际问题.具体的测试类.有3个测试.所有人都在特定地搜索"TestCompound"实例.事情是第一次执行这3个测试用例总是通过,另外2个总是失败.运行的顺序似乎是随机的(JUnit + @RunWith(SpringJUnit4ClassRunner.class)).这意味着任何测试都会通过,如果它是第一个运行的测试.

失败的测试抛出异常:

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

在第一次测试的情况下,正确选择获取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=?
Run Code Online (Sandbox Code Playgroud)

List<CompoundComposition> compositions在另一个select语句中选择.所以他们总共有3个陈述:获得复合,得到可容纳,得到成分.

对于第二次和第三次测试,用于获取可包含的SQL与用于获取合成的on合并,并且它以某种方式构建,因此它尝试选择RegistrationCompound而不是TestCompound,例如它包含

registrati1_.reg_number as reg10_1_0_, 
Run Code Online (Sandbox Code Playgroud)

和reg_number只是RegistrationCompound的属性.在这两种情况下,选择实际复合的第一个select语句在where子句中正确包含以下内容:

testcompou0_.compound_type='TestCompound'
Run Code Online (Sandbox Code Playgroud)

所以这很令人困惑.为什么它取决于测试运行的顺序?为什么它会尝试选择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));
}
Run Code Online (Sandbox Code Playgroud)

如果这个测试作为第二个或第三个运行我得到错误的类异常!有谁知道这里到底发生了什么?解?

beg*_*er_ 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;
}
Run Code Online (Sandbox Code Playgroud)

此映射缺少目标实体.正确的是

@ManyToOne(optional=true, fetch = FetchType.EAGER, cascade = CascadeType.ALL, targetEntity = Compound.class)
Run Code Online (Sandbox Code Playgroud)

出于某种原因,hibernate只是假设目标RegistrationCompound不是抛出异常.非常烦人,因为否则很容易找到问题.但就像这样,它几乎让我疯狂.