【发布时间】:2017-04-10 18:59:50
【问题描述】:
我有一个域模型,其中包含一些泛型,我尝试将其放入 JPA 中。我的示例是事件域,其中您拥有诸如 Concerts 之类的事件,并且拥有诸如 ConcertTickets 之类的门票。
事件:
@Entity
@Inheritance
@DiscriminatorColumn(discriminatorType=DiscriminatorType.STRING, name="s_discriminator")
public abstract class Event {
...
}
演唱会:
@Entity
@Inheritance
@DiscriminatorValue("Concert")
public class Concert extends Event {
...
}
门票:
@Entity
@Inheritance
@DiscriminatorColumn(discriminatorType=DiscriminatorType.STRING, name="s_discriminator")
public abstract class Ticket<E extends Event> {
...
@ManyToOne(targetEntity=Event.class)
private E event;
public E getEvent() {
return event;
}
}
演唱会门票:
@Entity
@Inheritance
@DiscriminatorValue("Concert")
public class ConcertTicket extends Ticket<Concert> {
...
}
服务:
ConcertTicket ticket = dao.findTicket(id);
Concert concert = ticket.getConcert();
这行得通。 targetEntity 是必需的,否则我会收到以下错误:
Property Ticket.event 具有未绑定类型且没有明确的目标实体。 解决此通用使用问题或设置明确的目标属性(例如 @OneToMany(target=) 或使用显式 @Type
到目前为止,我的模型没有问题。但我注意到我的表现并不好。解决的办法是把ticket和Event的关系变成Lazy Loading:
@ManyToOne(targetEntity=Event.class, fetch=FetchType.LAZY)
private E event;
现在问题开始了。当我调用上面发布的服务时,我得到以下异常:
java.lang.ClassCastException: Event_$$_jvst610_48 无法转换为 音乐会
在运行时,对泛型一无所知。因此,当 JPA 实现(Hibernate)创建“事件”的实例时,没有可用的信息表明它实际上是“音乐会”。因此创建了“Event”的子类,而不是“Concert”的子类。
有没有人能解决这个问题?我知道有 2 个明显的解决方案:a)避免泛型 b)使用急切加载。我希望找到一个可以同时保留两者的解决方案。
【问题讨论】:
-
不要使用 instanceof 和强制转换。使用访客模式。
-
solution c):正确支持泛型的 JPA 提供者不需要 targetEntity 指定。同样,如果这些提供程序不使用“代理”而是使用字节码增强,那么它们也没有 ClassCastException。
-
我认为问题不足以换掉 JPA 提供程序。不过我很受诱惑:-)
-
@JBNizet :我没有使用 instanceof 或强制转换。所以我不确定访问者模式对我有什么帮助。
-
@EasterBunnyBugSmasher 你有解决办法吗?
标签: java hibernate generics jpa lazy-loading