2011-01-02 26 views
14

JPA 2.0を使用して、汎用リレーションを持つ多相エンティティを作成しようとしています。イベントテーブルと通知テーブルの2つのテーブルが必要です。それはSQLで可能であるよう汎用リレーションを持つ多相JPAエンティティの実装方法

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

論理的にこれは、休止状態で可能なはずである:これらの表の中にそうように、互いに関連している具体的な実体である

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

これは私が持っているものです:私はLoginNotification_.event関係を使用しようとすると

@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は、それが落ちます私のJPA 2.0メタモデルクエリではThis issueは同様のことを説明します。

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 static volatile SingularAttribute<NotificationEntity, EventEntity> event; 

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()を使用することはできますが、LoginNotification_.eventをJPAメタモデルの結合に使用することはできません。これを達成するためにジェネリックスを使用する代わりに何ができますか?

@Pascal Thivent - これに答えることができますか?これに

答えて

8

一つの解決策は、「参加」機能を使用しないことですし、完全なクロスではなく、参加するか:

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

を私はまともなクエリオプティマイザは、この短い作品を作る必要があることを前提としていますが、誰であれば私はそれを聞いて鋭いだろうこのアプローチの効率性についての任意の洞察力を持っています!

+0

優れた実装しています。 – logan

0

一般的な@loganのコードを試しました。

しかし、私は最終的に最も簡単な方法は、Tを聞かせてされたが、私は私はとにかくSQLでこのように合流書き込むために使用される、Serializable

@Entity 
public class IgsSubject extends BasicObject implements Serializable{ 

    private static final long serialVersionUID = -5387429446192609471L; 
関連する問題