LINQ to Entities ne reconnaît pas le système de la méthode.Méthode String ToString ()', et cette méthode ne peut pas être traduite dans une expression de stockage

je suis en train de migrer des trucs d'un serveur mysql vers un serveur sql mais je ne peux pas trouver comment faire fonctionner ce code:

using (var context = new Context())
{
    ...

    foreach (var item in collection)
    {
        IQueryable<entity> pages = from p in context.pages
                                   where  p.Serial == item.Key.ToString()
                                   select p;
        foreach (var page in pages)
        {
            DataManager.AddPageToDocument(page, item.Value);
        }
    }

    Console.WriteLine("Done!");
    Console.Read();
}

quand il entre dans le deuxième foreach (var page in pages) il jette une exception disant:

LINQ to entities ne reconnaît pas la méthode " du Système.Chaîne Méthode ToString ()', et cette méthode ne peut pas être traduite dans un magasin expression.

N'importe qui sait pourquoi ce qui se passe?

115
demandé sur Erre Efe 2011-05-05 18:45:43

11 réponses

il suffit de sauvegarder la chaîne de caractères sur une variable temp et de l'utiliser dans votre expression:

var strItem = item.Key.ToString();

IQueryable<entity> pages = from p in context.pages
                           where  p.Serial == strItem
                           select p;

le problème se pose parce que ToString() n'est pas vraiment exécuté, il est transformé en un MethodGroup et ensuite analysé et traduit en SQL. Comme il n'y a pas d'équivalent ToString() , l'expression est rejetée.

Note:

assurez-vous également de vérifier Alex réponse concernant la classe helper SqlFunctions qui a été ajoutée plus tard. Dans de nombreux cas, il peut éliminer la nécessité pour la variable temporaire.

126
répondu Josh 2017-05-23 12:34:41

comme d'autres ont répondu, Cela casse parce que .ToString ne traduit pas vers le SQL approprié sur le chemin dans la base de données.

cependant, Microsoft fournit le la classe de fonctions SQL qui est un ensemble de méthodes qui peuvent être utilisées dans des situations comme celle-ci.

pour ce cas, ce que vous recherchez ici est Sqlfonctions.StringConvert :

from p in context.pages
where  p.Serial == SqlFunctions.StringConvert((double)item.Key.Id)
select p;

bon lorsque le la solution avec des variables temporaires n'est pas souhaitable pour quelque raison que ce soit.

similaire à des fonctions SQL vous avez également le Entityfonctions (avec EF6 obsolète par DbFunctions ) qui fournit un ensemble différent de fonctions qui sont également agnostiques source de données (pas limité à par exemple SQL).

57
répondu Alex 2015-05-10 10:00:38

le problème est que vous appelez ToString dans une requête LINQ to Entities. Cela signifie que l'analyseur essaie de convertir L'appel de ToString en son équivalent SQL (ce qui n'est pas possible...d'où l'exception).

tout ce que vous avez à faire est de déplacer L'appel ToString à une ligne séparée:

var keyString = item.Key.ToString();

var pages = from p in context.entities
            where p.Serial == keyString
            select p;
23
répondu Justin Niessner 2012-09-04 20:39:17

avait un problème similaire. Résolu en appelant ToList () sur la liste des entités et en questionnant la liste. Si la collection est petite c'est une option.

IQueryable<entity> pages = context.pages.ToList().Where(p=>p.serial == item.Key.ToString())

Espérons que cette aide.

10
répondu cynicaldoctor 2013-05-01 18:57:42

le changer comme ceci et il devrait fonctionner:

var key = item.Key.ToString();
IQueryable<entity> pages = from p in context.pages
                           where  p.Serial == key
                           select p;

la raison pour laquelle l'exception n'est pas lancée dans la ligne la requête LINQ est déclarée mais dans la ligne de la foreach est la fonctionnalité d'exécution différée, c.-à-d. la requête LINQ n'est pas exécutée jusqu'à ce que vous essayez d'accéder au résultat. Et cela se produit dans le foreach et pas plus tôt.

6
répondu Daniel Hilgarth 2012-09-04 20:37:26

table de coulée à Enumerable , puis vous appelez méthodes LINQ avec l'aide de ToString() méthode à l'intérieur:

    var example = contex.table_name.AsEnumerable()
.Select(x => new {Date = x.date.ToString("M/d/yyyy")...)

mais soyez prudent, lorsque vous appelez AsEnumerable ou ToList méthodes parce que vous demanderez toutes les données de toutes les entités avant cette méthode. Dans mon cas ci-dessus, je lis toutes les lignes table_name par une seule requête.

3
répondu neustart47 2017-04-28 14:12:42

dans MVC, présumez que vous faites une recherche de document(s) en fonction de vos besoins ou de vos renseignements. Il fonctionne correctement.

[HttpPost]
[ActionName("Index")]
public ActionResult SearchRecord(FormCollection formcollection)
{       
    EmployeeContext employeeContext = new EmployeeContext();

    string searchby=formcollection["SearchBy"];
    string value=formcollection["Value"];

    if (formcollection["SearchBy"] == "Gender")
    {
        List<MvcApplication1.Models.Employee> emplist = employeeContext.Employees.Where(x => x.Gender == value).ToList();
        return View("Index", emplist);
    }
    else
    {
        List<MvcApplication1.Models.Employee> emplist = employeeContext.Employees.Where(x => x.Name == value).ToList();
        return View("Index", emplist);
    }         
}
1
répondu shakti 2016-10-18 20:07:29

mise à niveau Entity Framework Version 6.2.0 a fonctionné pour moi.

j'étais déjà sur la Version 6.0.0.

Espère que cette aide,

1
répondu 93Ramadan 2018-05-03 11:49:49

si vous voulez vraiment taper ToString dans votre requête, vous pouvez écrire une expression tree visitor qui réécrit l'appel à ToString avec un appel à la appropriée StringConvert fonction :

using System.Linq;
using System.Data.Entity.SqlServer;
using System.Linq.Expressions;
using static System.Linq.Expressions.Expression;
using System;

namespace ToStringRewriting {
    class ToStringRewriter : ExpressionVisitor {
        static MethodInfo stringConvertMethodInfo = typeof(SqlFunctions).GetMethods()
                 .Single(x => x.Name == "StringConvert" && x.GetParameters()[0].ParameterType == typeof(decimal?));

        protected override Expression VisitMethodCall(MethodCallExpression node) {
            var method = node.Method;
            if (method.Name=="ToString") {
                if (node.Object.GetType() == typeof(string)) { return node.Object; }
                node = Call(stringConvertMethodInfo, Convert(node.Object, typeof(decimal?));
            }
            return base.VisitMethodCall(node);
        }
    }
    class Person {
        string Name { get; set; }
        long SocialSecurityNumber { get; set; }
    }
    class Program {
        void Main() {
            Expression<Func<Person, Boolean>> expr = x => x.ToString().Length > 1;
            var rewriter = new ToStringRewriter();
            var finalExpression = rewriter.Visit(expr);
            var dcx = new MyDataContext();
            var query = dcx.Persons.Where(finalExpression);

        }
    }
}
0
répondu Zev Spitz 2017-05-23 10:31:14

j'ai eu la même erreur dans ce cas:

var result = Db.SystemLog
.Where(log =>
    eventTypeValues.Contains(log.EventType)
    && (
        search.Contains(log.Id.ToString())
        || log.Message.Contains(search)
        || log.PayLoad.Contains(search)
        || log.Timestamp.ToString(CultureInfo.CurrentUICulture).Contains(search)
    )
)
.OrderByDescending(log => log.Id)
.Select(r => r);

après avoir passé beaucoup trop de temps à déboguer, j'ai compris que l'erreur apparaissait dans l'expression logique.

"151950920 La" première ligne search.Contains(log.Id.ToString()) fonctionne très bien, mais la dernière ligne qui traite d'un objet DateTime fait échouer lamentablement:

|| log.Timestamp.ToString(CultureInfo.CurrentUICulture).Contains(search)

supprimer la ligne problématique et le problème résolu.

je n'ai pas on comprend parfaitement pourquoi, mais il semble que ToString() soit une expression de LINQ pour les chaînes, mais pas pour les entités. LINQ for Entities traite des requêtes de bases de données comme SQL, et SQL n'a aucune notion de ToString(). En tant que tel, nous ne pouvons pas jeter ToString() dans un .Où() de la clause.

mais alors comment fonctionne la première ligne? Au lieu de ToString(), SQL ont CAST et CONVERT , donc ma meilleure supposition jusqu'à présent est que linq pour les entités utilise cela dans certains cas simples. Les objets DateTime ne sont pas toujours si simple...

0
répondu pekaaw 2016-12-06 15:29:54

il suffit de transformer la requête LINQ to Entity en une requête LINQ to Objects (par exemple call ToArray) à tout moment vous devez utiliser un appel de méthode dans votre requête LINQ.

-7
répondu T. Webster 2011-10-05 18:15:22