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

15

我正在尝试使用JPA 2.0创建具有通用关系的多态实体。应该有两个表,一个事件表和一个通知表。这些表中包含相互关联的具体实体,就像这样:

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

从逻辑上讲,这应该在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<X extends Event>{

 @ManyToOne(optional=false, targetEntity=Event.class)
 @JoinColumn
 private X event;

...
}

@Entity
public class LoginNotification extends Notification<LoginEvent>{

...
}

使用这段代码,我可以持久化并获取任何事件、通知、登录事件或通知事件,但当我尝试在我的JPA 2.0元模型查询中使用LoginNotification_.event关系时,它会失败。 此问题解释了类似的情况。

public static volatile SingularAttribute<NotificationEntity, EventEntity> event;

在使用条件查询进行联合操作时,出现错误:

EntityManager em = getEntityManager();
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<LoginNotification> query = cb.createQuery(LoginNotification.class);
Root<LoginNotification> root = query.from(LoginNotification.class);

//  This line complains: Type mismatch: cannot convert from
//  Join<LoginNotification,Event> to Join<LoginNotification,LoginEvent>
Join<LoginNotification, LoginEvent> 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<LoginNotification, LoginEvent> event; 

    ...
}
根据一些帖子的说法,通用关系不起作用 (How to handle JPA annotations for a pointer to a generic interface),但是通过使用@ManyToOne(optional=false, targetEntity=Event.class)注释,我们可以使它们正常工作。遗憾的是,泛型似乎破坏了JPA标准查询。
有没有什么建议可以执行此查找? 我可以在我的代码中使用LoginNotification.getEvent(),但我不能在我的JPA元模型连接中使用LoginNotification_.event。有没有使用泛型以完成此操作的替代方法?
@Pascal Thivent - 你能回答这个问题吗?
2个回答

8

解决这个问题的一个方法是避免使用“join”函数,而改为执行完整的交叉连接:

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

我认为一个不错的查询优化器应该能够很快地处理这个问题,但如果有人对这种方法的效率有任何见解,我很乐意听取!


太好了,我以前在 SQL 中就是这样写连接的。 - logan

0

我已尝试了你的通用代码,@logan。

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

@Entity
public class IgsSubject extends BasicObject implements Serializable{

    private static final long serialVersionUID = -5387429446192609471L;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接