16

我有以下代码:

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

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

4

2 回答 2

19

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)您只有一个选项 - 将计算移至客户端,就像您已经完成的那样。

于 2013-10-02T22:27:07.260 回答
17

代码的一种优化是AsEnumerable()在方法之后使用Where。如果不是,则从存储中返回每个实体,并使用 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();
}
于 2013-10-02T23:02:41.403 回答