I'm facing a problem with JOIN FETCH and EAGER relations.
I have the following entity relations:
Entity A extends abstract entity E.
Abstract entity E has a oneToOne bidirectional relation with Entity C with EAGER fetch type.
Entity A has oneToMany relation with Entity B.
Entity B extends abstract entity E (so have oneToOne relation too with C)
Entity C has inverse relation to abstract entity E
While executing a simple namedQuery like
SELECT a FROM A a WHERE a.key = :key
Where parameter 'key' is String type, then i have no problem. Accessing to sub entities B from retrieved entity A execute sub requests as its supposed to be.
But if i add a JOIN FETCH to my namedQuery:
SELECT a FROM A a JOIN FETCH a.entitiesB WHERE a.key = :key
i obtain the following error stack trace:
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)
at org.apache.openejb.core.ivm.BaseEjbProxyHandler.invoke(BaseEjbProxyHandler.java:283)
...
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 relation FROM Relation relation JOIN FETCH relation.accounts WHERE relation.key = :key [java.lang.String]
at org.apache.openjpa.jdbc.sql.DBDictionary.setUnknown(DBDictionary.java:1458)
at org.apache.openjpa.jdbc.sql.SQLBuffer.setParameters(SQLBuffer.java:544)
at org.apache.openjpa.jdbc.sql.SQLBuffer.prepareStatement(SQLBuffer.java:453)
at org.apache.openjpa.jdbc.sql.SQLBuffer.prepareStatement(SQLBuffer.java:429)
at org.apache.openjpa.jdbc.sql.SelectImpl.prepareStatement(SelectImpl.java:479)
...
If i change the EAGER relations to LAZY, i do not have this error anymore. So, what's the problem ?
Edit 1: I get the same error if i keep oneToOne relations with LAZY fetch type and add JOIN FETCH a.entityC directly on the namedQuery
Edit 2: Removing relation oneToOne with entity C from abstractEntity class and adding this relation directly into EntityA and EntityB (plus modifying entity C to have reverse relation with A & B), still keeping this oneToOne relation as EAGER => No problem. So it looks like the problem come from having this shared relation into the abstract entity class, but why?
This is code example illustrated the problem.
Entity A
@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;
...
}
Entity B
@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;
...
}
Abstract entity class
@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 = "TOTO_ID_SEQ", strategy = GenerationType.SEQUENCE)
private Long id;
@OneToOne(mappedBy = "...", fetch = FetchType.EAGER)
private C anotherEntity;
@OneToMany(mappedBy = "...", fetch = FetchType.LAZY)
private List<D> anotherEntities;
...
}
Embedded key
@Embeddable
@Access(AccessType.FIELD)
public class CustomEmbeddedKey {
@Column(name = "...", length = ...)
private String key;
...
}
Dao sample
TypedQuery<A> query = createNamedQuery("findADetails", A.class);
query.setParameter("customKey", queryParam);
List<A> aEntitiesFound = query.getResultList();
Thanks in advance for your help.
Think i found the problem. It's due to the mapping which not really supported by openJPA if we refer to the documentation on Eager Fetching Considerations and Limitations
So finally there are two solutions for me:
Solution 1 (easy one):
Advantages:
Disadvantages:
Solution 2: Modify the mapping
Advantages:
Disadvantages: