2008-11-11 116 views
28

.NET 3.5,C#LINQ to SQL查詢XML字段DB-serverside?

我有一個具有「搜索」功能的網絡應用程序。一些可搜索的字段是表中的頭等列,但其中一些字段實際上是嵌入在XML數據類型中的字段。

此前,我構建了一個用於爲我的搜索動態構造SQL的系統。我有一個很好的類層次結構,它構建了SQL表達式和條件語句。唯一的問題是它從SQL注入攻擊是不安全的。

我在閱讀Rob Conery的優秀文章(http://blog.wekeroad.com/2008/02/27/creating-in-queries-with-linq-to-sql/),指出如果IQueryable結果永遠不會枚舉,那麼多個查詢可以合併爲一個服務器的TSQL查詢。這讓我想到我的動態搜索結構太複雜 - 我只需要結合多個LINQ表達式。

例如(人爲):

作者: ID(INT), 名字(VARCHAR(32)), 姓(VARCHAR(32))

context.Author.Where(xx => xx.LastName == "Smith").Where(xx => xx.FirstName == "John") 

結果在下面的查詢:

SELECT [t0].[ID], [t0].[LastName], [t0].[FirstName] 
FROM [dbo].[Author] AS [t0] 
WHERE ([t0].[LastName] = Smith) AND ([t0].[FirstName] = John) 

我意識到這可能是一個簡單的動態查詢生成的完美解決方案,從SQL安全注入 - 我只是遍歷我的IQueryable結果並執行額外的條件表達式來獲得我最終的單執行表達式。

但是,我找不到任何支持XML數據的評估。在TSQL,以獲得從XML節點的值,我們會做類似

XMLField.value('(*:Root/*:CreatedAt)[1]', 'datetime') = getdate() 

但我找不到的LINQ to SQL相當於創建此評價。有一個存在嗎?我知道我可以評估所有非XML條件的數據庫端,然後做我的XML評估代碼端,但我的數據足夠大,以至於A)這是大量的網絡流量拖延性能和B)如果我無法評估XML第一個數據庫端以排除特定的結果集,則會出現內存異常。

想法?建議?

紅利問題 - 如果XML評估實際上是可能的數據庫方面,那麼FLWOR支持呢?

+1

這是2013年底 - 任何更新? – 2013-12-12 01:20:56

+1

@BenjaminGruenbaum自從我思考這個問題已經很長時間了。當我在此之間和之後改變工作時,我的用例就消失了。作爲我能記得的最好的,我使用了下面推薦的方法DanialM,該方法是調用用戶定義的函數。不能說因爲我從那以後就注意到了LINQ的任何直接支持(但我還沒有看過) – Matt 2013-12-12 19:07:04

+1

有趣 - 我會嘗試在5年後以賞金欣賞新的答案。 – 2013-12-12 19:18:18

回答

12

現在,這是一個有趣的問題。

現在,您不能指示SQL Server直接從Linq執行XML函數。 但是,您可以讓Linq使用用戶定義的函數... 因此,您可以設置udf來處理xml,獲取正確的數據等,然後在您的Linq表達式中使用它。這將在服務器上執行,並應該做你想做的。但是有一個重要的限制:您要查找的XML路徑(xmlColumn.value或類似的第一個參數)必須內置到函數中,因爲它必須是字符串,文字,它不能從輸入參數(例如)。因此,您可以使用UDF獲取您在編寫UDF時瞭解的字段,但不能將其用作從XML列中獲取數據的通用方法。

有關實現的更多信息,請參閱Scott Gutherie's excellent Blog series on Linq to SQL的支持用戶定義函數(UDF)部分。

希望這會有所幫助。

4

爲了闡明Daniel的答案 - 除非查詢的XPath部分是固定的,否則不能使用函數來執行此操作。看到我的博客條目:http://conficient.wordpress.com/2008/08/11/linq-to-sql-faq-xml-columns-in-sql/

基本上你不能通過LINQ to SQL來查詢xml列。儘管它返回一個XElement類型,但當您嘗試過濾此列時,您不能執行任何SQL轉換。

LINQ to SQL確實支持使用UDF - 但SQL本身不允許您在XML xpath查詢中使用參數字符串 - 它必須是字符串文字。這意味着如果XPath在設計時是固定的,那麼它可以工作,但如果您希望能夠傳遞變量XPath語句,則不會。

這導致只有兩種其他的替代方法:內聯SQL語句(它否定了LINQ的值)並在.NET CLR中編寫SQL庫函數來執行此操作。

-1

這是不是最好的,並不適用於所有的查詢,並沒有完全LINQ,但工作和快:

的XML SQL現場接受「的ToString」,所以你可以做:

Dim txt as String = "<File>3</File>" 
Return (From P In DC.LPlanningRefs Where P.Details.ToString.Contains(txt) Select P).FirstOrDefault 

我用它來限制線返回,然後,我找每個返回線