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:
  1. Entity A, étend l'entité abstraite E.

  1. Entity A possède une relation oneToMany sur l'entité B.

  1. Entity B, étend l'entité abstraite E.

  1. Entité abstraite E possède la définition de l'ID, ainsi qu'une relation OneToOne sur Entité C avec fetch type EAGER.

  1. 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 : Sélectionner tout - Visualiser dans une fenêtre à part
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 : Sélectionner tout - Visualiser dans une fenêtre à part
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 : Sélectionner tout - Visualiser dans une fenêtre à part
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 : Sélectionner tout - Visualiser dans une fenêtre à part
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 : Sélectionner tout - Visualiser dans une fenêtre à part
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 : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
 
SELECT a FROM A a JOIN FETCH a.bEntities WHERE a.customKey.key = :customKey
J'obtiens la stack d'erreurs suivante:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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:
  1. T1 = Passer la relation partagée oneToOne en LAZY au lieu de EAGER -> OK

  1. T1 + ajouter un JOIN FETCH sur la relation oneToOne dans la namedQuery -> KO

  1. 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.