How should EntityManager be used in a nicely decoupled service layer and data access layer?
Asked Answered
C

3

12

Somewhat related to my other question Should raw Hibernate annotated POJO's be returned from the Data Access Layer, or Interfaces instead? , I am experienced in creation of nicely decoupled layers, but not using Hibernate or J2EE/JPA. I have been looking at documentation and tutorials, and am puzzled about how to use the EntityManger in an elegant way, as it seems it is responsible for both transactions (which I want to do at my service layer) and persistance methods (which I want to keep in the data access layer). Should I create it at the service layer and inject it into the data access layer, or is there a better way? The below pseudo-java shows roughly what I'm thinking of doing.

EDIT: My pseudocode below is essentially taken from the hibernate JPA tutorial and modified for the layer separation and does not reflect that the product is being developed to run in an EJB container (Glassfish). In your answers please give best practices and code examples for code running in Glassfish or equivalent.

MyService
{

  setup()
  {
       EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory( "Something" ); //is the String you pass in important?
       entityManager = entityManagerFactory.createEntityManager();
  }

  myServiceMethod()
   {
   entityManager.getTransaction().begin();
   MyDao.setEntityManager(entityManagerFactory); 
   MyDao.doSomething();
   MyDao.doSomethingElse();
   entityManager.getTransaction().commit();
   entityManager.close();
   }
 }

MyDao
{
   doSomething()
    {
     entityManager.persist(...); //etc 
    }

}
Countrybred answered 21/10, 2011 at 23:30 Comment(2)
I see that you're not using the JTA - is it on purpose? You're creating your entity manager by hand and use the resource-level transactions. Are you on the Tomcat or Java EE server?Macromolecule
@PedroKowalski i essentially stole that code from the Hibernate tutorial. The app actually will run in Glassfish. I will edit the question to ask for help on that as well :)Countrybred
N
13

First off, whether you should use a DAO layer or not is a debate that has been around since the appearance of JPA and the EntityManager which many people consider a DAO itself. The answer to this depends on the type of application you are developing, but in most of the cases you will want to:

  • Use JPA criteria or custom queries. In this case you probably don't want to mix your business logic with your query creation. This would lead to large methods and would violate the single responsibility principle.
  • Reuse your JPA code as much as possible. Say you create a criteria query that retrieves a list of employees whose age is between 40 and 65 and have been working in the company for longer than 10 years. You might want to reuse this type of query somewhere else in your service layer, and if that is the case, having it in a service would make this task difficult.

That being said, if all you have in your application is CRUD operations and you don't think you might need to reuse any JPA code, a DAO layer is probably something overkill as it will act as a mere wrapper of the EntityManager, which doesn't sound right.

Secondly, I would advise to use container managed transactions whenever possible. In case you are using an EJB container like TomEE or JBoss this would avoid a large amount of code dedicated to programmatically create and manage transactions.

In the case you are using en EJB container, you can take advantage of declarative transaction management. An example of this using DAOs would be to create your service layer components as EJBs and your DAOs too.

@Stateless
public class CustomerService {

    @EJB
    CustomerDao customerDao;

    public Long save(Customer customer) {

        // Business logic here
        return customerDao.save(customer);
    }
}

@Stateless
public class CustomerDao {

    @PersistenceContext(unitName = "unit")
    EntityManager em;

    public Long save(Customer customer) {
        em.persist(customer);
        return customer.getId();
    }

    public Customer readCustomer(Long id) {
            // Criteria query built here
    }

}

In the example above, default transaction configuration is REQUIRED, which means that in absence of a transaction in the caller component, the EJB will create a new transaction. If the caller already creates a transaction (CustomerService) the component being called (CustomerDao) inherits the transaction. This can be customized using the @TransactionAttribute annotation.

If you are not using an EJB container, I think your example above would be probably equivalent.

EDITED: for the sake of simplicity I have used no-interface EJBs above, but it would be a good practice to use an interface for those in order to make them e.g. more testable.

Noeminoesis answered 22/10, 2011 at 15:0 Comment(3)
This will run in GlassFish, so I will edit the question to be explicit on that. Your example code assumes an EJB container, yes?Countrybred
Yes. The code above assumes a JEE compliant container, which Glassfish actually is.Noeminoesis
I would opt for this solution then, so Gonzalo - you have my axe... vote I mean :-). You could modify it a bit to provide your service with CRUD operations (i.e. create GenericCRUDService). Then some of your services which are plainly CRUD-based won't have any specific DAO and if the services would need to reuse some complicated queries, than these can be defined in separated class, as Gonzalo shown, or treated as DDD Repository.Macromolecule
D
2

Typically, you would want to isolate any persistence code to your DAO layer. So service layer should not even know about EntityManager. I think it's ok if DAO layer returns annotated pojos since they remain pojos still.

For the transaction management, I suggest that you look at Spring ORM. But if you choose not to use Spring or other AOP solution, you can always expose transaction related methods via your DAO so you call them from the service layer. Doing so will make your life much harder but the choice is yours...

Delve answered 22/10, 2011 at 8:17 Comment(2)
Isn't the EntityManager already a DAO? It gives you the nice CRUD interface and is database-agnostic.Macromolecule
I would love to use Spring but not an option for this project. Exposing transaction logic as DAO methods seems just wrong - perhaps you could clarify with a code example.Countrybred
C
0

For simple cases like getItem(), getEmployee() etc, better inject the entitymanager directly to the Service layer use in a method instead of Service method calling a Dao (which has entity manager inject into it) method which user entitymanager to return the object. This is overkill and the DAO simply acts as wrapper. For complex business logic involving queries and criterias, let the service method call Dao which talks tot eh DB.

Catholicity answered 3/2, 2016 at 18:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.