Requête Xml à partir de SQL à l'aide de la database Entity Framework First

J'ai besoin d'utiliser Entity Framework, LINQ pour interroger datatables XML à partir du SQL dans mon application asp.net mvc (C #).

J'ai une colonne XMLValue avec des données

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

Je dois get tous les Customers qui ont une Rating de 1 à partir du xml. Je me suis référé à ce post de stackoverflow et je ne suis pas capable de l'atteindre.

J'ai ajouté la fonction SQL et l'ai ajoutée à mon edmx:

 CREATE FUNCTION [dbo].[FilterCustomersByRating] (@Rating int) RETURNS TABLE AS RETURN SELECT XMLTest.* FROM XMLTest CROSS APPLY XMLValue.nodes('//MetaData') N(C) where NCvalue('Rating[1]', 'int')=@Rating GO 

Et la fonction DB suivante:

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

Ci-dessous est la requête linq que j'ai essayé exactement comme dans le post, mais pas en mesure d'utiliser la fonction et il jette une erreur.

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

Erreur:

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

Si j'utilise Any (), j'ai l'erreur suivante:

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

Erreur:

 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 atsortingbute. 

Quelqu'un peut-il suggérer sur la façon d'y parvenir s'il vous plaît?

Je pense que le problème est dû au type de return de votre fonction de rlocation.

Pouvez-vous vérifier quel est le type de return de votre méthode FilterCustomersByRating dans votre DbContext? Je ne pense pas que ça devrait être XMLTest . Cela devrait ressembler au code ci-dessous:

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

Dans ce cas, le type de return de la fonction stub sera de type FilterCustomersByRating_Result qui est généré automatiquement par la class lorsque vous ajoutez la fonction FilterCustomersByRating Table à votre file edmx.

 CREATE FUNCTION [dbo].[FilterCustomersByRating] (@Rating int) RETURNS TABLE AS RETURN SELECT XMLTest.* FROM XMLTest CROSS APPLY XMLValue.nodes('//MetaData') N(C) where NCvalue('Rating[1]', 'int')=@Rating GO 

Dans cet esprit, votre fonction stub doit renvoyer IQueryable<FilterCustomersByRating_Result> ie

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

vous pouvez l'utiliser comme indiqué ci-dessous:

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

S'il vous plaît noter que même si cela fonctionne, il returnnera tous les Customers . Vous devrez peut-être modifier la fonction FilterCustomersByRating pour accepter le CustomerID et l' rating .

Essaie.

MODIFIER

En plus de ce qui précède, lors de la définition de la fonction MyXmlHelper MyXmlHelper , assurez-vous que l'orthographe de FunctionName et NamespaceName est correcte. Dans mon cas, le FunctionName est FilterCustomersByRating et NamespaceName est TestingEntities qui correspondent aux valeurs dans la class DBContext générée automatiquement.

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

Première erreur

where clause dans vos requêtes doit évaluer à une valeur bool .

MyXmlHelper(1).Where(xh=> xh.XMLValue.Contains("1")) donnera un logging de type System.Linq.IQueryable<XMLTest> et non bool . Vous devez find une expression qui returnnera une valeur bool .

Deuxième erreur

La même chose s'applique à la seconde erreur – changez votre clause where pour get la valeur bool de l'expression.

 CREATE FUNCTION [dbo].[FilterCustomersByRating] (@Rating int) RETURNS TABLE AS RETURN SELECT XMLTest.* FROM XMLTest CROSS APPLY XMLValue.nodes('//MetaData') N(C) where NCvalue('Rating', 'int') LIKE '<Rating>'.@Rating.'</Rating>' GO 

Remplacez "=" par "LIKE". Je ne sais pas ce que N (C) est, cross apply, ou NCvalue (), mais en utilisant = au lieu de LIKE me donne souvent des ennuis. C'est en essayant d'évaluer ints / bools avec des strings, et pour des strings comme "1" vous devriez utiliser LIKE