首先使用实体框架数据库从SQL查询Xml
本文关键字:SQL 查询 Xml 数据库 框架 实体 | 更新日期: 2023-09-27 18:08:31
我需要使用实体框架,LINQ从我的asp.net mvc(c#)应用程序的SQL查询XML数据。
我有一个列XMLValue
数据
<MetaData>
<Reviews>1</Reviews>
<Rating>1</Rating>
</MetaData>
我需要从xml中获得Rating
为1的所有Customers
。我已经参考了这个stackoverflow帖子,但我无法实现它。
我已经添加了SQL函数并将其添加到我的edmx:
CREATE FUNCTION [dbo].[FilterCustomersByRating]
(@Rating int)
RETURNS TABLE
AS
RETURN
SELECT XMLTest.*
FROM XMLTest
CROSS APPLY XMLValue.nodes('//MetaData') N(C)
where N.C.value('Rating[1]', 'int')=@Rating
GO
和以下DB函数:
[DbFunction("XMLDBModel.Store", "FilterCustomersByRating")]
public static IQueryable<XMLTest> MyXmlHelper(int rating)
{
throw new NotImplementedException("You can only call this function in a LINQ query");
}
下面是我在帖子中尝试的linq查询,但无法使用该函数并抛出错误。
var _dbCustomers = (from x in _context.XMLTests
where MyXmlHelper(1).Where(xh=> xh.XMLValue.Contains("1"))
select x);
错误:Cannot implicitly convert type 'System.Linq.IQueryable<XMLTest>' to 'bool
如果我使用Any(),我有以下错误:
var _dbCustomers = (from x in _context.XMLTests
where MyXmlHelper(1).Any(xh => xh.XMLValue.Contains("1"))
select x);
错误:The specified method 'System.Linq.IQueryable`1[XMLTest] MyXmlHelper(Int32)' on the type 'CustomerRepository' cannot be translated into a LINQ to Entities store expression because its return type does not match the return type of the function specified by its DbFunction attribute.
谁能建议如何实现这一点?
我认为问题是由存根函数的返回类型引起的。
你能检查你的FilterCustomersByRating
方法的返回类型是在你的DbContext吗?我认为不应该是XMLTest
。它应该类似于下面的代码:
[EdmFunction("TestingDbEntities", "FilterCustomersByRating")]
public virtual IQueryable<FilterCustomersByRating_Result> FilterCustomersByRating(Nullable<int> rating)
{
var ratingParameter = rating.HasValue ?
new ObjectParameter("Rating", rating) :
new ObjectParameter("Rating", typeof(int));
return ((IObjectContextAdapter)this)
.ObjectContext
.CreateQuery<FilterCustomersByRating_Result>("[TestingEntities]
.[FilterCustomersByRating](@Rating)", ratingParameter);
}
在这种情况下,存根函数的返回类型将是FilterCustomersByRating_Result
类型,这是在您将FilterCustomersByRating
表值函数添加到edmx文件时类自动生成的。
CREATE FUNCTION [dbo].[FilterCustomersByRating]
(@Rating int)
RETURNS TABLE
AS
RETURN
SELECT XMLTest.*
FROM XMLTest
CROSS APPLY XMLValue.nodes('//MetaData') N(C)
where N.C.value('Rating[1]', 'int')=@Rating
GO
考虑到这一点,存根函数应该是return IQueryable<FilterCustomersByRating_Result>
例如[EdmFunction("TestingDbEntities", "FilterCustomersByRating")]
public static IQueryable<FilterCustomersByRating_Result> MyXmlHelper(int rating)
{
throw new NotImplementedException("You can only call this function in a LINQ query");
}
可以如下所示使用:
var dbCustomers = (from x in _context.XMLTests
where MyXmlHelper(1).Any(xh => xh.XMLValue.Contains("1"))
select x);
请注意,虽然这将工作,它将返回所有Customers
。您可能需要修改FilterCustomersByRating
函数以接受CustomerID
和rating
。
试一试。
编辑
除此之外,在定义MyXmlHelper
EdmFunction时,请确保FunctionName
和NamespaceName
的拼写正确。在我的例子中,FunctionName
是FilterCustomersByRating
, NamespaceName
是TestingEntities
,它们与自动生成的DBContext类中的值相匹配。
// </auto-generated code>
public partial class TestingEntities : DbContext
{
public TestingEntities()
: base("name=TestingEntities")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
public DbSet<XMLTest> XMLTests { get; set; }
[EdmFunction("TestingEntities", "FilterCustomersByRating")]
public virtual IQueryable<FilterCustomersByRating_Result> FilterCustomersByRating(Nullable<int> rating)
{
var ratingParameter = rating.HasValue ?
new ObjectParameter("Rating", rating) :
new ObjectParameter("Rating", typeof(int));
return ((IObjectContextAdapter)this)
.ObjectContext
.CreateQuery<FilterCustomersByRating_Result>("[TestingEntities]
.[FilterCustomersByRating](@Rating)", ratingParameter);
}
}
第一个错误
查询中的 where
子句需要计算为bool
值。
MyXmlHelper(1).Where(xh=> xh.XMLValue.Contains("1"))
将给出类型为System.Linq.IQueryable<XMLTest>
而不是bool
的记录。您需要提出一个表达式,它将返回一个bool
值。
同样适用于第二个错误-更改where子句以从表达式中获取bool
值
CREATE FUNCTION [dbo].[FilterCustomersByRating]
(@Rating int)
RETURNS TABLE
AS
RETURN
SELECT XMLTest.*
FROM XMLTest
CROSS APPLY XMLValue.nodes('//MetaData') N(C)
where N.C.value('Rating', 'int') LIKE '<Rating>'.@Rating.'</Rating>'
GO
将"="改为"LIKE"。不知道N(C)是什么,交叉应用,或N.C.value(),但使用=代替LIKE经常给我带来麻烦。它试图用字符串交叉计算int/bool值,对于像"1"这样的字符串,你应该使用like