2012-10-23 34 views
4

假設,我們有下面的代碼:LINQ到SQL,通過表達<Func<T, T>>查詢語法選擇方法

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變量就地轉化?

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 }; 
} 

其正常工作,因爲它編譯使用內聯表達。當沒有對應的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); 
} 

當然,我可以加空簽入映射器的方法,但是我試圖在DAL中實現的是將選擇器抽取到映射器類中,並可能省略空值檢查。

回答

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

正如你所看到的,這裏是左連接。如果只使用'Func',由於'grunt'可能等於null,它將拋出帶有內部NullReferenceException的TargetInvocationException。但它通常以傳遞給方法鏈格式中的Select方法的表達式工作。 – Harm

+0

@Harm你是否確信?雙精度型的'select'只是被編譯器翻譯成了對'SelectMany'的調用。無論如何,如果你擔心空咕嚕聲,爲什麼你打電話給DefaultIfEmpty_? – Rawling

+0

@Rawling,是的,我確定。我爲左連接調用DefaultIfEmpty。我更新了該問題以進行澄清。 – Harm

0

總是不能使用查詢語法,有些情況下只能用方法鏈表達計算。在這種特殊情況下,如果謂詞是內聯的,查詢語法會在幕後引入lambda表達式,但是您將其放入變量中,因此您無法指定應如何使用該變量,就像支持lambda一樣,支持通過查詢語法。