【问题标题】:Linq to Entities does not recognize string.Format or concatenation '+'Linq to Entities 无法识别 string.Format 或连接“+”
【发布时间】:2013-10-02 22:03:48
【问题描述】:

我有以下代码:

using (DBContext context = new DBContext())
{
    myCollection = context.Items.Where(i => i.Type == 1).OrderBy(k => k.Name).Select(w => new
    {
        Alias = w.Name + string.Format("{0}", w.Id),
        Name = w.Name                        
    }).ToArray();
}

在运行时我尝试连接字符串并尝试将整数 w.Id 转换为字符串时出现错误。

错误提示:

Linq to entity 无法识别方法 string.Format

也不支持加连接符号“+”。

我通过引入 AsEnumerable 解决了这个问题:

using (DBContext context = new DBContext())
{
    myCollection = context.Items.AsEnumerable().Where(i => i.Type == 1).OrderBy(k => k.Name).Select(w => new
    {
        Alias = w.Name + string.Format("{0}", w.Id),
        Name = w.Name                        
    }).ToArray();
}

但我想知道这是否是最好的解决方案,或者还有其他更适合这样做的方法。想法?

【问题讨论】:

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


【解决方案1】:

EF 无法将String.Format 转换为 SQL,但它可以毫无问题地处理字符串连接。在服务器端使用SqlFunctions.StringConvert 而不是String.Format 将数字转换为字符串:

Select(w => new {
    Alias = w.Name + SqlFunctions.StringConvert((double)w.Id),
    Name = w.Name                        
})

它会生成类似的东西

SELECT 
[Extent1].[Name] + STR( CAST( [Extent1].[Id] AS float)) AS [C1], 
[Extent1].[Name] AS [Name]
FROM [dbo].[Items] AS [Extent1]

更新:因此,您正在使用不支持此转换的 EF 提供程序(SQL CE 提供程序无法将此查询转换为 SQL)您只剩下一个选项 - 将计算移至客户端,就像您已经完成的那样。

【讨论】:

  • 它给了我以下错误:类型'System.Data.Objects.SqlClient.SqlFunctions 上的指定方法'System.String StringConvert(System.Nullable`1[System.Double])' ' 无法转换为 LINQ to Entities 存储表达式。
  • @Rodri 看起来您没有使用 Microsoft SQL Server 实体框架提供程序,并且您的提供程序不支持这些功能。如果提供者不支持在服务器端将数字转换为字符串,那么您只能将转换移动到客户端(例如使用AsEnumerable()
  • 我使用的提供程序是 SQLCe (compact edition) 4.0,所以在这种情况下,正如您所说,唯一可能的解决方案是使用 AsEnumerable()。
  • @Rodri 很遗憾是的,但我建议您在移至客户端之前仅选择所需的数据:Select(w => new { w.Name, w.Id }).AsEnumerable().Select(x => new { Alias = x.Name + x.Id, x.Name })
  • SqlFunction 非常有趣。以前从未使用过它。但是如何以文化敏感的方式转换数据呢?当我期望逗号时,我将点作为小数分隔符。谢谢。
【解决方案2】:

您的代码的一个优化是在Where 方法之后使用AsEnumerable()。如果不是,则从存储中返回每个实体,并使用 LINQ to Objects 检查整个表。通过对代码的这种简单修改,您可以让 where 子句在 sql 上运行并从存储中检索更少的记录。一般规则是首先放置由 LINQ 提供程序实现的任何查询子句。

using (DBContext context = new DBContext())
{
    myCollection = context.Items.Where(i => i.Type == 1)
       .AsEnumerable().OrderBy(k => k.Name).Select(w => new
        {
            Alias = w.Name + string.Format("{0}", w.Id),
            Name = w.Name                        
        }).ToArray();
}

【讨论】:

  • 是的,这行得通...但请注意缩小结果集的范围之前 .AsEnumerable(),就像您在示例中使用Where(...) 所做的那样。否则,事情可能会变得异常缓慢,因为您是在内存中而不是在数据库中执行此操作。
  • 小优化:您可能希望将.AsEnumerable() 放在.OrderBy(...) 后面,这样排序也将在数据库端进行。
猜你喜欢
  • 1970-01-01
  • 2013-05-01
  • 1970-01-01
  • 2014-08-09
  • 1970-01-01
  • 2012-04-03
  • 2021-11-06
  • 2012-05-03
相关资源
最近更新 更多