1

我为自己创建了一个 ExpressionBuilder 类,它可以帮助我在执行 Linq to Sql 查询时将可用作谓词的表达式组合在一起。它工作得很好。但是,我刚刚发现表达式只能用于过滤表,而不是实体集?为什么会这样?

例如,如果我有公司和有薪水的员工。我可以创建这两个表达式:

Expression<Func<Company, bool>> cp = x => x.Name.StartsWith("Micro");
Expression<Func<Employee, bool>> ep = x => x.Name.StartsWith("John");

然后我希望能够执行以下操作,但是它仅部分有效:

var companies = dataContext.Companies
    .Where(cp)                                // Goes fine
    .Select(x => new 
        {
            x.Name,
            SumOfSalaries = x.Employees
                .Where(ep)                    // Causes compile-time error
                .Sum(y => y.Salary),
        }
    .ToList();

此外,如果我执行ep.Compile()它会编译,但是在运行查询时会出现错误。

为什么会这样?我错过了什么吗?我觉得这不合逻辑。我能以某种方式解决这个问题吗?或者你有什么好的解决方法?

我知道在这种情况下我可以Where(x => x.Name.StartsWith("John"))改用,但问题是我需要的表达式并不是那么微不足道。它们是较长的AndAlsos 和OrElses 字符串。

4

3 回答 3

0

以下对我有用 - 注意两者都是编译的:

var companies = dataContext.Companies.Where(cp.Compile())
                .Select(x => new
                                 {
                                     x.Name,
                                     SumOfSalaries = x.Employees
                                        .Where( ep.Compile() )
                                        .Sum(y => y.Salary),
                                 }

                 ).ToList();

当您输入第二个 where 子句时,表达式解析器似乎在第一个 where 子句之后的某处丢失了类型信息。老实说,我还不确定为什么。

编辑:要清楚,我明白EntitySet 不支持将表达式传递到 where 子句。我不完全理解的是为什么当你添加 Where(ep.Compile()) 时它会失败。
我的理论是,在编译第一个 where (Where(cp.Compile()) 时,Linq2Sql 退出解析表达式 - 它无法针对实体集解析 ep.Compile(),并且无法决定分解查询成两个,直到你编译第一个 where 子句。

于 2009-09-30T14:48:27.350 回答
0

如果您要将 lambda 表达式传递给 LINQ to SQL 提供程序,请不要将其创建为Expression<T>- 让提供程序为您执行此操作。

于 2009-09-30T13:55:01.043 回答
0

我认为你需要重写你的查询。另一种询问您想要的详细信息的方法是:“给我所选公司中所选员工的工资总和,按公司名称组织”。

因此,以员工工资为重点,我们可以这样写:

    //Expression<Func<Employee, bool>> ep = x => x.Name.StartsWith("John");
    //Expression<Func<Company, bool>> cp = x => x.Name.StartsWith("Micro");

    Expression<Func<Employee, bool>> ep = x => x.Name.StartsWith("John");
    Expression<Func<Employee, bool>> cp = x => x.Company.Name.StartsWith("Micro");

    var salaryByCompany = dataContext.Employees
        .Where(ep)
        .Where(cp)
        .GroupBy(employee => employee.Company.Name)
        .Select(companyEmployees => new
                                        {
                                            Name = companyEmployees.Key,
                                            SumOfSalaries = companyEmployees.Sum(employee => employee.Salary)
                                        });

    var companies = salaryByCompany.ToList();
于 2009-10-12T12:39:58.700 回答