views:

38

answers:

1

I'm building a repository layer for nhibernate, in which I have the following find method:

public IList<TEntity> Find(Expression<Func<TEntity, bool>> query)

I would like to add a condition to the query in that method. The extra condition should limit rows to all where RemovedAt is larger than DateTime.Now.

Explanation using SQL:

Let's assume that I have the following SQL query:

SELECT * FROM users WHERE first_name LIKE 'a%' OR last_name LIKE 'a%'

It would look like this after the modification:

SELECT * FROM users WHERE (first_name LIKE 'a%' OR last_name LIKE 'a%') AND created_at > '2010-09-22 19:31'

Can it be done on the linq query, or in nhibernate?

Edit

Sorry, forgot to mention that all entities do not have a RemovedAt method. The interface is declared as:

public interface IRepository<TEntity, TKey> where TEntity : class, new()

I'm changing CreatedAt/RemovedAt/UpdatedAt (in their respective methods) by looking for a property with that name and using reflection to update the value.

+1  A: 

First off, I am not sure why you just don't return IQueryable and let the user of the method determine if they want it as a List, etc. Because IQueryables are not executed until actually needed, you can keep adding to the expression tree until you actually need it.

In this case, when you change it to a List of objects, that is when the query will actually get executed against the databse when it is turned into a list.

If you really want to keep the interface as an IList instead of an IQueryable, just add an additional expression to the expression tree before you compile.

Since I have had limited work with the root level expression trees, I would likely give the syntax to you wrong, so here is a different type of example that may give you enough information as to what I am talking about:

var query = something.Where( n => n.FirstName.StartsWith("N")) ;
query = query.Where(n => n.created_at > DateTime.Now);
return query.ToList();

I hope that makes sense. You can just continue to add criteria to the expression tree until it gets compiled and executed.

I would still recommend passing arround IQueryable though, instead. In my example, you would just return the query instead of calling ToList first. It makes it easier for fluent syntax and will perform better with nHibernate because nHibernate will try to take all of the criteria into account before calling the database. If you only needed an aggragate or a count, for example, that would be handled at the database instead of pulling back all of the rows into a list and then iterating over it to get the aggregate or count.

Bytemaster
Exposing IQueryable would also expose lower level exceptions which I want to handle in the repository classes. Anyway, I'll let the service layer handle the RemovedAt filter instead.
jgauffin
For some additional abstraction; have a look at: http://code.google.com/p/linq-specifications/ this can give you a cleaner/more uniform approach to formulating the queries.
DanP