我有一个奇怪的问题,即hibernate不会在多对一关系中创建预期的实体类型.我们有以下具有子类层次结构的实体(简化):
@Entity @Table(name = "A") @Inheritance(strategy = InheritanceType.SINGLE_TABLE) @DiscriminatorColumn(name = "DISCRIMINATOR",discriminatorType = DiscriminatorType.STRING,length = 1) public abstract class A { @Id ... public Long getId() { ... } ... } @Entity @DiscriminatorValue("1") public class A1 extends A { ... } @Entity @DiscriminatorValue("2") public class A2 extends A { ... } @Entity @Table(name = "B") @Inheritance(strategy = InheritanceType.SINGLE_TABLE) @DiscriminatorColumn(name = "DISCRIMINATOR",length = 1) public abstract class B<AClass extends A> { protected AClass a; @Id ... public Long getId() { ... } ... public abstract AClass getA(); public void setA(AClass a) { ... } } @Entity @DiscriminatorValue("1") public class B1 extends B<A1> { ... @Override @ManyToOne(fetch = EAGER) @JoinColumn(name = "A_ID") public A1 getA() { ... } } @Entity @DiscriminatorValue("2") public class B2 extends B<A2> { ... @Override @ManyToOne(fetch = EAGER) @JoinColumn(name = "A_ID") public A2 getA() { ... } }
在persistence.xml中,两个实体都按顺序声明
A2 A1 B2 B1
现在我在DB中创建A1和B1的实例:
A1 a1 = new A1(); entityManager.persist(a1); B1 b1 = new B1(); b1.setA(a1); entityManager.persist(b1);
我可以看到实例保存到数据库中,每个都有ID 1,DISCRIMINATOR也是1,B中的A_ID也是1.
当我现在尝试获取B(在另一个休眠会话中):
B b = entityManager.find(B.class,1L);
我得到了例外:
org.hibernate.PropertyAccessException: Exception occurred inside getter of B Caused by: java.lang.ClassCastException: A2 cannot be cast to A1 at B1.getA(B1.java:61) ... 108 more
通过调试,我发现hibernate正在创建B1类型的正确实体,并为与A的关系创建类型为A2的不正确实体.如果更改了persistence.xml中的顺序,则会创建正确的A1类型.在这种情况下,似乎hibernate不会将A表的DISCRIMINATOR列考虑在内,但始终会创建在配置中声明的第一个子类型.怎么解决这个问题?注释有问题吗?
(我还首先在超类型B中使用了注释方法getA()的具体实现,但这会导致类似的问题.)
解决方法
使用Hibernate 5.0.2.Final,我能够使用@ManyToOne(…,targetEntity = A.class)使您的示例工作.我还替换了公共抽象的AClass getA();与普通的吸气剂.
@Entity @Table(name = "B") @Inheritance(strategy = InheritanceType.SINGLE_TABLE) @DiscriminatorColumn(name = "DISCRIMINATOR",length = 1) public abstract class B<AClass extends A> { private Long id; private AClass a; @Id @GeneratedValue public Long getId() { return id; } public void setId(Long id) { this.id = id; } @ManyToOne(fetch = FetchType.EAGER,targetEntity = A.class) @JoinColumn(name = "A_ID") public AClass getA() { return a; } public void setA(AClass a) { this.a = a; } }
@Entity @DiscriminatorValue("1") public class B1 extends B<A1> { // no need to override getA() }
@Entity @DiscriminatorValue("2") public class B2 extends B<A2> { // no need to override getA() }
我在文档中没有找到任何关于此行为的信息.所以我只有我的观察:
>没有targetEntity = A.class Hibernate甚至没有查询表A的DISCRIMINATOR列,因为它急切地从A和B一起获取行,就像它已经做出关于A的实际类型的决定一样.>当我添加targetEntity = A.class时,A.DISCRIMINATOR出现在查询中,并且使用类A的正确子类创建对象.