Gan*_*alf 8 java hibernate jpa discriminator
我有一个奇怪的问题,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", discriminatorType = DiscriminatorType.STRING, 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() { ... }
}
Run Code Online (Sandbox Code Playgroud)
在persistence.xml两个实体中都按顺序声明
A2
A1
B2
B1
Run Code Online (Sandbox Code Playgroud)
现在我在DB中创建A1和B1的实例:
A1 a1 = new A1();
entityManager.persist(a1);
B1 b1 = new B1();
b1.setA(a1);
entityManager.persist(b1);
Run Code Online (Sandbox Code Playgroud)
我可以看到实例正确保存到数据库中每个都有ID 1,DISCRIMINATOR也是1,B中的A_ID也是1.
当我现在尝试获取B(在另一个休眠会话中):
B b = entityManager.find(B.class, 1L);
Run Code Online (Sandbox Code Playgroud)
我得到了例外:
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
Run Code Online (Sandbox Code Playgroud)
通过调试,我发现hibernate正在创建B1类型的正确实体,并为A的关系创建一个类型为A2的错误实体.如果persistence.xml更改了该订单,则会创建正确的A1类型.在这种情况下,似乎hibernate不会将A表的DISCRIMINATOR列考虑在内,但始终会创建在配置中声明的第一个子类型.怎么解决这个问题?注释有问题吗?
(我也getA()首先在超类型B中使用其注释的方法的具体实现,但这会导致类似的问题.)
使用 Hibernate 5.0.2.Final 我能够使用@ManyToOne(..., targetEntity = A.class). 我也换成public abstract AClass getA();了普通的吸气剂。
@Entity
@Table(name = "B")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "DISCRIMINATOR", discriminatorType = DiscriminatorType.STRING, 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;
}
}
Run Code Online (Sandbox Code Playgroud)
@Entity
@DiscriminatorValue("1")
public class B1 extends B<A1> {
// no need to override getA()
}
Run Code Online (Sandbox Code Playgroud)
@Entity
@DiscriminatorValue("2")
public class B2 extends B<A2> {
// no need to override getA()
}
Run Code Online (Sandbox Code Playgroud)
我在文档中没有找到有关此行为的任何信息。所以我只有我的观察:
targetEntity = A.classHibernate,那么在急切地从with 中获取行时甚至不会查询DISCRIMINATOR表的列,就像它已经决定了. AABAtargetEntity = A.class,A.DISCRIMINATOR出现在查询中时,对象是用 class 的正确子类创建的A。| 归档时间: |
|
| 查看次数: |
1727 次 |
| 最近记录: |