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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4581205/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 07:03:03  来源:igfitidea点击:

How to implement polymorphic JPA entities with generic relations

javahibernatejpa-2.0metamodel

提问by logan

I'm trying to use JPA 2.0 to create polymorphic entities with generic relations. There should be two tables, an event table and a notification table. Inside those table are concrete entities that are related to one another, like so:

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

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

Logically this should be possible in hibernate, as it is possible in SQL:

从逻辑上讲,这在 hibernate 中应该是可能的,因为它在 SQL 中是可能的:

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

This is what I have:

这就是我所拥有的:

@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>{

...
}

Using this code, I can persist and fetch any Event, Notification, LoginEvent, or NotificationEvent, but it falls down when I try to use the LoginNotification_.eventrelation in my JPA 2.0 metamodel queries. This issueexplains something similar.

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

public static volatile SingularAttribute<NotificationEntity, EventEntity> event;

When I try to do a join in a criteria query, I get an error:

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

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);

I can get around this error, by adding a new SingularAttributeto the LoginNotification_metamodel, but this fails in execution:

我可以通过向元模型添加一个新的SingularAttribute来解决这个错误LoginNotification_,但这在执行时失败了:

public abstract class LoginNotification_ extends Notification_ {

    // Adding this Removes Type mismatch error, but causes run-time error
    public static volatile SingularAttribute<LoginNotification, LoginEvent> event; 

    ...
}

According to some posts, generic relations won't work (How to handle JPA annotations for a pointer to a generic interface), but by using a @ManyToOne(optional=false, targetEntity=Event.class)annotation, we can get them to behave. Unfortunately, the generics seem to break the JPA criteria query.

根据一些帖子,泛型关系不起作用(如何处理指向泛型接口的指针的 JPA 注释),但通过使用@ManyToOne(optional=false, targetEntity=Event.class)注释,我们可以让它们起作用。不幸的是,泛型似乎破坏了 JPA 标准查询。

Are there any suggestions on how I can perform this lookup? I can use LoginNotification.getEvent()in my code, but I cannot use LoginNotification_.eventin my JPA metamodel joins. What's the alternative to using generics to accomplish this?

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

@Pascal Thivent - Can you answer this?

@Pascal Thivent - 你能回答这个吗?

采纳答案by idle

One solution to this is to avoid using the 'join' function and do a full cross join instead:

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

I would assume that a decent query optimizer should make short work of this, but if anyone has any insight on the efficiency of this approach I would be keen to hear it!

我会假设一个体面的查询优化器应该可以缩短工作时间,但是如果有人对这种方法的效率有任何见解,我会很想听到它!

回答by Raymond

I've tried you code for generic, @logan .

我已经尝试过为通用代码 @logan 编写代码。

But I finally found the simplest way is let Timplements Serializable

但我终于找到了最简单的方法是 let TimplementsSerializable

@Entity
public class IgsSubject extends BasicObject implements Serializable{

    private static final long serialVersionUID = -5387429446192609471L;