有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java如何实现具有泛型关系的多态JPA实体

我试图使用JPA2.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>{

...
}

使用这段代码,我可以持久化和获取任何事件、通知、LoginEvent或NotificationEvent,但当我尝试在JPA2.0元模型查询中使用LoginNotification_.event关系时,它会失败This issue解释了类似的情况

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) 个答案

  1. # 1 楼答案

    我试过你的通用代码,@logan

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

    @Entity
    public class IgsSubject extends BasicObject implements Serializable{
    
        private static final long serialVersionUID = -5387429446192609471L;
    
  2. # 2 楼答案

    一种解决方案是避免使用“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));
    

    我认为一个好的查询优化器应该能很快做到这一点,但如果有人对这种方法的效率有任何见解,我会非常乐意听到