为什么Entity Framework无法在LINQ语句中使用ToString()?
这适用于LINQ-to-SQL:
var customersTest = from c in db.Customers select new { Id = c.Id, Addresses = from a in db.Addresses where c.Id.ToString() == a.ReferenzId select a }; foreach (var item in customersTest) { Console.WriteLine(item.Id); }
但entity framework中的类似示例会收到一条错误消息 ,表示它无法“将其转换为SQL”,这是德语中的原始错误消息:
“’LINQ to Entities’erkennt die Methode’System.String ToString()’nicht,und diese Methode kann nicht in einenSpeicherausdruckübersetztwerden。”
翻译:
“’LINQ to Entities’无法识别Method’System.String ToString()’,此方法无法转换为内存表达式。
任何人都可以阐明我们如何在Entity Framework中使用这种语句或解释为什么会出现这个错误?
简单地说:LINQ to Entities不知道从ID类型到字符串的转换。
c.ID
的类型是c.ID
? 有什么理由说它是ID的一种类型,而ReferenzId
另一种类型? 如果可能的话,让它们成为相同的类型,此时你将不再有问题。 我不知道是否还有其他方法可以在LINQ to Entities中执行转换 – 可能有 – 但是对齐类型会更清晰。
顺便说一句,这真的看起来像是一个联接:
var query = from c in db.Customers join a in db.Addresses on c.Id equals a.ReferenzId into addresses select new { Id = c.Id, Addresses = addresses };
编辑:要回复您的评论 – ToString
出现在IntelliSense中,因为编译器不知道您的查询意味着什么或将如何翻译。 它是完全有效的C#,可以生成一个有效的表达式树 – 它只是EF不知道如何将该表达式树转换为SQL。
您可以尝试使用Convert.ToString(c.Id)
而不是仅调用c.Id.ToString()
…
对我来说,为什么Linq2EF不会将.ToString()
转换为正确的SQL语句,正如Linq2SQL所做的那样,只有Microsoft开发团队知道他们尚未实现它的原因。 🙁
但是,如果您通过此链接 投票支持此function ,则可以提高实施优先级。
幸运的是,还有2个可用的解决方法 ,我最近在EF查询中使用了它们:
I)帮助我解决这个限制的原因是将查询更改为列表 ,如下所示:
var customersList = (from c in db.Customers select c).ToList(); // converts to IEnumerable ... var customersTest = (from c in customersList select new {Id=c.ID.ToString()}); // ... which allows to use .ToString()
语句.ToList()
转换为IEnumerable
,其中.ToString()
可用。 请注意 ,根据要求,您也可以使用.AsEnumerable()
,这样做的优点是支持延迟执行,如果您有多个linq查询.AsEnumerable()
或者您使用的是不同的参数值,则会更好(非常感谢Divega的暗示!)。
之后您可以根据需要使用此查询,例如:
var customersTest2 = from c in customersTest select new { Id = c.Id, Addresses = from a in db.Addresses where c.Id == a.ReferenzId select a };
当然,如果需要,可以根据需要向customersTest
的对象添加更多属性。 您还可以优化上面的查询,我只使用了3个步骤来实现此示例的可读性。
II)对于简单的转换,如果必须在其他子查询中重用生成的查询(并且它需要保持IQueryable
),请使用System.Data.Objects.SqlClient
SqlFunctions
,它们将被正确地转换为SQL查询。
示例1 :日期转换(您必须使用如下所示的dateparts)
var customersTest = from c in db.Customers select new { strDate=SqlFunctions.DateName("dd", c.EndDate) +"."+SqlFunctions.DateName("mm", c.EndDate) +"."+SqlFunctions.DateName("yyyy", c.EndDate) }
示例2 :数字到字符串转换
var customersTest = from c in db.Customers select new { strID=SqlFunctions.StringConvert((double)c.ID) }
这可以帮助您摆脱需要转换为字符串的大多数情况。
更新:如果您按照我在回答开始时给您的链接,这个缺失的function同时获得了75票 ,现在(最后!) 由Microsoft在EF 6.1中实现 。 对所有参与者:感谢您的投票! 你的声音被听到了。
例如:
var query = from e in context.Employees where e.EmployeeID.ToString() == "1" select e;
现在将被翻译为:
DECLARE @p0 NVarChar(1000) = '1' SELECT [t0].[EmployeeID], [t0].[LastName], [t0].[FirstName], [t0].[Title], [t0].[TitleOfCourtesy], [t0].[BirthDate], [t0].[HireDate], [t0].[Address],[t0].[City], [t0].[Region], [t0].[PostalCode], [t0].[Country], [t0].[HomePhone], [t0].[Extension], [t0].[Photo], [t0].[Notes], [t0].[ReportsTo], [t0].[PhotoPath] FROM [Employees] AS [t0] WHERE (CONVERT(NVarChar,[t0].[EmployeeID])) = @p0
即e.EmployeeID.ToString()
转换为(CONVERT(NVarChar,[t0].[EmployeeID]))
。
刚刚发布的Entity Framework 6.1 RTM现在支持.ToString()
LINQ to Entities据我所知(对于v1)非常具有初衷性。 换句话说,它不知道如何采用扩展方法“ToString()”并为其生成SQL。
在LINQ to SQL中,它在生成SQL之前执行扩展方法“ToString()”。 不同之处在于LINQ to Entities使用IQueryable而不是IEnumerable。
但是,从我记得铸造应该工作(因为转换是一种数据类型,SQL知道CAST())。
所以
c.Id.ToString()应该是(string)c.Id
(另外,确保它是(字符串)而不是(字符串))。
关于使用Lambda(在entity framework中)生成SQL表达式而不是纯LINQ,我会说的一个缺点。
请记住,在SQL中等号的左侧使用CAST表现不佳:-)