Thursday, 21 January 2010

Enabling Filters on mapped entities

I was trying to figure out if I could persuade NHibernate to enable filters on my <many-to-one /> entities and i fell on this discussion on the nhibernate-development google group. In short, <many-to-one /> filters should not work because filters where designed to filter data, not modify the domain.A valid viewpoint but i needed that functionality.

I have to think that filters should work out-of-the box and the developer should be responsible of enabling or disabling them. The reason is that i have a setup, that the represented domain can only reflected using filters. That is, applying WHERE clauses with dynamic parameters that are generated from the UI and that parameters remain the same for the length of the Request. As such the WHERE attribute on the class

Digging up the NH 2.1.2 source code i've found the single piece of code that is responsible for the behaviour.
Open up the NHibernate.Loader.Entity.EntityJoinWalker class and at approximately line 24 exists this piece of code:

SqlStringBuilder whereCondition = WhereString(Alias, uniqueKey, batchSize)
      //include the discriminator and class-level where, but not filters
      .Add(persister.FilterFragment(Alias, new CollectionHelper.EmptyMapClass<string, IFilter>()));
if you change it to

SqlStringBuilder whereCondition = WhereString(Alias, uniqueKey, batchSize)
       .Add(persister.FilterFragment(Alias, enabledFilters));

any enabled filters will be applied to your <many-to-one /> mapped entities as long as the filter exists on the entity definition mapping.

This little modification additionally enables filters for ISession.Get() and it works normally with lazy loading. If you are going to use ISession.Get() note that the cache is hit first before going to the datastore. In my setup, because the filter parameter defines a different entity instance for a given entity-id the second-level cache is not (and must not) be used, so take that into consideration before applying the modification to your solution.

I am thinking that if we could pass a parameter on the WHERE attribute on the class mapping (and ensure that this where fragment is used on ANSI-joins) none of this would have a reason to exist

No comments:

Post a Comment