开发者

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 using Expression.Equals, using the same ParameterExpression you've just created.
  • Combine the equality expressions with multiple calls to Expression.AndAlso
  • Call Expression.Lambda at the very end to create an Expression<Func<T, bool>>
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜