gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-03 20:37:46 27 4
gpt4 key购买 nike

我在 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 的一个特定实现相关联(反之亦然)。这导致以下实现:
@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(但不是从 Batch 到 test_compound,这里它仅正确映射到 registration_compound)。

在 Containable 方面,我使用什么策略似乎并不重要。

现在到我的测试中的实际问题。具体测试类。有 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)

在第一次测试的情况下,在正确选择获取容器后 hibernate 问题
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在另一个 select 语句中被选中。所以它们总共有 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));
}

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

最佳答案

问题是映射之一:

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

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

关于Hibernate:继承和关系映射+泛型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14810287/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com