Thursday, August 6, 2009

Hibernate query filter vs load/get

ETaxi project uses Hibernate as JPA provider (which means nothing surprising :) ). We are using Hibernate Query Filters, one nuance of which I'm going to discuss here, so at first some short information about them

Query Filter comprises of filter definition declaring filter name and parameters , filter metainformation for an entity defining what SQL string will be appended to where clauses of queries for the entity, and code that enables filter by invoking

Filter filter = session.enableFilter("filterName") ;
filter.setParameter("key1", value1);
filter.setParameter("keyN", valueN);

The purpose of using them is to make our life a bit easier. Our application has multiple working areas each of which should be accessible only by corresponding customer. So customer specific entities are filtered by default, and we don't need to put customer id explicitly into the list of our DAO method parameters. For example, I mean method which should look like:

public interface DriverDao {
public List findAll(Customer customer);

Looks instead as:

public interface DriverDao {
public List findAll();

Thus when filters are off it is possible to retrieve all drivers, when on - only those belonging to current customer. The benefits we have from using filters are - shorter queries, less parameters for dao methods, it's harder to forget to include filtering by customer to some query (and have one customer see other customer drivers/users/orders etc, which means very angry customers)

But there is at least one annoying 'But', query filters don't apply to results of Session.get() and Session.load() methods (which try to locate objects in cache before querying database), so when you want filters to work you need to use a query finding entities by id instead of get/load methods - and now you have your session cache not working on simple entity find by id!

Today after analyzing one of the typical requests to our app I discovered that current user is queried 5 times during it! Sure this partially can be helped by redesigning user searches inside application, but in this way we loose one of the benefits of Hibernate (because we are trying to use the other one consistently)

Till recently I even have not understood why this is made so that load()/get() can not make use of filters, but it is now clear to: suppose you turned filter off and loaded some entity which normally should be filtered, than turned filter on and try to load() that entity by id. How can simple cache search know should particular entity be filtered or not? (considering that applied filter is only a piece of SQL that is appended to queries, probably containing parameters that are also filled when preparing JDBC statement)

So query filters turned to be one of those Hibernate features that should be paid for and for which is hard to predict in what way you will have to pay (if you don't have some experience using). I wish this post will help someone make more conscious decision about whether or not to use them

1 comment:

  1. Excellent appreciation.

    Thanks for the post.

    It helped me a lot.