2011-01-02 15 views
14

Estoy tratando de usar JPA 2.0 para crear entidades polimórficas con relaciones genéricas. Debe haber dos tablas, una tabla de eventos y una tabla de notificaciones. Dentro de los tabla son entidades concretas que están relacionados entre sí, así:Cómo implementar entidades JPA polimórficas con relaciones genéricas

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

Lógicamente, esto debería ser posible en hibernación, ya que es posible en SQL:

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

Esto es lo que tengo :

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

... 
} 

Usando este código, que puede persistir a buscar cualquier caso, notificación, LoginEvent o NotificationEvent, pero se cae cuando trato de usar la relación LoginNotification_.event en mis consultas de metamodelo JPA 2.0. This issue explica algo similar.

public static volatile SingularAttribute<NotificationEntity, EventEntity> event; 

Cuando intento hacer una combinación en una consulta criterios, me sale un 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); 

puedo solucionar este error, mediante la adición de un nuevo SingularAttribute a la LoginNotification_ metamodelo, pero esto falla en la ejecución:

public abstract class LoginNotification_ extends Notification_ { 

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

    ... 
} 

de acuerdo con algunos mensajes, las relaciones genérico no funcionará (How to handle JPA annotations for a pointer to a generic interface), pero mediante el uso de un @ManyToOne(optional=false, targetEntity=Event.class) una notación, podemos hacer que se comporten. Desafortunadamente, los genéricos parecen romper la consulta de criterios de JPA.

¿Hay alguna sugerencia sobre cómo puedo realizar esta búsqueda? Puedo usar LoginNotification.getEvent() en mi código, pero no puedo usar LoginNotification_.event en las combinaciones de mi metamodelo JPA. ¿Cuál es la alternativa al uso de genéricos para lograr esto?

@Pascal Thivent - ¿Puedes responder esto?

Respuesta

8

Una solución a esto es para evitar el uso de la función de 'unirse' y hacer una cruz llena unirse a su lugar:

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

yo asumiría que un optimizador de consultas decente debe hacer el trabajo por debajo de esta, pero si alguien tiene alguna idea sobre la eficiencia de este enfoque, ¡me gustaría escucharlo!

+0

Excelente, solía escribir mi se une de esta manera en SQL de todos modos. – logan

0

He intentado codificar genérico, @logan.

Pero finalmente encontré la forma más sencilla es dejar T implementa Serializable

@Entity 
public class IgsSubject extends BasicObject implements Serializable{ 

    private static final long serialVersionUID = -5387429446192609471L; 
Cuestiones relacionadas