LINQ 表达式“无法翻译”

Posted

技术标签:

【中文标题】LINQ 表达式“无法翻译”【英文标题】:The LINQ expression "could not be translated" 【发布时间】:2021-12-28 03:23:12 【问题描述】:

我已将我的应用程序从 dotNet core2.1 迁移到 Dotnet core5。以下功能已停止工作。我尝试调试代码,但找不到解决方案。给出错误的行是X => Convert.ToInt32(X.Value)。如果我不这样做,转换功能可以正常工作,但列表的顺序会受到干扰。

错误:-

The LINQ expression 'DbSet<EbDepartmentMsts>()\r\n .OrderBy(e => Convert.ToInt32(e.DeptCode.ToString()))' could not be translated. Additional information: Translation of method 'object.ToString' failed. If this method can be mapped to your custom function, Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'

功能

public List<SelectListItem> GetDepartmentCode()
        
            var table = new List<SelectListItem>();
            try
            
                table = (from eb in _context.EbDepartmentMsts

                         select new SelectListItem
                         
                             Text = string.Concat(eb.DeptCode.ToString(), "~", eb.Description),
                             Value = eb.DeptCode.ToString()
                         ).OrderBy(X => Convert.ToInt32(X.Value)).ToList();

            catch(Exception ex)
            

            
            return table;
        

【问题讨论】:

物化 LINQ 查询然后Selectfrom eb in _context.EbDepartmentMsts.ToList(). @YongShun 但是当我使用 .net core sdk 2.1 时,相同的代码更早地工作了 【参考方案1】:

您需要分三步完成:

    仅将必填字段投影到匿名类型中,如果有任何过滤条件,则此处也应包括在内。 在很多情况下也可以包含排序标准!

    select new eb.DeptCode, eb.Description

    通过.ToList()IQueryable 中的LINQ 查询具体化为IEnumerable。这会将结果带入内存以供本地客户端执行

    .ToList()

    执行.Select() 将结果投影到SelectListItem。这是在 C# 客户端中执行的,因此您还可以使用您可能需要的任何框架或自定义方法。

       .Select(x => new SelectListItem
       
           Text = string.Concat(x.DeptCode.ToString(), "~", x.Description),
           Value = x.DeptCode.ToString()
       )
    

有许多解决方案建议“只需将.Tolist() 放入您的查询中”,但重要的是我们尽可能最好地利用数据库并通过投影到临时匿名类型来最小化返回的数据。它不必匿名,但这会减少维护工作并为您提供最大的灵活性。

这是在客户端执行排序的示例:

table = (from eb in _context.EbDepartmentMsts
         select new  eb.DeptCode, eb.Description 
        )
        .ToList()
        .Select(x => new SelectListItem
        
            Text = string.Concat(x.DeptCode.ToString(), "~", x.Description),
            Value = x.DeptCode.ToString()
        )
        .OrderBy(x => Convert.ToInt32(x.Value))
        .ToList();

或者,您也可以在数据库查询中执行排序:

table = (from eb in _context.EbDepartmentMsts
         orderby eb.DeptCode
         select new  eb.DeptCode, eb.Description 
        )
        .ToList()
        .Select(x => new SelectListItem
        
            Text = string.Concat(x.DeptCode.ToString(), "~", x.Description),
            Value = x.DeptCode.ToString()
        )
        .ToList();

【讨论】:

虽然这行得通,但一般来说,对 "Materialize First" 的建议太笼统不是很好,您所做的是制定一个 近似的表达式 所需的结果,那么您在执行最终投影之前已将其具体化。这是解决此类问题的 100% 最佳实践方法。对于 OP 在下一个场景中正确应用于此的推理有点模糊。 是的,谢谢你的建议。使用this answer 中提到的支持的函数在具体化数据之前制定表达式会很好。无论如何,感谢知识分享。 =) 感谢您提供的链接,这是传奇!

以上是关于LINQ 表达式“无法翻译”的主要内容,如果未能解决你的问题,请参考以下文章

无法翻译 LINQ 表达式,将在本地计算

EF.Property 抛出“无法翻译 LINQ 表达式”

无法翻译 LINQ 表达式 DbSet<>.Any

LINQ 表达式 - 使用 .Any in s Select 无法翻译

无法翻译 LINQ 表达式。以可翻译的形式重写查询,或切换到客户端评估 EF Core 3.1

Entityframework Core 3 linq表达式无法翻译