Take the 2-minute tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

I need to use Entity Framework, LINQ to query the XML data from the SQL in my asp.net mvc(C#) application.

I have a column XMLValue with data

<MetaData>
     <Reviews>1</Reviews>
     <Rating>1</Rating>
</MetaData>

I need to get all the Customers who have a Rating of 1 from the xml. I have referred to this stackoverflow post and I am not able to achieve it.

I have added the SQL function and added it to my 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

And the following DB function:

[DbFunction("XMLDBModel.Store", "FilterCustomersByRating")]
public static IQueryable<XMLTest> MyXmlHelper(int rating)
{
            throw new NotImplementedException("You can only call this function in a LINQ query");
}

Below is the linq query which I tried exactly as in the post, but not able to use the function and it throws error.

 var _dbCustomers = (from x in _context.XMLTests
                     where MyXmlHelper(1).Where(xh=> xh.XMLValue.Contains("1"))
                     select x);

Error:

Cannot implicitly convert type 'System.Linq.IQueryable<XMLTest>' to 'bool

If I user Any(), I have the following error:

 var _dbCustomers = (from x in _context.XMLTests
                          where MyXmlHelper(1).Any(xh => xh.XMLValue.Contains("1"))
                          select x);

Error:

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.

Can someone suggest on how to achieve this please?

share|improve this question
    
Are you writing SQL (structured query language) and really mean Microsoft SQL Server (the actual product) by this? If yes: please add sql-server tag to make this clear. If not: what database system is this for? –  marc_s Jun 14 at 10:36
1  
@marc_s, Yes, I am writing the sql query (FUNCTION) in sql server and I have updated the tags. Thanks for pointing at it :) –  Prasad Jun 14 at 10:49
    
What error does it throw? "You can only call this function in a LINQ query"? –  Typist Jun 15 at 14:06
    
@Typist, it shows the error "Cannot implicitly convert type 'System.Linq.IQueryable<XMLTest>' to 'bool'". I have also tried with Any() and I have the "Cannot be translated" error. Please check my updated question –  Prasad Jun 16 at 4:06
add comment

3 Answers

First error

where clause in your queries needs to evaluate to a bool value.

MyXmlHelper(1).Where(xh=> xh.XMLValue.Contains("1")) will give a record of type System.Linq.IQueryable<XMLTest> and not bool. You need to come up with a expression which will return a bool value.

Second error

Same is applicable to second error - change your where clause to get bool value from the expression.

share|improve this answer
    
I am not sure on how to use the DbFunctions in the LINQ where clause. I did as per the other SO post(referred in my question), but still no luck. Any help on this? –  Prasad Jun 16 at 6:16
    
You database function returns table, does it have CustomerId column? –  Typist Jun 16 at 6:29
    
Yes. It has the CustomerId as primary key. –  Prasad Jun 16 at 6:30
add comment

I think the problem is caused by the return type of your stub function.

Can you check what the return type for your FilterCustomersByRating method is in your DbContext? I don't think it should be XMLTest. It should look similar to the code below:

[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);
}

In this case, the return type of the stub function would be of type FilterCustomersByRating_Result which is class auto-generated when you add the FilterCustomersByRating Table-valued function to your edmx file.

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

With this in mind your stub function should be return IQueryable<FilterCustomersByRating_Result> i.e.

[EdmFunction("TestingDbEntities", "FilterCustomersByRating")]
public static IQueryable<FilterCustomersByRating_Result> MyXmlHelper(int rating)
{ 
    throw new NotImplementedException("You can only call this function in a LINQ query");
}

you can the use it as shown below:

var dbCustomers = (from x in _context.XMLTests
                   where MyXmlHelper(1).Any(xh => xh.XMLValue.Contains("1"))
                   select x);

Please note that while this will work it will return all Customers. You might need to modify the FilterCustomersByRating function to accept theCustomerID and rating.

Give it a try.

EDIT

In addition to the above, when defining the MyXmlHelper EdmFunction, make sure that the spelling of the FunctionName and NamespaceName is correct. In my case, the FunctionName is FilterCustomersByRating and NamespaceName is TestingEntities which match the values in the auto-generated DBContext class.

// </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);
    }
}
share|improve this answer
    
though I have the return type as "FilterCustomersByRating_Result" , I am still getting the same error "The specified method 'System.Linq.IQueryable`1[FilterCustomersByRating_Result] 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." –  Prasad Jun 28 at 9:33
    
@Prasad 1. Check and make sure you are using .Any LINQ function. 2. Double check the spelling of your EdmFuntion namespace and funtionName and make sure they are both correct. In my tests changing [EdmFunction("TestingDbEntities", "FilterCustomersByRating")] to [EdmFunction("TestingDbEntities", "FilterCustomersByRatingWRONGSPELLING")] results in the same error as you are getting. What is the name of your DbContext? –  Jamleck Jun 30 at 9:07
    
@Prasad I've edited the answer to add more information. Let me know how you go. –  Jamleck Jun 30 at 9:54
    
I was using Store namespace. After changing it to the namespace of the DBContext, it shows the error "Argument data type xml is invalid for argument 1 of like function." –  Prasad Jun 30 at 10:14
    
Below is the SQL it generates on running the LINQ(which throws the above error): SELECT [Extent1].[XMLId] AS [XMLId], [Extent1].[XMLValue] AS [XMLValue] FROM [dbo].[XMLTest] AS [Extent1] WHERE EXISTS (SELECT 1 AS [C1] FROM [dbo].[FilterXmlByRating](1) AS [Extent2] WHERE [Extent2].[XMLValue] LIKE N'%1%' ) –  Prasad Jun 30 at 10:34
show 3 more comments
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

Change "=" to "LIKE". Don't know what N(C) is, cross apply, or N.C.value(), but using = instead of LIKE often gives me trouble. Its trying to cross evaluate ints/bools with strings, and for strings like "1" you should use LIKE

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.