2011-04-07 50 views
6

什麼樣子我做DataConvert.ToThema()發生的窗簾後面,當我包括一個函數到我的編譯的查詢,這裏的表對象轉換成我的自定義業務對象:包括「離線」的代碼編譯querys

public static class Queries 
{ 
    public static Func<MyDataContext, string, Thema> GetThemaByTitle 
    { 
     get 
     { 
      var func = CompiledQuery.Compile(
       (MyDataContext db, string title) => 
        (from th in elan.tbl_Thema 
        where th.Titel == title 
        select DataConvert.ToThema(th)).Single() 
        ); 
      return func; 
     } 
    } 
} 

public static class DataConvert 
{ 
    public static Thema ToThema(tbl_Thema tblThema) 
    { 
     Thema thema = new Thema(); 

     thema.ID = tblThema.ThemaID; 
     thema.Titel = tblThema.Titel; 
     // and some other stuff 

     return thema; 
    } 
} 

,並調用它

Thema th = Queries.GetThemaByTitle.Invoke(db, "someTitle"); 

顯然,功能沒有到SQL或翻譯的東西(這怎麼可能呢),但它也當我在VS2010中設置斷點有不成立。

它工作沒有問題,但我不明白如何或爲什麼。那裏發生了什麼?

回答

2

你的DataConvert.ToThema()你的DataConvert.ToThema()靜態方法是簡單地創建一個類型的實例,它有一個默認的構造函數,並設置各種屬性,是否正確?如果是這樣,它不是從非常不同:當你打電話Queries.GetThemaByTitle

(from th in elan.tbl_Thema 
where th.Titel == title 
select new Thema{ID=th.ThemaID, Titel=th.Titel, etc...} 
).Single()); 

,查詢被編譯。 (順便說一下,你調用這個函數的方式可能實際上不會給你任何預編譯好處)。 「查詢」實際上是一個代碼表達式樹,只是其中的一部分用於生成發送到數據庫的SQL代碼。

它的其他部分將生成IL代碼,它將抓取從數據庫返回的內容並將其放入某種形式供您使用。 LINQ(EF或L2S)足夠聰明,可以進行靜態方法調用並從中生成IL以執行所需操作 - 也可以通過內部delegate或其他類似方法進行操作。但最終,它不需要與我在上面替換的東西產生(很多)不同。

但請注意,不管你回來的是什麼類型,某處,正在生成IL代碼,將DB值放入CLR對象中。那是表達式樹的另一部分。


如果你想在這些表達式樹,以及他們參與更詳細的研究,我不得不挖你,但我不知道從你的問題,如果這是你在找什麼。

+0

LINQ to EF不能做到這一點。 – 2011-04-15 10:06:39

1

讓我首先指出,不管你是否編譯你的查詢都不重要。即使你沒有預編譯,你也會觀察到相同的結果。

從技術上講,正如Andrew指出的那樣,使這項工作不那麼複雜。在評估LINQ表達式時,表達式樹會在內部構建。您的函數在此表達式樹中顯示爲一個節點。這裏沒有魔法。你可以在L2S和L2E中編寫這個表達式,它會編譯並運行正常。直到您嘗試實際執行鍼對數據庫的實際SQL查詢。這是差異開始的地方。 L2S似乎很高興地執行此任務,而L2E因NotSupportedException而失敗,並報告說它不知道如何將ToThema轉換爲存儲查詢。

那麼裏面發生了什麼?在L2S中,正如Andrew所解釋的那樣,查詢編譯器明白您的函數可以與已經執行的存儲查詢分開運行。因此它會將對函數的調用發送到對象讀取管道(將從SQL讀取的數據轉換爲作爲調用結果返回的對象)。

一旦安德魯的事情不完全正確,那麼它對靜態方法中的內容至關重要。我不認爲它確實如此。

如果你在調試器中爲你的函數設置了一個斷點,你會看到每個返回行調用一次。在堆棧跟蹤中,您會看到「輕量級函數」,實際上,這意味着該方法是在運行時發出的。所以這就是它對Linq to Sql的作用。

Linq to Entity團隊似乎走了不同的路線。我不知道,爲什麼他們決定從L2E查詢中禁止所有的InvocationExpressions。也許這些是性能原因,或者可能是因爲它們需要支持所有類型的提供程序,而不是僅支持SQL Server,因此數據讀取程序的行爲可能會有所不同。或者他們只是認爲大多數人不會意識到其中的一些是針對每個返回的行執行的,並且希望關閉此選項。

只是我的想法。如果有人有更多的見解,請加入!