LINQ to SQL 可以查询 XML 字段 DB-serverside 吗?

Posted

技术标签:

【中文标题】LINQ to SQL 可以查询 XML 字段 DB-serverside 吗?【英文标题】:Can LINQ to SQL query an XML field DB-serverside? 【发布时间】:2010-09-21 21:30:02 【问题描述】:

.NET 3.5,C#

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

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

我正在阅读Rob Conery's excellent article,它指出如果从未枚举 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。一个存在吗?我知道我可以在 DB 端评估所有非 XML 条件,然后在代码端进行 XML 评估,但是我的数据足够大,以至于 A)有很多网络流量会拖累性能,B)我会出去-如果我无法评估 XML 第一个 DB 端以排除某些结果集,则会出现内存异常。

想法?建议?

额外问题 - 如果 XML 评估实际上是可能的 DB 端,那么 FLWOR 支持呢?

【问题讨论】:

2013 年结束了 - 有什么更新吗? @BenjaminGruenbaum 很久没有想到这个问题了。当我从那时到现在换工作时,我的用例就消失了。我记得最好的是,我使用了下面推荐的 DanialM 方法,即调用用户定义的函数。不能说,因为从那以后我注意到 LINQ 有任何直接支持(但我也没有看过) 有趣 - 我会在 5 年后尝试用赏金钓到新的答案。 【参考方案1】:

现在这是一个有趣的问题。

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

查看Scott Gutherie's excellent Blog series on Linq to SQL 的支持用户定义函数 (UDF) 部分,了解有关实施的更多信息。

希望这会有所帮助。

【讨论】:

谢谢丹尼尔,成功了!前段时间我读过那篇文章,但是当我阅读上面提到的关于在执行前将多个查询组合在一起的文章时,它并没有引起我的注意。【参考方案2】:

澄清丹尼尔的回答 - 除非查询的 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 库函数来执行此操作。

【讨论】:

另请参阅该博客上的更新:conficient.wordpress.com/2011/01/20/… 澄清答案的最佳方法就是这样做:编辑答案以澄清它,或者如果您(当时)没有编辑权限,请发表评论以标记问题。 (这就是 SO 在 08 年 12 月的工作方式吗?我不知道,八个月后我加入了。:-) 那是我加入的时候,但当时 SO 正在迅速发展和变化。)【参考方案3】:

这不是最好的,不适用于所有查询,也不是完全 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

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

【讨论】:

以上是关于LINQ to SQL 可以查询 XML 字段 DB-serverside 吗?的主要内容,如果未能解决你的问题,请参考以下文章

怎么用linq to sql 写单表多字段的模糊查询方法

使用 LINQ 和 XElement 查询 SQL 表

针对 LINQ To SQL 查询中的位字段评估布尔值

LinQ to SQL 查询

如何编写这个 Linq-to-SQL 选择查询

LINQ to XML 查询中的 xmlns 属性