it-swarm.com.de

LINQ to Entities erkennt die Methode 'System.String ToString ()' nicht. Diese Methode kann nicht in einen Speicherausdruck übersetzt werden

Ich migriere einige Sachen von einem MySQL-Server zu einem SQL-Server, aber ich kann nicht herausfinden, wie dieser Code funktioniert:

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

Wenn es in die zweite foreach (var page in pages) eintritt, löst es eine Ausnahme aus:

LINQ to Entities erkennt die Methode 'System.String ToString () -Methode, und diese Methode kann nicht in ein Geschäft übersetzt werden Ausdruck.

Weiß jemand, warum das passiert?

119
Erre Efe

Speichern Sie die Zeichenfolge einfach in eine temporäre Variable und verwenden Sie diese dann in Ihrem Ausdruck:

var strItem = item.Key.ToString();

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

Das Problem entsteht, weil ToString() nicht wirklich ausgeführt wird, sondern in eine MethodGroup umgewandelt und dann analysiert und in SQL übersetzt wird. Da es kein ToString()-Äquivalent gibt, schlägt der Ausdruck fehl.

Hinweis:

Stellen Sie sicher, dass Sie auch die Antwort von Alex bezüglich der später hinzugefügten SqlFunctions-Helper-Klasse überprüfen. In vielen Fällen kann auf die temporäre Variable verzichtet werden.

130
Josh

Wie andere beantwortet haben, bricht dies, da .ToString auf dem Weg in die Datenbank nicht in relevantes SQL übersetzt werden kann.

Microsoft bietet jedoch die SqlFunctions-Klasse , dh eine Sammlung von Methoden, die in solchen Situationen verwendet werden können. 

In diesem Fall suchen Sie nach SqlFunctions.StringConvert :

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

Gut, wenn die Lösung mit temporären Variablen aus welchen Gründen auch immer nicht erwünscht ist.

Ähnlich wie bei SqlFunctions gibt es auch die EntityFunctions (mit EF6, die durch DbFunctions veraltet ist), die verschiedene Funktionen bereitstellt, die auch Datenquellen agnostisch sind (nicht auf beispielsweise SQL beschränkt).

64
Alex

Das Problem ist, dass Sie ToString in einer LINQ to Entities-Abfrage aufrufen. Das bedeutet, dass der Parser versucht, den ToString-Aufruf in sein entsprechendes SQL zu konvertieren (was nicht möglich ist ... daher die Ausnahme).

Sie müssen lediglich den ToString-Aufruf in eine separate Leitung verschieben:

var keyString = item.Key.ToString();

var pages = from p in context.entities
            where p.Serial == keyString
            select p;
23
Justin Niessner

Hatte ein ähnliches Problem . Es wurde durch Aufrufen von ToList () für die Entitätsauflistung und Abfragen der Liste ..__ gelöst. Wenn die Auflistung klein ist, ist dies eine Option.

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

Hoffe das hilft.

10
cynicaldoctor

Ändern Sie es so und es sollte funktionieren:

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

Der Grund, warum die Ausnahme nicht in der Zeile ausgegeben wird, in der die LINQ-Abfrage ausgeführt wird, ist in der Zeile der Variablen foreach die Funktion für die verzögerte Ausführung, d. Und dies geschieht in der foreach und nicht früher.

6
Daniel Hilgarth

Tabelle in Enumerable umwandeln, dann rufen Sie LINQ-Methoden mit der ToString()-Methode auf:

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

Seien Sie jedoch vorsichtig, wenn Sie AsEnumerable- oder ToList-Methoden aufrufen, da Sie vor dieser Methode alle Daten von allen Entitäten anfordern. In meinem obigen Fall lese ich alle table_name-Zeilen mit einer Anfrage. 

3
neustart47

Angenommen, Sie suchen in MVC nach Datensätzen basierend auf Ihren Anforderungen oder Informationen. Es funktioniert einwandfrei.

[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
shakti

Upgrade auf Entity Framework Version 6.2.0 hat für mich funktioniert.

Ich war vorher auf Version 6.0.0.

Hoffe das hilft,

1
93Ramadan

Ich habe in diesem Fall den gleichen Fehler erhalten:

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

Nachdem ich viel zu viel Zeit mit dem Debuggen verbracht hatte, stellte ich fest, dass ein Fehler im Logikausdruck auftauchte. 

Die erste Zeile search.Contains(log.Id.ToString()) funktioniert einwandfrei, aber die letzte Zeile, die ein DateTime-Objekt behandelt, hat dazu geführt, dass es fehlschlug: 

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

Entfernen Sie die problematische Leitung und das Problem wurde gelöst.

Ich verstehe nicht ganz warum, aber ToString () scheint ein LINQ-Ausdruck für Strings zu sein, nicht jedoch für Entities. LINQ for Entities behandelt Datenbankabfragen wie SQL, und von ToString () ist in SQL keine Ahnung. Als solches können wir ToString () nicht in eine .Where () - Klausel werfen. 

Aber wie funktioniert die erste Linie? Anstelle von ToString () haben SQL CAST und CONVERT, daher ist meine beste Vermutung bisher, dass linq für Entitäten dies in einigen einfachen Fällen verwendet. DateTime-Objekte sind nicht immer so einfach zu finden ...

0
pekaaw

Wenn Sie wirklich ToString in Ihre Abfrage eingeben möchten, können Sie einen Ausdrucksbaumbesucher schreiben, der den Aufruf von ToString mit einem Aufruf an die entsprechende StringConvert-Funktion schreibt

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
Zev Spitz