Dynamically build an expression for calling the LINQ Where method
I'm using some code from a book to implement a generic repository class for EF data access. the code uses the following two methods to get a single entity by its int id
primary key, assuming all DB objects have an int PK. However, I am using an imported DB with mainly natural keys, and I wish to preserve all the FK relationships as they are, i.e. I don't want to redesign the DB to use single column int PK's.
How can I adapt the code below to work with multi-column keys?
protected Expression<Func<T, bool>> CreateGetExpression<T>开发者_运维技巧;(int id)
{
ParameterExpression e = Expression.Parameter(typeof(T), "e");
PropertyInfo propInfo = typeof(T).GetProperty(KeyPropertyName);
MemberExpression m = Expression.MakeMemberAccess(e, propInfo);
ConstantExpression c = Expression.Constant(id, typeof(int));
BinaryExpression b = Expression.Equal(m, c);
Expression<Func<T, bool>> lambda = Expression.Lambda<Func<T, bool>>(b, e);
return lambda;
}
public override T Get<T>(int id)
{
return List<T>().FirstOrDefault(CreateGetExpression<T>(id));
}
I want my Get
method to look like this:
public override T Get<T>(params object[] keyValues)
{
return List<T>().FirstOrDefault(CreateGetExpression<T>(keyValues));
}
Well, you basically need to build up an expression tree with multiple equality checks. You can take the code you've got for building a single equality check, and build up multiple ones, one for each key. Then you need to combine them using Expression.AndAlso
multiple times - so if you've got individual equality checks e1
, e2
and e3
you might use:
var e = Expression.AndAlso(Expression.AndAlso(e1, e2), e3);
One thing to note: you'll need to use a single ParameterExpression
for the whole final expression - so you'll need to adapt your "build a single check" method to take a ParameterExpression
as a parameter... and you don't need to use Expression.Lambda
until the very end. So the overall steps will be something like:
- Create a
ParameterExpression
- For each key, create a
BinaryExpression
usingExpression.Equals
, using the sameParameterExpression
you've just created. - Combine the equality expressions with multiple calls to
Expression.AndAlso
- Call
Expression.Lambda
at the very end to create anExpression<Func<T, bool>>
精彩评论