如何使用generics关系实现多态JPA实体

我正在尝试使用JPA 2.0来创建具有generics关系的多态实体。 应该有两个表,一个事件表和一个通知表。 在这些表中是彼此相关的具体实体,如下所示:

Event <---------- Notification | | LoginEvent <------ LoginNotification extends Notification 

从逻辑上讲,这应该可以在hibernate中实现,因为它可以在SQL中实现:

 +----------+ +----------+ | Event | | Notif | +----------+ +----------+ | | | Id | | Id | <- | Evt_id | | Type | <- | Type | | ... | | ... | +----------+ +----------+ 

这就是我所拥有的:

 @Entity @Inheritance public abstract class Event{ ... } @Entity public class LoginEvent extends Event{ ... } @Entity @Inheritance public abstract class Notification{ @ManyToOne(optional=false, targetEntity=Event.class) @JoinColumn private X event; ... } @Entity public class LoginNotification extends Notification{ ... } 

使用此代码,我可以持久化并获取任何Event,Notification,LoginEvent或NotificationEvent,但是当我尝试在JPA 2.0元模型查询中使用LoginNotification_.event关系时,它就会失败。 这个问题解释了类似的东西

 public static volatile SingularAttribute event; 

当我尝试在条件查询中进行连接时,出现错误:

 EntityManager em = getEntityManager(); CriteriaBuilder cb = em.getCriteriaBuilder(); CriteriaQuery query = cb.createQuery(LoginNotification.class); Root root = query.from(LoginNotification.class); // This line complains: Type mismatch: cannot convert from // Join to Join Join join = root.join(LoginNotification_.event, JoinType.INNER); 

我可以通过向LoginNotification_元模型添加新的SingularAttribute来解决此错误,但是执行失败:

 public abstract class LoginNotification_ extends Notification_ { // Adding this Removes Type mismatch error, but causes run-time error public static volatile SingularAttribute event; ... } 

根据一些post,generics关系不起作用( 如何处理指向generics接口的指针的JPA注释 ),但是通过使用@ManyToOne(optional=false, targetEntity=Event.class)注释,我们可以将它们带到表现。 不幸的是,generics似乎打破了JPA标准查询。

有关如何执行此查找的建议吗? 我可以在我的代码中使用LoginNotification.getEvent() ,但我不能在我的JPA元模型联接中使用LoginNotification_.event 。 使用generics来实现这一目标的替代方法是什么?

@Pascal Thivent – 你能回答这个问题吗?

一个解决方案是避免使用’join’函数并执行完全交叉连接:

 EntityManager em = getEntityManager(); CriteriaBuilder cb = em.getCriteriaBuilder(); CriteriaQuery query = cb.createQuery(LoginNotification.class); Root notfRoot = query.from(LoginNotification.class); Root eventRoot = query.from(LoginEvent.class); ... query.where(cb.equals(notfRoot.get(Notification_.event), eventRoot.get(Event_.id)), ...(other criteria)); 

我认为一个体面的查询优化器应该对此做一些简短的工作,但如果有人对这种方法的效率有任何见解,我会热衷于听到它!

我试过你的generics代码,@ logan。

但我终于发现最简单的方法是让T实现Serializable

 @Entity public class IgsSubject extends BasicObject implements Serializable{ private static final long serialVersionUID = -5387429446192609471L;