4

假设,我们有下一个代码:

public class Dto
{
  public int Id;
  public string Name;
}    

...

using (var db = new NorthwindDataContext())
{
  var q = from boss in db.Employees
          from grunt in db.Employees.Where(p => p.ReportsTo == boss.EmployeeID).DefaultIfEmpty()
          select new Dto { Id = boss.EmployeeID, Name = grunt.FirstName };
}

我想将选择器提取为表达式并将其存储在另一个地方。在方法语法中,它将如下所示:

Expression<Func<Employee, Employee, Dto>> selector = (boss, grunt) => new Dto
{
  Id = boss.EmployeeID, Name = grunt.FirstName
};

using (var db = new NorthwindDataContext())
{
  var q = db.Employees.SelectMany(boss => db.Employees.Where(p => p.ReportsTo == boss.EmployeeID).DefaultIfEmpty(), selector);
}

是否可以将此 LinqToSql 方法链转换为保持 Expression 变量就地的查询语法?

升级版:

为了澄清我的问题,我使用 DefaultIfEmpty 进行左连接,它是相等查询的一种简短形式:

using (var db = new NorthwindDataContext())
{
  var q = from boss in db.Employees
          join stub in db.Employees on boss.EmployeeID equals stub.ReportsTo into stubi
          from grunt in stubi.DefaultIfEmpty()
          select new Dto { Id = boss.EmployeeID, Name = grunt.FirstName };
}

它可以正常工作,因为它使用内联表达式进行编译。null当没有对应的 时,它分配给 Name 字段grunt。但是如果用调用外部映射器方法重写这个查询,它将被编译为方法调用,这将得到可为空grunt的参数,并会导致 NullReferenceException:

public static Dto GetDto(Employee boss, Employee grunt)
{
  return new Dto
    {
      Id = boss.EmployeeID,
      Name = grunt.FirstName
    };
}

using (var db = new NorthwindDataContext())
{
  var q = from boss in db.Employees
          join stub in db.Employees on boss.EmployeeID equals stub.ReportsTo into stubi
          from grunt in stubi.DefaultIfEmpty()
          select GetDto(boss, grunt);
}

当然,我可以在映射器方法中添加空检查,但我在 DAL 中试图实现的是将选择器提取到映射器类中,并可能在那里省略空检查。

4

2 回答 2

0

您不能总是使用查询语法,在某些情况下您只能使用方法链来表达计算。在这种特定情况下,如果谓词是内联的,则查询语法将在幕后引入 lambda,但是您将其放入变量中,因此您无法指定应如何使用该变量,就像使用 lambda 一样,支持通过查询语法。

于 2012-10-23T10:23:42.923 回答
0

我不确定你为什么需要Expression- 只需使用Func. 这应该有效:

Func<Employee, Employee, Dto> selector = (boss, grunt) => new Dto 
{ 
Id = boss.EmployeeID, Name = grunt.FirstName 
}; 

using (var db = new NorthwindDataContext()) 
{ 
var q = from boss in db.Employees 
        from grunt in db.Employees.Where(p => p.ReportsTo == boss.EmployeeID).DefaultIfEmpty() 
        select selector(boss, grunt)
} 
于 2012-10-23T09:22:53.937 回答