Nathan Russell
Nathan Russell

Reputation: 3668

JPA EntityManager: 'find' vs. 'createQuery' and 'getResultList'

I'm working on a legacy code base that uses JPA (not JPA-2), and have come across the following method in a DAO implementation class to retrieve a single entity by ID (which is also it's primary key):

public EmailTemplate findEmailTemplateById(long id) {

    LOG.debug("Entering findEmailTemplateById(id='" + id + "')");
    // Construct JPQL query       
    String queryString = "SELECT a FROM EmailTemplate a " +
            "WHERE templateId = :templateId";
    Query query = entityManager.createQuery(queryString);

    query.setParameter("templateId", id);

    LOG.debug("Using query " + queryString);

    List<EmailTemplate> resultList = query.getResultList();

    LOG.debug("Exiting findEmailTemplateByName(id='" + id + "') results size " + resultList.size() + " ( returns null if 0 )");

    if (resultList.isEmpty() || resultList.size() == 0) {
        return null;
    } else {
        return resultList.get(0);
    }

}

I now need to write a similar DAO class for a different entity, and my method to find the entity by it's primary key looks a lot simpler! :

@Override
public EmailTemplateEdit findEmailTemplateEditById(long id) {
    LOG.debug("Entering findEmailTemplateEditById(id={})", id);
    return entityManager.find(EmailTemplateEdit.class, id);
}

The original author is not around to ask, so I'm wondering if anyone can suggest reasons as to why he constructed a JPQL query rather than simply using EntityManager#find(Class<T> entityClass, Object primaryKey)?

The javadoc for the find method says:

If the entity instance is contained in the persistence context, it is returned from there.

which suggests some form of caching and/or delayed writes. The javadoc for the createQuery and getResultList methods don't say anything like this.

I am unaware of any business or technical requirement in this application that would preclude caching, or of any issues resulting from stale entities or similar. I will check these with the rest of the project team when available, but I just thought I'd canvas the opinion of the SO community to see if there might be other reasons why a query was constructed and executed instead of simply using find

(I've seen this: When use createQuery() and find() methods of EntityManager?. Whilst it answers the question re: difference between createQuery and find, it doesn't answer it in context of finding entities by primary key)

Updated with additional info

From looking at the other methods in the original DAO class, it looks like there has been a deliberate/conscious decision to not take advantage of JPA managed objects. As above, the method to find by primary key uses a JPQL query. The method to delete an entity also uses a JPQL query. And the method to update an entity makes a copy of the passed in entity object and calls EntityManager#merge with the copy (thus the copy is a managed object, but is never used or returned from the method)
Weird ....

Upvotes: 0

Views: 7835

Answers (1)

Klaus Groenbaek
Klaus Groenbaek

Reputation: 5035

Short answer, there is no difference between find and a select query.

Your question suggests that you are not entirely familiar with what an EntityManager and a Persistence context is. EntityManager implementation are not required to be thread safe. If the EntityManager is injected by Spring or and EJB-container it is thread safe (because it is a thread-local proxy), if it is application managed (you created it by calling EntityManagerFactory.createEntityManager(), it is not thread safe, and you can't stor it in a variable, but have to create a new one every time.

The Persistence Context, is where entities live, whenever you create a new EntityManager you get a new Persistence context (there are exceptions to this rule). When you persist an Entity, or load an existing entity from the db (using find or query) it will be managed by the persistence context. When you commit a transaction JPA runs through ALL Entities managed by the Persistence context, and checks the state of the entity to find out which queries should be sent to the database.

The PersistenceContext can be seen as a first-level cache on top of the database. It is meant to have a short lifespan, typically no longer than the transaction. If you re-use the same entityManager for multiple transactions, the size could grow as more data is loaded, this is bad because every transaction has to run through all entities in the persistence context.

Upvotes: 6

Related Questions