Showing posts with label hibernate. Show all posts
Showing posts with label hibernate. Show all posts

2008-03-11

A NamedQuery a day keeps the RuntimeExceptions away

Getting your queries right takes some work; and if you get them wrong, you'll get exceptions at runtime, right?

Wrong. Using named queries means that (at least with sensible persistence engines) that your queries are parsed at startup time (technically when the persistence engine is instantiated). Your application fails early, and that is a good thing.

There is a further idea lurking below, so read on!

Consider the following code (Spring-/Hibernate-y, but the principle is general):

public User findUserByName(String username) {
return (User)getHibernateTemplate().find("select from User u where u.username = '" + username + "'");
}

Leaving aside the obvious stupidity of using string concatenation to construct queries (can you say "SQL injection"?), there is a further problem here.

Look at the User class:

@Entity
public class User {
@Id @GeneratedValue public Long id;
public String userName;
}

Spot the problem.

The above query will fail at runtime, with an error message along the lines of "failed to find property username of User"; the capitalization is wrong.

Of course, you will catch this during testing. You will, right? Right?

But why not let the engine catch it for you?

@Entity
@NamedQuery(name="User.byName", query="select from User u where u.userName = :username")
public class User {
@Id @GeneratedValue public Long id;
public String userName;
}

Any errors in the query will be reported at startup time. However, we introduce another failure point: What if you mistype the query name when using it? Or, for that matter, when defining it - I've done both?

public User findUserByName(String username) {
return (User)getHibernateTemplate().findByNamedQueryAndNamedParam("User.byname", "username", username);
}

But we have a compiler; introduce a constant and let it do the work for us!

@Entity
@NamedQuery(name=User.BY_NAME, query="select from User u where u.userName = :username")
public class User {
public static final String BY_NAME = "User.byName";
@Id @GeneratedValue public Long id;
public String userName;
}

public User findUserByName(String username) {
return (User)getHibernateTemplate().findByNamedQueryAndNamedParam(User.BY_NAME, "username", username);
}

End of problem.

Of course, you still have to remember how many parameters a query takes and what their names are. If I come up with a solution, you'll be the first to know.

2007-10-18

Generics makes DAOs easy

We've all been there. You're developing a medium-to-large application that uses a POJO persistence engine such as Hibernate. Good software design advocates that you have a DAO for each type of POJO, so off you go writing some. But after five–ten iterations of writing CRUD methods, it gets boring, doesn't it?

Here's how to make it easy.


Assumptions


This article uses generics; generics are supported starting with Java 5. My examples use classes from the Spring framework and assume that you're using Hibernate as your persistence engine, but the techniques illustrated should be applicable to other setups.

The interface

The standard DAO

Every DAO should support the basic CRUD methods:
  • Create
  • Retrieve
  • Update
  • Destroy
I tend to have three methods:

save
Saves an object, updating if it is already present; this handles C and U.

get
Fetches an object by id; this handles R.

remove
Deletes an object from the persistent store; this handles D.

In addition, I like to define methods to remove an object by its id, load all objects of the type, and to reassociate an object with the persistence layer. This last method is useful in an MVC environment, where your persistent object may make several round-trips to the view layer before you're done. So we end up with the following interface:
 public interface BaseDAO {
void save(Object o);

Object get(Serializable id);

void remove(Object o);

void remove(Serializable id);

List loadAll();

void reassociate(Object o);
}

The generic DAO interface, version 1

Adding generics

Notice all the Object references in that interface? That's not very modern, and it means that we have to litter our code with potentially unsafe casts. Let's add some generics.
 public interface BaseDAO<T> {
void save(T o);

T get(Serializable id);

void remove(T o);

void remove(Serializable id);

List<T> loadAll();

void reassociate(T o);
}

The generic DAO interface, version 2

A concrete DAO

With this interface defined, we can define a concrete DAO interface for the fictitious Order class:

 public interface OrderDAO extends BaseDAO<Order> { }

The OrderDAO interface

Yes, that is all there is to it. This interface now has methods to do CRUD operations on Order objects, with compile-time type safety.

The implementation

Implementing the generic DAO

The implementation of the generic DAO is straightforward:

 public abstract class BaseDAOHibernate<T>
extends HibernateDaoSupport
implements BaseDAO<T> {
public void save(T object) {
getHibernateTemplate().saveOrUpdate(object);
}

public T get(Serializable id) {
return getModelClass().cast(getHibernateTemplate().get(getModelClass(), id));
}

public void remove(T object) {
getHibernateTemplate().delete(object);
}

public void remove(Serializable id) {
remove(get(id));
}

@SuppressWarnings("unchecked")
public List<T> loadAll() {
return getHibernateTemplate().loadAll(getModelClass());
}

public void reassociate(T object) {
getHibernateTemplate().lock(object, LockMode.NONE);
}

protected abstract Class<T> getModelClass();
}

Implementing BaseDAO

I added the @SuppressWarnings annotation to get rid of a compiler warning about an unchecked cast.

Implementing OrderDAO

Now comes the reason for doing all this:

 public class OrderDAOHibernate
extends BaseDAOHibernate<Order>
implements OrderDAO {
protected Class<Order> getModelClass() {
return Order.class;
}
}


Implementing OrderDAO

And there you have it, a complete DAO for Order objects in seven neatly-formatted lines of code.

Conclusion

Generics can be a difficult subject to grasp, but when the benefits are as major as shown here, it is well worth the effort to get to grips with it.

Writing less code is always a big win. Not only is there less work to do (meaning that you get to go home early), but it is easier to debug the code that is present.