为什么Entity Framework无法在LINQ语句中使用ToString()?

时间:2009-12-17 10:28:02

标签: c# linq linq-to-sql entity-framework

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

但实体框架中的一个类似示例得到错误消息,基本上说它不能“将其翻译为SQL”,这是德语中的原始错误消息:

  

“'LINQ to Entities'erkennt die   Methode'System.String ToString()'   nicht,und diese Methode kann nicht in   einenSpeicherausdruckübersetzt   werden“。

翻译

  

“'LINQ to Entities'无法识别   方法'System.String ToString()',   这种方法无法翻译成   记忆表达。

任何人都可以了解我们如何才能在Entity Framework中使用此类声明或解释为何会出现此错误?

4 个答案:

答案 0 :(得分:9)

简单地说:LINQ to Entities不知道从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() ...

答案 1 :(得分:8)

更新回答:

如果您按照我在回答开始时给您的链接,这个缺失的功能同时收到 75票,现在(终于!)implemented by Microsoft in 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]))


原始回答:

对我来说,为什么Linq2EF没有将.ToString()转换为正确的SQL语句是没有意义的,正如Linq2SQL所做的那样,只有 Microsoft开发团队知道他们没有实现它的原因然而。的: - (

但是,如果您投票支持此功能,则可以通过关注this link.来提高实施优先级

幸运的是,还有 2个可用的解决方法,这两个我最近在EF查询中使用过:


I)帮助我摆脱这种限制的是将查询更改为列表,如下所示:

var customersList = (from c in db.Customers
             select c).ToList(); // converts to IEnumerable<T> ...
var customersTest = (from c in customersList 
             select new {Id=c.ID.ToString()}); // ... which allows to use .ToString()

语句.ToList()转换为IEnumerable<T>,其中.ToString()可用。 注意,根据要求,您也可以使用.AsEnumerable(),这样做的好处是支持延迟执行,如果您有多个linq查询,或者相互依赖,则会更好您正在使用不同的参数值(非常感谢此{1}}提示!)。

之后您可以根据需要使用此查询,例如:

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),请使用SqlFunctions来自{{ 1}},它们将被正确地翻译成SQL查询。

示例1 :日期转换(您必须使用如下所示的dateparts)

System.Data.Objects.SqlClient

示例2 :数字到字符串转换

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 :(得分:6)

刚刚发布的实体框架6.1 RTM支持.ToString()

答案 3 :(得分:-2)

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(在实体框架中)生成SQL表达式而不是纯LINQ的一个缺点。

请记住,在SQL中等号的左侧使用CAST表现不佳: - )