首先使用实体框架数据库从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.

谁能建议如何实现这一点?

首先使用实体框架数据库从SQL查询Xml

我认为问题是由存根函数的返回类型引起的。

你能检查你的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函数以接受CustomerIDrating

试一试。

编辑

除此之外,在定义MyXmlHelper EdmFunction时,请确保FunctionNameNamespaceName的拼写正确。在我的例子中,FunctionNameFilterCustomersByRating, NamespaceNameTestingEntities,它们与自动生成的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