JPA - JOIN FETCH sur relation OneToOne en EAGER = ArgumentException error
Bonjour,
J'ai une erreur lorsque j'effectue une NamedQuery avec un JOIN FETCH sur une relation partagée OneToOne en EAGER. Par partager je veux dire que cette relation se trouve dans une entité abstraite.
En gros voici la composition de mes entités:
- Entity A, étend l'entité abstraite E.
- Entity A possède une relation oneToMany sur l'entité B.
- Entity B, étend l'entité abstraite E.
- Entité abstraite E possède la définition de l'ID, ainsi qu'une relation OneToOne sur Entité C avec fetch type EAGER.
- Entité C, possède la relation inverse sur l'entité abstraite E (commune à A et B donc)
Voici le code simplifié qui pose problème.
Entité A
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
|
@Entity
@Table(name = "TABLE_A")
@Access(AccessType.FIELD)
@NamedQueries({
@NamedQuery(name = "findADetails", query = "SELECT a FROM A a WHERE a.customKey.key = :customKey")})
public class A extends abstractEntity {
@Embedded
private CustomEmbeddedKey customKey;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "entityA")
private List<B> bEntities;
...
} |
Entité B
Code:
1 2 3 4 5 6 7 8 9 10 11 12
|
@Entity
@Table(name = "TABLE_B")
@Access(AccessType.FIELD)
public class B extends abstractEntity {
@ManyToOne(fetch = FetchType.LAZY, targetEntity = A.class)
@JoinColumn(name = "FK_A_ID")
private A entityA;
...
} |
Entité abstraite
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
|
@Entity
@Access(AccessType.FIELD)
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
@SequenceGenerator(name = "TOTO_ID_SEQ", sequenceName = "TOTO_ID_SEQ", initialValue = 1, allocationSize = 1)
public abstract class abstractEntity {
@Id
@Column(name = "ID")
@GeneratedValue(generator = "...", strategy = GenerationType.SEQUENCE)
private Long id;
@OneToOne(mappedBy = "...", fetch = FetchType.EAGER)
private C anotherEntity;
@OneToMany(mappedBy = "...", fetch = FetchType.LAZY)
private List<D> anotherEntities;
...
} |
Clé custom
Code:
1 2 3 4 5 6 7 8 9 10
|
@Embeddable
@Access(AccessType.FIELD)
public class CustomEmbeddedKey {
@Column(name = "...", length = ...)
private String key;
...
} |
Exemple Dao
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
|
// Dao utilisant la NamedQuery
public class Dao {
...
// Code d'exemple
public A bidule (String queryParam) {
TypedQuery<A> query = createNamedQuery("findADetails", A.class);
query.setParameter("customKey", queryParam);
List<A> aEntitiesFound = query.getResultList();
return aEntitiesFound.get(0);
}
...
} |
Problème: Via un test junit, lorsque j'exécute ma namedQuery via le Dao, tout se passe bien.
Par contre, souhaitant récupérer la liste de mes entités B configurée en LAZY en une seule requête, si j'ajoute un JOIN FETCH dans la NamedQuery comme ceci:
Code:
1 2
|
SELECT a FROM A a JOIN FETCH a.bEntities WHERE a.customKey.key = :customKey |
J'obtiens la stack d'erreurs suivante:
Code:
1 2 3 4 5 6 7 8
|
javax.ejb.EJBTransactionRolledbackException: The transaction has been marked rollback only because the bean encountered a non-application exception :javax.ejb.EJBTransactionRolledbackException : The transaction has been marked rollback only because the bean encountered a non-application exception :org.apache.openjpa.persistence.ArgumentException : The specified parameter of type "class org.apache.openjpa.util.LongId" is not a valid query parameter.
at org.apache.openejb.core.ivm.BaseEjbProxyHandler.convertException(BaseEjbProxyHandler.java:345)
...
Caused by: <openjpa-2.2.0-r422266:1244990 nonfatal user error> org.apache.openjpa.persistence.ArgumentException: The specified parameter of type "class org.apache.openjpa.util.LongId" is not a valid query parameter.
FailedObject: SELECT a FROM A a JOIN FETCH a.bEntities WHERE a.customKey.key = :customKey [java.lang.String]
at org.apache.openjpa.jdbc.sql.DBDictionary.setUnknown(DBDictionary.java:1458)
... |
Après les tests et résultats suivants:
- T1 = Passer la relation partagée oneToOne en LAZY au lieu de EAGER -> OK
- T1 + ajouter un JOIN FETCH sur la relation oneToOne dans la namedQuery -> KO
- Virer la relation oneToOne de la classe abstraite pour l'ajouter dans l'entity A et B, et modifier l'entité C pour y acceuillir les relations inverses vers A et B -> OK
Il apparait donc que le problème viendrait du fait que la relation oneToOne sur l'entité C soit partagée, i.e présente dans la classe abstratire.
Est-ce que quelqun sait pourquoi ? Y -a-t-il un problème du fait que lorsque openJpa tente d'améliorer la requête, il n'arrive pas à matcher les ID issue de cette relation entre celui de A et celui de B (qui pourtant ne sont pas les mêmes puisque la régle de génération est commune sur l'entité abstraite)
Bref, si une âme charitable pourrait m'aider à y voir plus clair, ce serait très sympa :)
Merci d'avance pour toute aide.