views:

1975

answers:

5

I'm in the processes of changing my DAO layer from using Hibernate API to using a pure JPA API implementation. It looks like the recommended method is to use the createNamedQuery from the entity manager. The named queries are stored in annotations in the model/entity classes. This just not makes sense to me. Why would you define the JPA Queries in the model objects but use them in the DAOs. Wouldn't it make more sense to just use createQuery from within the DAO itself and define the queries in the DAO or even just define the named queries in the DAO itself?

For those of you that have implemented your DAO layer using the JPA API how have you defined your queries?

+3  A: 

I use named queries.

There are two reasons to do so:

  1. It puts them in a more central place rather than scattered in code with random createQuery() calls; and
  2. Build processes can validate the queries (really useful).
cletus
Why should the central location be the model object vs the DAO that is actually using it?
Ruggs
I forgot to mention that these named queries I typically put on the entity. If the query crosses several entities you just pick the one most relevant.
cletus
A: 

I had experience completely opposite to the one of cletus - I found no benefit and also found them awkward to use. Trivial queries would make no difference where to define, but non-trivial queries are usually hard to associate with any single entity but easy with business-oriented method.

If you use more or less sophisticated infrastructure in DAOs (for re-use and consistency) then usage of named queries tend to complicate both implementation and readability with no apparent benefit to offer.

Validating of queries by build process sounds interesting - I would like to know more what it really means... My queries leave little margin for error since every DAO method is unit tested as much as it makes sense.

grigory
I am also finding them awkward which is why I'm proposing the questions. Having a central place for queries makes sense for maintainability however I don't know if putting them in the model object makes sense. If I'm maintaining a DAO I first go to the DAO method that needs to be updated, now I have to go to the model object just to begin to look at the query.
Ruggs
The validation is actually quite nice. I use eclipse for my development and when I wrote a couple of queries I left the AS keyword off and I received errors during the build.
Ruggs
I should add that I don't normally use them for trivial queries (eg "select p from Party p where name = :name"), just more complicated queries.
cletus
+1  A: 

Don't just use named queries everywhere, there are cases where they are not appropriate, such as when its gonna be rarely used queries then it may be more efficient when built on as needed basis.

Named queries make more sense when its gonna be complex and got executed frequently.

[Updated]

You can write the named queries at mapping, instead.

Adeel Ansari
Why would the frequency of the query executed make it a better candidate for being a named query.
Ruggs
The named queries are parsed once and used forever. So, that if we write a wrong query it throws an exception right away. The queries that you build in code are parsed all the time unless cached.
Adeel Ansari
By the way, given link suggests the same. http://www.oracle.com/technology/products/ias/toplink/doc/1013/main/_html/qryun008.htm
Adeel Ansari
+2  A: 

You could take a look at project Hades. It allows you to simply define an interface and execute queries without the need to implement the execution manually.

Entity:

@Entity
@NamedQuery(id="User.findByLastname" query="from User u where u.lastname = ?1")
public class User implements Persistable<Long> {

  @Id
  private Long id;
  private String username;
  private String lastname;
  private int age;
}

DAO:

public interface UserDao extends GenericDao<User, Long> {

  // Will trigger the NamedQuery due to a naming convention
  List<User> findByLastname(String lastname);

  // Will create a query from the methodname
  // from User u where u.username = ?
  User findByUsername(String username);

  // Uses query annotated to the finder method in case you
  // don't want to pollute entity with query info
  @Query("from User u where u.age > ?1")
  List<User> findByAgeGreaterThan(int age);
}

Setup:

EntityManager em = Persistence.getEntityManagerFactory().createEntityManager();
GenericDaoFactory factory = GenericDaoFactory.create(em);

UserDao dao = factory.getDao(UserDao.class);

As you see you can choose between different ways to derive the query to be executed from the method. While deriving it directly from the method name is feasible for simple queries you'd probably choose between the @NamedQuery (JPA standard) or @Query (Hades annotation) dependening on how much you like to stick with standards.

Hades gives you support in various other corners of data access layer implementation, allows providing custom implementations for methods and nicely integrates with Spring.

Oliver Gierke
The question is about JPA solutions, not which persistence API to use.
Jim Barrows
The question is "For those of you that have implemented your DAO layer using the JPA API how have you defined your queries?" and I just wanted to point out a feasible solution. Hades provides a more accessible alternative to using the plain EntityManager and is based on plain JPA, so I don't get your point really.
Oliver Gierke
I think Oliver's answer and reasoning is well justified. I personally think that his example of Hades is very interesting and does answer to the question. Actually, I think I'll have a deeper glance at the framework... :)
Tuukka Mustonen
A: 

Embrace the power of and :) If you have a query that makes sense to put into the model, do so. If you don't, don't. It might be even better to ask "Why are you writing DAO's with JPS?" If the answer is to "Isolate my code from the database." This is done by the library implementing JPA. If the answer is "to isolate my code from changes to the way I persist things", then JPA does that by allowing you to have different implementations. I use query objects for complex queries, and still used named queries where possible, and I like the fact that named queries get compiled, and so I find bugs in them that much faster. I have no DAO layer.

Jim Barrows