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
How to implement polymorphic JPA entities with generic relations
提问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_.event
relation 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 SingularAttribute
to 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_.event
in 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 T
implements Serializable
但我终于找到了最简单的方法是 let T
implementsSerializable
@Entity
public class IgsSubject extends BasicObject implements Serializable{
private static final long serialVersionUID = -5387429446192609471L;