Sql server 通过实体框架使用用户提供的XPath查询SQL Server xml列

Sql server 通过实体框架使用用户提供的XPath查询SQL Server xml列,sql-server,entity-framework,xpath,Sql Server,Entity Framework,Xpath,我很难弄清楚如何在SQLServer中使用xml数据列,特别是用于实体框架 基本上,我们的一个表存储用户以XML形式提供的“自定义元数据”,因此将其存储在表中的XML列中似乎是明智的 然而,我们的应用程序的一个要求是支持元数据的搜索。用户能够提供一个XPath查询字符串,以及一个用于比较XPath值的值,以搜索包含与其查询匹配的元数据的元素 我认为SQL Server xml函数非常适合于此(例如,[xmlcol].exist('/path1/path2[0][text()='valuetest

我很难弄清楚如何在SQLServer中使用xml数据列,特别是用于实体框架

基本上,我们的一个表存储用户以XML形式提供的“自定义元数据”,因此将其存储在表中的XML列中似乎是明智的

然而,我们的应用程序的一个要求是支持元数据的搜索。用户能够提供一个XPath查询字符串,以及一个用于比较XPath值的值,以搜索包含与其查询匹配的元数据的元素

我认为SQL Server xml函数非常适合于此(例如,[xmlcol].exist('/path1/path2[0][text()='valuetest']),但Entity Framework不支持它们,这令人恼火(或者特别是不支持xml列)。作为替代方案,我尝试创建一个UDF,将用户提供的XPath传递给xml函数,但随后发现xml函数只允许字符串文本,因此我无法提供变量

在这一点上,我已经没有选择了

我创建了一小段代码,对IQueryable.ToString()的结果执行正则表达式替换,以插入我的XPath筛选器,然后手动将此字符串发送到数据库,但这也存在问题,例如,结果似乎没有延迟加载导航属性

我一直在寻找,偶然发现了SQLCLR类型的概念,并开始创建一个执行XPath比较的SQLCLR函数。我认为我在这一点上是赢家,直到一位同事指出Azure中的SQL Server不支持SQLCLR-doh


我还有什么其他选择吗?我的运行似乎非常接近于空…

您可以在一个存储过程中执行此操作,在该存储过程中动态构建查询

MS SQL Server 2008架构设置

create table YourTable
(
  ID int identity primary key,
  Name varchar(10) not null,
  XMLCol xml
);

go

insert into YourTable values
('Row 1', '<x>1</x>'),
('Row 2', '<x>2</x>'),
('Row 3', '<x>3</x>');

go

create procedure GetIt
  @XPath nvarchar(100)
as
begin
  declare @SQL nvarchar(max);

  set @SQL = N'
  select ID, Name
  from YourTable
  where XMLCol.exist('+quotename(@XPath, '''')+N') = 1';

  exec (@SQL);
end
exec GetIt N'*[text() = "2"]'
| ID |  NAME |
--------------
|  2 | Row 2 |

create table YourTable
(
  ID int identity primary key,
  Name varchar(10) not null,
  XMLCol xml
);

go

insert into YourTable values
('Row 1', '<x>1</x>'),
('Row 2', '<x>2</x>'),
('Row 3', '<x>3</x>');

go

create procedure GetIt
  @XPath nvarchar(100)
as
begin
  declare @SQL nvarchar(max);

  set @SQL = N'
  select ID, Name
  from YourTable
  where XMLCol.exist('+quotename(@XPath, '''')+N') = 1';

  exec (@SQL);
end
exec GetIt N'*[text() = "2"]'
| ID |  NAME |
--------------
|  2 | Row 2 |
要保持“可定制”,可以使用:

var query = @"SET ARITHABORT ON; 
              select * from [YourTable] where 
              [xmlcol].exist('/path1/path2[0][text()=''{0}''']";
var numOfResults = 5;
var offsetPage = 1;

var results = Context.YourTable.SqlQuery(String.Format(query,"valuetest"))
                              .OrderBy(x => x.col)
                              .Skip(offsetPage * numOfResults)
                              .Take(numOfResults).ToList();

注意,由于其动态特性,此方法很可能会暴露一定程度的sql注入安全漏洞。

我认为这是诚实的,但搜索结果中有太多需要定制的内容(orderby列、结果数、结果集偏移量)如果可能的话,在linq中构建查询似乎要容易得多。但是,SQL FIDLE链接为+1-我以前没有见过,但它看起来很方便!动态SQL是动态查询构建的答案。如果您想指定结果的数量,可以在SQL st的构建中动态嵌入一个“++”TOP“++@results++”要执行的操作。按相同的方式排序。我通常会添加一个“WHERE 1=1”来处理默认的WHERE条件,并允许您不添加任何条件或添加任意数量的条件来筛选数据。我支持这条路线。这是一个巨大的安全漏洞。@flup您想解释一下您的意思吗?如果您指的是sql-InJetion如果您能提供一个XPath来实现这一点,那将是一件有趣的事情。这会执行查询,然后应用顺序,跳过并在本地执行吗?我将对此进行测试,如果它有效,我将接受这个答案。