Linq to SQL DynamicInvoke(System.Object [])'没有支持的SQL转换

Eva*_*gle 8 c# lambda linq-to-sql

我有一个班级,用户.

用户具有UserId属性.

我有一个看起来像这样的方法:

static IQueryable<User> FilterById(this IQueryable<User> p, Func<int, bool> sel)
{
   return p.Where(m => sel(m.UserId));
}
Run Code Online (Sandbox Code Playgroud)

当我调用函数时,不可避免地:

var users = Users.FilterById(m => m > 10);
Run Code Online (Sandbox Code Playgroud)

我得到以下异常:

方法'System.Object DynamicInvoke(System.Object [])'没有支持的SQL转换.

有没有解决这个问题的方法?Expression.KillMeAndMyFamily()的兔子洞可能需要走多远?

为了澄清我为什么这样做:我使用T4模板自动生成一个简单的存储库和一个管道系统.在管道内,而不是写:

new UserPipe().Where(m => m.UserId > 10 && m.UserName.Contains("oo") && m.LastName == "Wee");
Run Code Online (Sandbox Code Playgroud)

我想生成类似的东西:

new UserPipe()
  .UserId(m => m > 10)
  .UserName(m => m.Contains("oo"))
  .LastName("Wee");
Run Code Online (Sandbox Code Playgroud)

dtb*_*dtb 15

我们UserId以此为例.你想写:

new UserPipe().UserId(uid => uid > 10);
Run Code Online (Sandbox Code Playgroud)

并希望它与以下相同:

new UserPipe().Where(user => user.UserID > 10);
Run Code Online (Sandbox Code Playgroud)

您需要做的是获取第一个版本的表达式树并将其转换为第二个版本.


因此,首先更改签名UserId以接受表达式树而不是编译的lambda:

public static IQueryable<User> UserId(
    IQueryable<User> source, Expression<Func<int, bool>> predicate)
Run Code Online (Sandbox Code Playgroud)

然后,编写一个将第一个表达式树转换为第二个版本的方法.我们来看看两个表达式树:

输入:

        Lambda
         uid
          |
       BinaryOp
          >
    /            \
Parameter     Constant
   uid           10

输出:

         Lambda
          user
            |
        BinaryOp
            >
     /            \
 Property         Constant
  UserID             10
     | 
Parameter
   user

正如你所看到的,所有你需要做的就是把拉姆达的身体,递归来替换参数的所有匹配uid与性能UserId的参数user,并创建与转化体和参数的新lambda表达式user.

您可以使用ExpressionVisitor进行替换.