LINQ to SQL能够在数据库服务器端查询XML字段吗?

28

.NET 3.5, C#

我有一个带有“搜索”功能的Web应用程序。其中一些可搜索的字段是表中的一级列,但实际上,有些字段是嵌套在XML数据类型中的。

以前,我构建了一个动态构建我的搜索SQL语句的系统。我有一个很好的类层次结构,可以构建SQL表达式和条件语句。唯一的问题是它不安全,容易受到SQL注入攻击。

我正在阅读Rob Conery的优秀文章,他指出如果IQueryable结果从未枚举,则多个查询可以组合成单个TSQL查询以供服务器使用。这让我想到,我的动态搜索构造过于复杂 - 我只需要组合多个LINQ表达式即可。

例如(假设):

Author:
    ID (int),
    LastName (varchar(32)), 
    FirstName (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 以排除某些结果集,则会出现 out-of-memory 异常。

有什么想法?建议?

附加问题 - 如果数据库端实际上支持 XML 评估,那么 FLWOR 支持呢?


1
现在是2013年的年底了 - 有任何更新吗? - Benjamin Gruenbaum
1
@BenjaminGruenbaum 自从我最后思考这个问题已经很久了。当时我换工作后,用例消失了。据我最好的回忆,我使用了DanialM下面推荐的方法,即调用用户定义的函数。自那以来,我没有注意到LINQ直接支持它(但我也没有在寻找)。 - Matt
1
有趣 - 我会在5年后用赏金来寻找新的答案。 - Benjamin Gruenbaum
3个回答

12

这是一个有趣的问题。

目前,你无法直接从Linq指令中指示SQL Server执行XML函数。但是,你可以让Linq使用用户定义的函数...因此,你可以设置一个UDF来处理XML、获取正确的数据等,然后在Linq表达式中使用它。这将在服务器上执行并应该能实现你想要的功能。不过有一个重要的限制:你正在查找的XML路径(xmlColumn.value或类似方法的第一个参数)必须嵌入到函数中,因为它必须是一个字符串字面量,不能从输入参数构建(例如)。因此,在编写UDF时,你可以使用UDF来获取你知道的字段,但不能作为从XML列获取数据的通用方法。

请参阅Scott Gutherie的关于Linq to SQL的博客系列中的支持用户定义函数(UDFs)部分以获取更多实现信息。

希望这能帮助你。


谢谢Daniel,那个方法很管用!我之前读过那篇文章,但当我读到上面提到的关于在执行之前将多个查询组合在一起的文章时,它并没有让我恍然大悟。 - Matt

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库函数来完成此操作。

请查看该博客的更新内容:http://conficient.wordpress.com/2011/01/20/querying-xml-fields-in-linq-to-sql/ - PaulG
澄清答案的最佳方式是这样做:编辑答案以澄清,或者如果您当时没有编辑权限,则发表评论以标记问题。(SO在2008年12月是否是这样工作的?我不知道,我是在八个月后加入的。 :-) 当我加入时是这样的,但当时SO正在快速增长和变化。) - T.J. Crowder

-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

我使用它来限制返回的行数,然后查找每个返回的行


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接