views:

178

answers:

4

I'm designing a new app based on JPA/Hibernate, Spring and Wicket. The distinction between the DAO and Service layers isn't that clear to me though. According to Wikipedia, DAO is

an object that provides an abstract interface to some type of database or persistence mechanism, providing some specific operations without exposing details of the database.

I was wondering whether a DAO could contain methods that don't really have to do much with data access, but are way easier executed using a query? For example "get a list of all airlines that operate on a certain set of airports"? It sounds to me to be more of a service-layer method, but I'm not sure if using JPA EntityManager in the service layer is an example of good practice?

A: 

Dao is a data access object. It does storing/updating/selecting entities on the database. The entity manager object is used for that (at least in open jpa). You can also run query's with this entity manager. It's no sql but JPQL (Java persistence query language).

Simple example:

emf = Persistence.createEntityManagerFactory("localDB");
em = emf.createEntityManager();

Query q = em.createQuery("select u from Users as u where u.username = :username", Users.class);
q.setParameter("username", username);

List<Users> results = q.getResultList();

em.close();
emf.close();
Mark Baijens
+2  A: 

One thing is certain: if you use EntityManager on the service layer, you don't need a dao layer (only one layer should know implementation details). Apart from that, there are different opinions:

  • Some say the EntityManager exposes all needed dao functionality, so they inject EntityManager in the service layer.
  • Others have a traditional dao layer backed by interfaces (so the service layer is not tied to implementation details).

The second approach is more elegant when it comes to separation of concerns and it also will make switching from one persistence technology to the other easier (you just have to re-implement the dao interfaces with the new technology), but if you know that nothing will change, the first is easier.

I'd say if you have a small project, use JPA in the service layer, but in a large project use a dedicated DAO layer.

seanizer
in your example the entity manager is your DAO
walnutmon
in the first example, yes
seanizer
+1. Indeed in larger projects the service layer should be persistence-mechanism agnostic.
Bozho
+2  A: 

A DAO should provide access to a single related source of data and, depending on how complicated your business model, will return either full fledged Business objects, or simple Data objects. Either way, the DAO methods should reflect the database somewhat closely.

A Service can provide a higher level interface to not only process your business objects, but to get access to them in the first place. If I get a business object from a Service, that object may be created from different databases (and different DAO's), it could be decorated with information made from an HTTP request. It may have certain business logic that converts several data objects into a single, robust, business object.

I generally create a DAO thinking that it will be used by anyone who is going to use that database, or set of business related data, it is literally the lowest level code besides triggers, functions and stored procedures within the database.

Answers to specific questions:

I was wondering whether a DAO could contain methods that don't really have to do much with data access, but are way easier executed using a query?

for most cases no, you would want your more complicated business logic in your service layer, the assembly of data from separate queries. However, if you're concerned about processing speed, a service layer may delegate an action to a DAO even though it breaks the beauty of the model, in much the same way that a C++ programmer may write assembler code to speed up certain actions.

It sounds to me to be more of a service-layer method, but I'm not sure if using JPA EntityManager in the service layer is an example of good practice?

If you're going to use your entity manager in your service, then think of the entity manager as your DAO, because that's exactly what it is. If you need to remove some redundant query building, don't do so in your service class, extract it into a class that utilized the entity manager and make that your DAO. If your use case is really simple, you could skip the service layer entirely and use your entity manager, or DAO in controllers because all your service is going to do is pass off calls to getAirplaneById() to the DAO's findAirplaneById()

UPDATE - To clarify with regard to the discussion below, using an entity manager in a service is likely not the best decision in most situations where there is also a DAO layer for various reasons highlighted in the comments. But in my opinion it would be perfectly reasonable given:

  1. The service needs to interact with different sets of data
  2. At least one set of data already has a DAO
  3. The service class resides in a module that requires some persistence which is simple enough to not warrant it's own DAO

example.

//some system that contains all our customers information
class PersonDao {
   findPersonBySSN( long ssn )
}

//some other system where we store pets
class PetDao {
   findPetsByAreaCode()
   findCatByFullName()
}

//some web portal your building has this service
class OurPortalPetLostAndFoundService {

   notifyOfLocalLostPets( Person p ) {
      Location l = ourPortalEntityManager.findSingle( PortalUser.class, p.getSSN() )
        .getOptions().getLocation();
      ... use other DAO's to get contact information and pets...
   }
}
walnutmon
thanks for such a detailed answer. i just wonder: would it be ok to both have a collection of DAO's and use EntityManager in the service layer?
John Manak
I don't think there is anything wrong with this, keep in mind what Bohzo said about service layer being persistence agnostic. If things become less than trivial, I'd just have a single DAO which uses the entity manager and deals with all entities. I've never found any use for the common pattern where a DAO is specific to an entity or a table, I think a DAO should be bound to a database, if the class becomes large, refactor when it's apparent what is redundant
walnutmon
ok. i've mostly seen DAO's that were tightly coupled with a single entity/table and thought uncoupling would be a breach of good practice. so the method getAirlinesOperatingFrom() in Qwerky's answer is fine?
John Manak
"would it be ok to both have a collection of DAO's and use EntityManager in the service layer?" - what would be the point of this? By using JPA in the service layer, you've defeated the purpose of having DAO interfaces which abstract away the choice of persistence technology - assuming of course this is your goal in having a DAO layer. If this abstraction is not a goal, then you don't really need to jump through the hoops of pretending to have a separate layer.
matt b
@matt b exactly!
seanizer
@John Manak - on the point of entities 1 to 1 with DAO's I respectfully disagree, though conventional wisdom does follow your methodology, I would point to DRY (don't repeat yourself), in practice you will have a lot of classes that perform simple CRUD operations on an entity, where that could be handled very easily by a simple generic method. I find class explosion to be a distraction. When you follow the single DAO for the database, you will begin to see as development evolves what it is that is redundant, and your DAO can be refactored organically.
walnutmon
@matt b - agreed mostly, but I think a Data Access layer is useful for more than being able to change persistence mechanisms - still, the point your making is valid and should definitely be considered before making this decision
walnutmon
My larger point though is that if you have your service layer using the EntityManager directly, then do you really even have a "data layer"? What is it being used for? In this case, it sounds like you wouldn't have two different layers with a clear boundary - but rather one amalgam of code doing similar things.
matt b
thanks a lot for your comments, it's becoming clearer for me. i really like the idea of the single DAO, but i'm still not sure how to implement those generic CRUD methods within it. could you please show me an example/share a link?
John Manak
i wrote a new question for that: http://stackoverflow.com/questions/3888575/single-dao-generic-crud-methods-jpa-hibernate-spring
John Manak
+1  A: 

Traditionally you would write interfaces that define the contract between your service layer and data layer. You then write implementations and these are your DAOs.

Back to your example. Assuming the relationship between Airport and Airline is many to many with a table containing airport_id and airline_id you might have an interface;

public interface AirportDAO
{
   public List<Airline> getAirlinesOperatingFrom(Set<Airport> airports);
}

..and you might provide a Hibernate implementation of this;

public class HibernateAirportDAO implements AirportDAO
{
   public List<Airline> getAirlinesOperatingFrom(Set<Airport> airports)
   {
      //implementation here using EntityManager.
   }
}

You could also look into having a List on your Airline entity and defining the relationship with a @ManyToMany JPA annotation. This would remove the necessity to have this particular DAO method altogether.

You might also want to look into the Abstract Factory pattern for writing DAO factories. For example;

public abstract class DAOFactory
{
   private static HibernateDAOFactory hdf = new HibernateDAOFactory();

   public abstract AirportDAO getAirlineDAO();

   public static DAOFactory getFactory()
   {
      //return a concrete implementation here, which implementation you
      //return might depend on some application configuration settings.
   }
}

public class HibernateDAOFactory extends DAOFactory
{
   private static EntityManagerFactory emFactory = Persistence.createEntityManagerFactory("myPersistenceUnit");

   public static EntityManager getEM()
   {
      return emFactory.createEntityManager();
   }

   public AirportDAO getAirportDAO()
   {
      return new HibernateAirportDAO();
   }
}

This pattern allows your HibernateDAOFactory to hold a single EMF and supply individual DAO instances with EMs. If you don't want to go down the fatory route then Spring is great at handling DAO instances for you with dependancy injection.

Edit: Clarified a couple of assumptions.

Qwerky
yes, but isn't that mixing of business/service and data access layers? i specifically mean getAirlinesOperatingFrom(). or is this good practice? it's my first project in this field, so i'm not very sure
John Manak
This Factory approach makes no sense in a Spring scenario.
seanizer
@seanizer Yeah, with Spring the OP probably wants to configure his DAOs as part of his app context and inject them.
Qwerky
@John Manak I assumed the relationship between Airline and Airport was in the data, eg a JPA @ManyToMany with a table containing airline_id and airport_id. If the relationship isn't in the data (eg have to call a webservice) then this method shouldn't be in the DAO.
Qwerky