Linq-to-SQL,传递Expression <func <t,t =“”>&gt;选择查询语法中的方法</func <t,>

时间:2012-10-23 09:06:04

标签: c# linq linq-to-sql linq-query-syntax

假设我们有下一个代码:

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并将其存储在另一个地方。在方法语法中,它将如下所示:

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变量保留在原位?

UPD:

为了澄清我的问题,我正在使用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,它会将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);
}

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

2 个答案:

答案 0 :(得分: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)
} 

答案 1 :(得分:0)

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