2010-10-05 62 views
7

我想用我的查詢怎麼我需要實現一個特殊類型的過濾器內部產生的方法...如何創建一個支持向sql轉換的方法?

return manager.Clients.SelectAll().Where(cli => cli.Name.SatisfyFilter(filter.Name) && cli.LastName.SatisfyFilter(filter.LastName) && cli.MiddleName.SatisfyFilter(filter.MiddleName)).ToList(); 

但我得到:

「方法「布爾SatisfyFilter(系統。 String,System.String)'不支持對SQL的轉換。「

錯誤

我的方法是:

public static bool SatisfyFilter(this string palavra, string filtro) 

同樣的事情

public bool Contains(string value) 
在字符串類型

,幷包含作品就好了... ...

我需要這種方法在IQueryable上運行,因爲我的表有25萬個客戶端...

我看到SQL事件探查器的包含SQL轉換...

如何實現我的方法對相關過濾器代碼發送到SQL? =/

+2

爲什麼不直接使用包含它是有用的? – Paddy 2010-10-05 15:47:35

回答

4

一個簡單的答案是你不能。 LINQ to SQL轉換器只識別一些標準的.NET方法,並且您無法添加其他方法。

  • 如果您需要類似的東西,您需要顯式創建表達式樹(用作lambda表達式的主體)。一個直接的方法是使用Expression類的方法,但它可以被簡化很多。

  • 也許最好的選擇是使用LINQKit project。它可以調用其他lambda表達式(不完全的方法,但關閉)。它提供了一個AsExpandable擴展方法,可以讓你寫:

    Expression<Func<Purchase, bool>> customFunction = ... 
    var data = new MyDataContext(); 
    var query = 
        from c in data.Purchases.AsExpandable() 
        where customFunction.Compile()(c) 
        select c.Name; 
    

    customFunction被編譯爲表達式樹lambda函數,你可以用它查詢裏面。 AsExpandable擴展名替換了函數體的使用,所以LINQ to SQL翻譯器可以處理這個。你可以閱讀更多關於my blog post的工作原理。

  • 其他可供他人討論的更多細節的替代方法是將功能實現爲SQL用戶定義的函數。然後,您可以將該函數拖到數據上下文中,並從查詢中調用該函數。翻譯器只會將一個調用插入到你的SQL函數中。

1

如果您可以將其映射到udf,您可以將udf拖到data-contex中。當通過數據上下文進行訪問時,LINQ-to-SQL可以進行翻譯。

如果你只是過濾一個iQueryable,你可以編寫一個方法,只使用Where(返回一個新的iqueryable),它可以很好地工作。

如果您需要更多杯子,您可能必須手動處理表達式樹。

0

做到這一點最簡單的方法是要弄清楚如何將你的'SatisfyFilter'函數轉換爲一系列具有可接受的轉換的linq命令。恐怕真的沒有其他「簡單」的方法來使用您的定製功能,而無需將您的2500萬客戶端過濾爲更具體的數字。

6

在您的SQL服務器上創建一個與您的C#代碼等效的用戶函數。說它被稱爲「dbo.SatsFilter」。

您的datacontext覆蓋創建方法,說它看起來像:

public bool SatisfiesFilter(string name, string filter) 
{ 
    // some sort of implementation. 
} 

裝點C#方法與[Function][Parameter]屬性,所以它看起來是這樣的:

[Function(Name="dbo.SatsFilter",IsComposable=true)] 
public bool SatisfiesFilter([Parameter name="@name",DbType="nvarchar(50)"]string name, [Parameter name="@filter",DbType="nvarchar(50)"]string filter) 

IsComposable=true意味着其一個函數而不是存儲過程,因此可以用作更大查詢的一部分。

現在可以使用在DataContext的這種方法,它會被轉換成SQL時適當,或C#將在查詢中使用在存儲器中被執行。

還要注意,如果你想只使用SQL所有的時間(有時是有用的),你可以調用到SQL時調用該方法在C#代碼:

[Function(Name="dbo.SatsFilter",IsComposable=true)] 
public bool SatisfiesFilter([Parameter name="@name",DbType="nvarchar(50)"]string name, [Parameter name="@filter",DbType="nvarchar(50)"]string filter) 
{ 
    return (bool)ExecuteMethodCall(this, (MethodInfo)MethodInfo.GetCurrentMethod(), name, filter).ReturnValue; 
} 

這不是時候非常有用在C#相當於是方便,因爲它意味着一個命中的數據庫和一些翻譯,但如果用戶功能依賴於數據庫狀態或難以順利轉化爲C#

+0

你的意思是我將不得不繼承DataContext類,然後將SatisfiesFilter方法作爲實例方法放入其中?然後在發佈LINQ to SQL查詢時,我應該使用新的繼承類。 – RBT 2016-06-14 14:25:10

+0

@RBT我這麼認爲。有一陣子了。 – 2016-06-14 14:43:52

+0

你可以在下面的鏈接看看我的問題。我正在嘗試同樣的事情,但得到一個錯誤。 http://stackoverflow.com/questions/37814449/linq-to-sql-unable-to-use-sql-server-udfs-in-linq-query – RBT 2016-06-15 00:24:24