tags:

views:

506

answers:

4

Hello, we are developing a J2SE application and we are using Hibernate for our persistence layer. For our database access I created a singleton class that has all the necessary methods to obtain and persist objects from the database. But once I created the second method for obtaining objects I immediately realized that I have a smelly code:

public enum DataManager {
  Instance;

  public List<Employee> getEmployees() {
    EntityManagerFactory emf = Persistence.createEntityManagerFactory("test");
    EntityManager em = emf.createEntityManager();
    EntityTransaction tx = em.getTransaction();
    tx.begin();
    List<?> ems = em.createQuery("select e from Employee e").getResultList();
    List<Employee> result = new ArrayList<Employee>();
    for (Object o : ems )
      result.add((Employee) o);

    tx.commit();
    em.close();
    emf.close();
    return result;
  }

  public List<Shift> getShifts() {
    EntityManagerFactory emf = Persistence.createEntityManagerFactory("test");
    EntityManager em = emf.createEntityManager();
    EntityTransaction tx = em.getTransaction();
    tx.begin();
    List<?> ems = em.createQuery("select s from Shift s").getResultList();
    List<Shift> result = new ArrayList<Shift>();
    for (Object o : ems )
      result.add((Shift) o);

    tx.commit();
    em.close();
    emf.close();

    return result;
  }
}

So I definitely need to redesign this. The Hibernate documentation has a HibernateUtility class for Session handling and Transactions. But I use EntityManager.

Just yesterday I found this very interesting article called Generic DAO pattern with JDK 5.0. It is written in 2005 so I really not sure if it is still valid. It again uses Sessions.

Is this what you use? If not, have a better solution?

Thank you.

Note1: I'm fairly new to Hibernate
Note2: The title doesn't seem right

+2  A: 

I strongly recommend that you use Spring to configure and manage your EntityManager singleton. No more smells. This sort of problem is the kind of irritating mechanics that there's really no need to worry about.

skaffman
I thought about Spring for a while. I never had used it before. I'm really tempted to use it mainly for my CV :P But I think that it brings unnecessary complexity in my project. Of course, I could be wrong. ;)
pek
You are wrong :-) Spring *removes* complexity, the kind of complexity that you're seeing in your sample code.
skaffman
+1. Once you actually start using Spring you'll wonder how have you ever done without it.
ChssPly76
A: 

A possible way to avoid the writing the same session/transaction opening and closing is to either use a container in a J2EE environment, or perhaps use Spring to wrap all of your methods in a class. You can also use JPA and Hibernate annotations with Spring which provides a nice clean way of handling this. I have always preferred Spring as it provides the level of control I want, and also allows me to inject things like a Data Accessor into a service level class although there are other ways to do that as well.

Ivan
A: 

A simple refactoring would be to extract the common code to a single utility method:

public List<Employee> getEmployees() {
    return getObjects("Employee", Employee.class);
}

private <T> List<T> getObjects(String typeName, Class<T> typeClass) {
    EntityManagerFactory emf = Persistence.createEntityManagerFactory("test");
    EntityManager em = emf.createEntityManager();
    EntityTransaction tx = em.getTransaction();
    tx.begin();
    List<?> ems = em.createQuery("select o from " + typeName + " o").getResultList();
    List<T> result = new ArrayList<T>();
    for (Object o: ems)
      result.add(typeClass.cast(o));
    tx.commit();
    em.close();
    emf.close();
    return result;
  }

Would that address the smell that's disturbing you? Or is there more?

Tom Anderson
You could then easily refactor this to have a generic class which does various kinds of retrieval, and then parameterised instances for each object type. This is getting pretty close to that Generic DAO pattern, but is more gradual. Implement the full pattern if and when you need it.
Tom Anderson
Indeed, this looks like a good start.
pek
Creating new EntityManagerFactory instance for every call is **extremely** inefficient.
ChssPly76
That is why I started this post. I new there had to be a better way. ;)
pek
Promoting the EntityManagerFactory to an instance variable would fix that. The EntityManager isn't threadsafe, though, so you can't keep that in an instance variable. You could use a thread-local, though.
Tom Anderson
A: 

If your container is EJB-aware, or if you are using spring, you can request a EntityManagerFactory.

@PersistenceUnit private EntityManagerFactory emf;

Another option is to use Spring or any other IoC to inject EntityManagerFactory or EntityManager (with the correct scoping).

EMF is thread safe, so you can share an instance across an entire application. No need to recreate one for each operation. EM (EntityManager) is not thread safe so unless you want to do synchronization (you don't) by "definition" it is not reusable.

Take a look at the link below, it provides good information on the subject. https://blueprints.dev.java.net/bpcatalog/ee5/persistence/webonlyapp.html

IMHO the best way is to use an IoC to take care of the injection of the EntityManager and/or EntityManagerFactory.

Miguel Ping