Reputation: 319
Im using JPA in my Java ee application. I have a table A mapped to a class A. Now when I query the entity (e.g. by its id) it always returns a different object. Example:
public A getAById(int id) {
A obj = (A) em.createNamedQuery("getAById")
.setParameter("id", id).getSingleResult();
return obj;
}
public void test(){
getAById(1)==getAById(1) //is false
}
Is there a way to tell JPA not to always create new instances when querying from a database but to return an existing object if it hast alreay been queried?
//EDIT This article helped me a lot: http://en.wikibooks.org/wiki/Java_Persistence/Caching#Example_JPA_2.0_Cacheable_annotation
Upvotes: 1
Views: 3081
Reputation: 21145
JavaEE containers wrap the JPA providers EntityManager in a proxy, so the behavior you see is likely because your container gets a new EM outside of a transaction. Your two getAById(1) calls are going to two different EntityManagers underneath the covers. You can get around this by wrapping them in a single transaction, forcing the container to use the same entity manager for the life of the transaction.
Upvotes: 2
Reputation: 11298
Is there a way to tell JPA not to always create new instances when querying from a database but to return an existing object if it hast already been queried?
JPA never creates new entity for select queries. See the following example
Query qry = em.createNamedQuery("SELECT r FROM BusinessUnit r WHERE r.buKey = :buKey");
Object result1 = qry.setParameter("buKey", "32").getSingleResult();
qry = em.createNamedQuery("SELECT r FROM BusinessUnit r WHERE r.buKey = :buKey");
Object result2 = qry.setParameter("buKey", "32").getSingleResult();
System.out.println(result1 == result2);
For the above, I get result1 == result2
true, since hashCode
method is overwritten in entity class.
If your entity class is overwritten the equals
method, you can test with equals method instead of comparing with object reference.
public void test(){
getAById(1).equals(getAById(1)) ;
}
Upvotes: 3
Reputation: 2257
if there is already an existing entity instance in the persistence context, yes, but you need to use EntityManager operations such entityManager.find(entity.class, id); Doing this will ask entitymanager to find entity from associated PersistenceContext first, if it cannot find it it will query from DB. Once the entity instance is first time loaded into associated PersistenceContext, the rest query against same entity ID will not trigger a DB query and always reuse the one cached in PersistenceContext. This is JPA first level cache.
Using JPQL will not fit your requirement, since JPQL will bypass PersistenceContext and always communicate with DB directly, which will end up with getting different java object(same entity in terms of primary key).
Upvotes: -2