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 

我用它来限制线返回,然后,我找每个返回线