首页 > 解决方案 > 如何将 LINQ 表达式传递给返回 IQueryable 的函数

问题描述

我有一些方法可以作用于一个查询,一个是简单的 where 过滤器,另一个是带有要在 where 过滤器中使用的表达式的表达式,第三个也有一个表达式作为参数。

public static IQueryable<Employee> FilterExpression(this IQueryable<Employee> employees,
        Expression<Func<Employee, Boolean>> expression)
{
    return employees.Where(expression);
}

public static IQueryable<Employee> Active(this IQueryable<Employee> employees)
{
    return employees.Where(e => e.IsActive);
}

前两个执行良好,没有任何问题。

var active = db.Employees.Active().Take(5).ToList();
var activeExpression = db.Employees.Take(5).FilterExpression((e) => e.IsActive).ToList();

下一个在另一个扩展方法中被调用,该方法返回一个任务集合上的选择的委托。

public static Expression<Func<SpwTask, TaskView>> Tasks(this TaskService service)
{
    return (x) => new TaskView()
        {
            NotifyList = db.TaskContacts.JoinedEmployees
                  (t => t.TaskId == x.Id).Select(Projections.SimpleEmployees)
        };
}

public static IQueryable<Employee> JoinedEmployees(this IQueryable<TaskContact> contacts,
        Expression<Func<TaskContact, Boolean>> expression)
{
    var id = ServicesRoot.Company.Id;
    return from c in contacts.Where(expression)
           join e in db.Employees on c.EmployeeId equals e.Id
           where e.CompanyId == id
           select e;
}

调用代码如下所示

// db is the DbContext and the Tasks is the extension method
...
return db.Tasks.Select(this.Tasks()); 
... 

我得到的错误是这样的:

System.NotSupportedException:'LINQ to Entities 无法识别方法'System.Linq.IQueryable 1[SafetyPlus.Data.Models.Employee] JoinedEmployees(System.Linq.IQueryable1[SafetyPlus.Data.TaskContact],System.Linq.Expressions.Expression 1[System.Func2[SafetyPlus.Data.TaskContact,System.Boolean]])'方法,并且此方法不能翻译成商店表达式。

有没有办法解决这个问题?在其他类似的查询中重用它会非常好。看来这应该可行。

内联版本:

public static Expression<Func<SpwTask, TaskView>> Tasks(this TaskService service)
{
    return (x) => new TaskView()
        {
            NotifyList = 
                (from c in service.db.TaskContacts.
                where c.TaskId == x.Id
                join e in db.Employees on c.EmployeeId equals e.Id
                where e.CompanyId == id
                select e).Select(Projections.SimpleEmployees)
        };
}

当我运行查询的代码内联版本时,我得到一个生成的单个 SQL,它经过优化,是我想要的,但不可重用。

起初,我认为下面给出的 Compile() 解决方案是我需要的答案,但在查看 SQL Profiler 时,我意识到外部任务查询的每一行都在为每个任务运行一个查询,而不是单个查询对于整个数据集。这几乎违背了重用查询的目的。

标签: asp.net-mvcentity-frameworklinqlinq-to-sql

解决方案


您应该将其作为委托传递,而不在 Select 中调用它,并在使用前进行编译。

尝试这个: db.Tasks.Select(Tasks.Compile());


推荐阅读