2011-01-02 5 views
14

Sto cercando di utilizzare JPA 2.0 per creare entità polimorfiche con relazioni generiche. Dovrebbero esserci due tabelle, una tabella eventi e una tabella di notifica. All'interno coloro tabella sono entità concrete che sono legati gli uni agli altri, in questo modo:Come implementare entità polimorfiche JPA con relazioni generiche

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

Logicamente questo dovrebbe essere possibile in ibernazione, in quanto è possibile in SQL:

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

Questo è ciò che ho :

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

... 
} 

Utilizzando questo codice, posso persistere e recuperare ogni caso, notifica, LoginEvent o NotificationEvent, ma cade quando si tenta di utilizzare la relazione LoginNotification_.event nelle mie query sui metamodelli JPA 2.0. This issue spiega qualcosa di simile.

public static volatile SingularAttribute<NotificationEntity, EventEntity> event; 

Quando provo a fare un join in una query criteri, ottengo un errore:

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

posso ottenere intorno a questo errore, con l'aggiunta di un nuovo SingularAttribute al LoginNotification_ metamodello, ma questo non riesce in esecuzione:

public abstract class LoginNotification_ extends Notification_ { 

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

    ... 
} 

Secondo alcuni messaggi, rapporti generici non funziona (How to handle JPA annotations for a pointer to a generic interface), ma utilizzando un @ManyToOne(optional=false, targetEntity=Event.class) un notazione, possiamo farli comportare. Sfortunatamente, i generici sembrano rompere la query sui criteri JPA.

Ci sono suggerimenti su come posso eseguire questa ricerca? Posso usare LoginNotification.getEvent() nel mio codice, ma non posso usare LoginNotification_.event nei miei join Metamodel JPA. Qual è l'alternativa all'uso dei generici per realizzare questo?

@Pascal Thivent - Puoi rispondere a questo?

risposta

8

Una soluzione a questo è quella di evitare di utilizzare la funzione di 'unire' e fare una croce piena join invece:

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

Parto dal presupposto che una query optimizer decente dovrebbe rendere il lavoro a breve di questo, ma se qualcuno Ho qualche idea sull'efficienza di questo approccio che mi piacerebbe sentirlo!

+0

eccellente, ho usato per scrivere il mio si unisce in questo modo in SQL comunque. – logan

0

Ho provato il codice generico, @logan.

Ma ho finalmente trovato il modo più semplice è lasciare T implementa Serializable

@Entity 
public class IgsSubject extends BasicObject implements Serializable{ 

    private static final long serialVersionUID = -5387429446192609471L;