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?
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.
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.
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).
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;
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.
Ä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.
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.
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);
}
}
Upgrade auf Entity Framework Version 6.2.0 hat für mich funktioniert.
Ich war vorher auf Version 6.0.0.
Hoffe das hilft,
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 ...
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);
}
}
}