java – Hibernate在关系中创建错误的实体子类型

我有一个奇怪的问题,即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的正确子类创建对象.

相关文章

ArrayList简介:ArrayList 的底层是数组队列,相当于动态数组。与 Java 中的数组相比,它的容量能动态增...
一、进程与线程 进程:是代码在数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位。 线程...
本文为博客园作者所写:&#160;一寸HUI,个人博客地址:https://www.cnblogs.com/zsql/ 简单的一个类...
#############java面向对象详解#############1、面向对象基本概念2、类与对象3、类和对象的定义格式4、...
一、什么是异常? 异常就是有异于常态,和正常情况不一样,有错误出错。在java中,阻止当前方法或作用域...
Collection接口 Collection接口 Collection接口 Collection是最基本的集合接口,一个Collection代表一组...