2012-03-30 40 views
1

我能夠創建一個我認爲很奇怪的LINQ語句,並希望看看是否有其他人有過使用它的經驗。將查詢數據從LINQ傳遞給同一查詢中的方法

我就簡化爲這樣:

var x = db.Test 
    .Where(a => a.Field1 == Utils.CreateHash(Preferences.getValue(a.Field2))) 
    .FirstOrDefault(); 

現在,這如何轉換爲數據庫的代碼?不會LINQ需要對每一行進行雙重查詢,即對於行a:

 
1) Query a.Field2 
2) Return value to run Utils.CreateHash(Preferences.getValue(a.Field2)) 
3) Take that value from step 2 and compare it against a.Field1 
4) Repeat 1-3 until I've gone through all the rows or returned a matching row 

這不會是非常低效嗎?還是LINQ智能足以以更好的方式運行它?請注意,我沒有真正運行此代碼,因此另一種可能性是運行時錯誤。爲什麼LINQ不夠智能以檢測到衝突,而不讓我編譯它?

+0

我不認爲你的查詢將工作是看到你要'utils的呼叫。你試圖在數據庫上執行的lambda中的CreateHash' – BrokenGlass 2012-03-30 18:52:21

+0

@BrokenGlass我實際上並沒有運行它,但爲什麼它會編譯? Linq是否不夠聰明知道該功能不在數據庫上? – onit 2012-03-30 18:54:58

+0

不,Linq IQuerable提供程序在運行時會失敗,lambda語法是有效的,並且與Linq到對象一起使用,而不是在您的提供程序上(它在運行時將查詢轉換爲數據庫查詢) – BrokenGlass 2012-03-30 18:55:58

回答

2

由於在您的lambda中調用了Utils.CreateHash,您試圖在數據庫上執行,因此該查詢不起作用,因爲在該上下文中,您無法執行該方法,因爲在數據庫方面沒有等價物,因此查詢將失敗。作爲在大多數訪問原始值或集合的經驗法則,通常第三方提供者(例如,Linq to SQL,Linq to Entities)在內存結構(諸如方法或類)中訪問的能力是非常有限的的基元會起作用。

+0

有趣的是,如果我傳遞一個已經定義的值而不是a.Field2,查詢就可以工作。事實上,它一直在努力。所以你所說的是,如果它在執行數據庫端之前無法評估函數,那麼它會嘗試在數據庫端找到一個等價的東西,如果不存在則拋出一個運行時錯誤? – onit 2012-03-30 19:03:07

+0

@onit:是的,確切地說 - 沒有來回走 - 把它看作是一條單行道。最好你可以傳遞預先計算的值,完成對數據庫的所有工作,然後使用'AsEnumerable()'在內存中進行一些後處理,但不會傳遞例如數據。列在查詢數據庫的過程中返回到您的代碼 – BrokenGlass 2012-03-30 19:05:04

+0

您是對的。我試圖運行它,並得到一個NotSupportedException。謝謝(你的)信息。關於Linq如何在數據庫端搜索存儲過程,您有任何參考嗎?或者爲什麼它不能識別它是無效的。如果你不確定,我意識到我有點特別。 – onit 2012-03-30 19:09:52

0

的LINQ提供程序將運行選擇這兩個字段一個SELECT查詢,然後爲每個兩個值執行你的lambda表達式返回行。

+0

我不確定是否這回答了我的問題。它是否返回所有行的兩個字段?或者必須逐行查詢並評估lambda表達式?如果它是逐行進行的,那麼對我來說效率就會非常低下。那麼,如果它發現來自兩個字段的匹配不需要再次爲該行中的所有字段查詢數據庫? – onit 2012-03-30 18:53:53

+0

@onit:正如我在我的回答中所說的,它將運行一個SELECT並迭代DataReader中的行,直到找到匹配。當然,這取決於LINQ提供商。 – SLaks 2012-03-30 19:25:17

1

只是爲了快速添加...
一個很好的例子可以知道這是如何工作的(極端情況我同意,但最好:)或者通過自定義(開源)LINQ提供程序的源代碼(例如http://relinq.codeplex.com/有一個等)。
基本上(在這裏我簡化事情有點),一個LINQ提供程序只能「地圖」爲dB(支持的SQL,函數),他「知道」有關。
即它有一個標準的設置可以用比工作,其他的,並與您的自定義方法(不轉化爲常量等)的框架,有沒有辦法解決的「DB/SQL側'。
例如與你的'自定義'linq提供者(不是這裏的情況),你可以添加一個特定的分機呼叫,例如.MyCalc() - 將被正確解析並轉換爲SQL等效項 - 然後您就可以使用它了。
除此之外,我認爲如果我記得正確的話,提供者將把它作爲一個表達式來解決它從Db'fetch'返回時的查詢操作。或者在某些情況下抱怨。
Linq基於IQueryable - 你可以看看那裏提供的支持SQL等價物的擴展方法。
希望這有助於
編輯:東西「工作」與否是否並不重要 - 它仍然並不意味着它會在數據庫環境中執行 - 即它會在大多數情況下不可接受的性能明智。 IQueryable與表達式一起工作(並且如果您查看接口) - 並且通常在調用或枚舉時執行linq。在這一點上,一些表達式可能會計算出一個可以用於SQL的常量值,但在您的情況下不會。
最好的測試方法是測試查詢生成的SQL(可能這是我認爲的Translate LINQ to sql statement)。