假设,我们有下一个代码:
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方法链转换为查询语法,将表达式变量定为就地?
upd:
为了澄清我的问题,我正在使用Defaultifempty进行左JOIN,这是一种相等查询的简短形式:
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 };
}
正常工作的
,因为它使用内联表达式编译。当没有相应的grunt
时,它将null
分配给字段。但是,如果通过呼叫对外部映射器方法进行调查,将其编译为方法调用,该方法将获得可确定的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);
}
当然,我可以将null-Check添加到mapper方法中,但是我在DAL中要实现的目标是将选择器提取到映射器类中,并可能省略那里的null-checks。
我不确定为什么需要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)
}
您不能始终使用查询语法,在某些情况下,您只能使用方法链表示计算。在这种特定情况下,查询语法如果谓词是内联的,则将在幕后引入lambda,但是您将其放入变量中,因此您无法指定应该如何使用该变量,就像使用lambda一样,通过查询语法。