views:

480

answers:

2

Using Castle ActiveRecord / NHibernate: Is there a way you can force an ICriterion on all queries on a table?

For example, a good amount of of my tables have a "UserId" column. I might want to ensure that I am always selecting rows for the logged in user. I can easily create an ICriterion object, but I am forced to supply it for different methods: FindAll(), FindFirst(), FindLast() etc.

Is there a way to force a WHERE clause on all queries to a Castle ActiveRecord?

+1  A: 

The closest thing would be using filters. See http://ayende.com/Blog/archive/2009/05/04/nhibernate-filters.aspx

Mauricio Scheffer
This seems to be a good solution, however I cannot figure out if its possible to use these filters with Castle ActiveRecord.
mbp
http://groups.google.com/group/castle-project-devel/browse_thread/thread/ce94f492615e0d52/c721a7abb0a1f1a7 I don't think this was ever implemented... you'll have get the current ISession and enable the filters yourself
Mauricio Scheffer
IIRC you can get the current ISession from ActiveRecordMediator.GetSessionFactoryHolder().CreateSession(typeof(ActiveRecordBase))
Mauricio Scheffer
Enabling the filter seems possible, but how to create one is more of a problem.
mbp
+2  A: 

I finally found a great solution (using filters). Since Castle AR does not have any native API for mapping to NHibernate filters, this part was pretty much undocumented. So here goes.

This example filter, will make sure you will never get news more than a year old, no matter what kind of query you use on the ActiveRecord. You can probably think of more practical applications for this.

First, create an ActiveRecord "News".

Use the following code before you initialize ActiveRecordStarter.

ActiveRecordStarter.MappingRegisteredInConfiguration += MappingRegisteredInConfiguration;
Castle.ActiveRecord.Framework.InterceptorFactory.Create = () => { return new EnableFiltersInterceptor(); };

Then, add the missing function and class:

void MappingRegisteredInConfiguration(Castle.ActiveRecord.Framework.ISessionFactoryHolder holder)
{
    var cfg = holder.GetConfiguration(typeof (ActiveRecordBase));

    var typeParameters = new Dictionary<string, IType>
                                  {
                                    {"AsOfDate", NHibernateUtil.DateTime}
                                  };

    cfg.AddFilterDefinition(new FilterDefinition("Latest", "", typeParameters));

    var mappings = cfg.CreateMappings(Dialect.GetDialect(cfg.Properties));

    var newsMapping = cfg.GetClassMapping(typeof (News));
    newsMapping.AddFilter("Latest", ":AsOfDate <= Date");
}


public class EnableFiltersInterceptor : EmptyInterceptor
{
    public override void SetSession(ISession session)
    {
        session.EnableFilter("Latest").SetParameter("AsOfDate", DateTime.Now.AddYears(-1));
    }
}

And voila! Queries on News, e.g. FindAll(), DeleteAll(), FindOne(), Exists(), etc. will never touch entries more than a year old.

mbp