I have a thorny question about transforming Linq Expressions. I had a good search about, but I couldn't find anything that seems to cover this case. I'm reasonably familiar with Linq, at least in terms of creating and passing lambdas to methods, but I'm somewhat weaker on the Expression stuff.
First, some context: I have a generic persistence solution based on NHibernate used inside a number of DDD-ish projects. For special cases where a given collection of children within an aggregate could be essentially infinite (ie very large indeed), I cannot simply map a set or bag as it would never be acceptable for the entire collection to be loaded into memory. In this architecture it's not possible for code consuming the API to talk to the Repository directly to do a query or limit the results that way. I could of course not have a collection in the API at all and expose methods to retrieve relevant subsets of child objects instead (and if this doesn't work that's what I'll do), but I'm trying to do something slightly different and I've almost got it working...
These projects are being mapped with Fluent (not auto-mapping), and so I added a method to my base map class in the form
HasManyQueryable<TCollection>(Expression<Func<T, IQueryable<TCollection>>> memberExpression, Expression<Func<T, TCollection, bool>> selector)
This method derives the relevant PropertyInfo
from the first Expression
(which specifies the member to map). The selector Expression
contains the relationship between the parent and child objects as a substitute for a normal NHibernate mapping.
So, suppose I have a selector in the map for a domain type User
(which is T
above):
HasManyQueryable<Transaction>(x => x.Transactions, (u, t) => t.User == u);
This specifies a mapping between the subset of all Transactions
where Transaction.User
is the supplied User
u, and the User.Transactions
property which is IQueryable<Transaction>
. When an actual User
object is constructed, I need to turn this into
Expression<Func<Transaction, bool>> expression = (t => t.User == this)
where this
is the User
object being constructed. In other words, I want to take a general rule that says how to map Users
to Transactions
and turn it into a rule about mapping this User
to Transactions
. I can then use this expression to generate an IQueryable<Transaction>
from the Repository by doing a Linq query, thus:
return Repository.For<Transaction>().Where(selector);
This can only work when the selector is Func<Transaction, bool>
, hence my ultimate need is to turn the original expression, which would generate a Func<User, Transaction, bool>
into Func<Transaction, bool>
.
This gives me an IQueryable
collection where all the query operations are being done as Linq-to-NHibernate queries and thus the entire collection never gets loaded into memory (yes, I know you could frame a query that would actually make it do that, but I can catch those at code review time).
Phew. Hope that makes sense.
Anyone with leet Expression re-writing skills able to point me in the right direction?