动态构建用于调用LINQ Where方法的表达式

时间:2010-10-16 07:18:59

标签: c# .net entity-framework

我正在使用书中的一些代码来实现EF数据访问的通用存储库类。假设所有DB对象都具有int PK,代码使用以下两种方法通过其int id主键获取单个实体。但是,我使用的是主要是自然键的导入数据库,我希望保留所有FK关系,即我不想重新设计数据库以使用单列int PK。

如何调整以下代码以使用多列密钥?

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));           
}

我希望我的Get方法看起来像这样:

public override T Get<T>(params object[] keyValues)
{
    return List<T>().FirstOrDefault(CreateGetExpression<T>(keyValues));           
}

1 个答案:

答案 0 :(得分:1)

好吧,你基本上需要构建一个带有多个相等性检查的表达式树。您可以获取用于构建单个相等性检查的代码,并构建多个代码,每个密钥对应一个。然后,您需要多次使用Expression.AndAlso将它们组合在一起 - 因此,如果您有个别等式检查e1e2e3,则可以使用:

var e = Expression.AndAlso(Expression.AndAlso(e1, e2), e3);

有一点需要注意:您需要使用 ParameterExpression作为整个最终表达式 - 所以您需要调整“构建单一检查”方法将ParameterExpression作为参数...并且在最后之前不需要使用Expression.Lambda。所以整体步骤将是:

  • 创建ParameterExpression
  • 对于每个密钥,使用BinaryExpression创建Expression.Equals,使用您刚刚创建的ParameterExpression
  • 将相等表达式与对Expression.AndAlso
  • 的多次调用相结合
  • 在最后致电Expression.Lambda以创建Expression<Func<T, bool>>