【问题标题】:Why LINQ to Entities does not recognize the method 'System.String ToString()?为什么 LINQ to Entities 无法识别方法 'System.String ToString()?
【发布时间】:2012-04-11 16:42:06
【问题描述】:

在 MVC3 Web 应用程序中出现错误。 LINQ to Entities does not recognize the method 'System.String ToString()' method, and this method cannot be translated into a store expression.

当我尝试使用 EF 从查询中获取值时:

public class DataRepository
    {
        public mydataEntities1 dbContext = new mydataEntities1();

        public List<SelectListItem> GetPricingSecurityID()
        {
        var pricingSecurityID = (from m in dbContext.Reporting_DailyNAV_Pricing
                                     select new SelectListItem
                                         {
                                                Text = m.PricingSecurityID.ToString(),
                                                Value = m.PricingSecurityID.ToString()
                                         });

        return pricingSecurityID.ToList();
        }
    }

【问题讨论】:

    标签: asp.net-mvc linq entity-framework


    【解决方案1】:

    无法转换为 SQL。我想,理论上可以,但没有实现。

    你只需要在得到结果后执行你的投影:

    var pricingSecurityID = (from m in dbContext.Reporting_DailyNAV_Pricing
                                         select m.PricingSecurityID).AsEnumerable()
        .Select(x => new SelectListItem{ Text = x.ToString(), Value = x.ToString() });
    

    【讨论】:

    • 这里不需要调用ToList() - 为什么要建立另一个列表,而AsEnumerable 会以更少的开销完成这项工作?
    • @JonSkeet 这取决于。如果您需要立即对结果进行操作,或者您想等到编译器实际执行查询。
    • @MandeepJanjua:OP 在最后调用 ToList 以返回一个列表 - 调用 ToList().Select(...).ToList() 毫无意义。
    【解决方案2】:

    如果它已经是一个字符串,你为什么还要费心打电话给ToString?我怀疑翻译没有包含在 LINQ to Entities 中,因为它没有意义。将您的选择子句更改为:

    select new SelectListItem
    {
        Text = m.PricingSecurityID,
        Value = m.PricingSecurityID
    }
    

    如果您确实需要执行 LINQ to Entities 不支持的操作,请使用 AsEnumerable 从数据库查询转换到进程内:

    public List<SelectListItem> GetPricingSecurityID()
    {
        return dbContext.Reporting_DailyNAV_Pricing
                        .Select(m => m.PricingSecurityID)
                        .AsEnumerable() // Rest of query is local
                        // Add calls to ToString() if you really need them...
                        .Select(id => new SelectListItem { Text = id, Value = id })
                        .ToList();
    }
    

    顺便说一句,我也同意 Jason 的反对意见。您最好返回在其他地方呈现的List&lt;string&gt;

    还请注意,如果您只是要使用单个 select 子句或仅使用 where 子句,则查询表达式实际上不会增加​​太多 - 调用 LINQ 扩展方法可以最终减少混乱,特别是如果您想调用查询表达式中不支持的方法(例如ToList)。

    【讨论】:

    • 您是否将System.String ToString() 理解为PricingSecurityID 已经是string?我实际上认为它指的是ToString 的返回类型,而PricingSecurityID 可能(可能?)还不是string
    • @Jason:是的,这是我的猜测。也许我错了,在这种情况下,我的第二段代码(带有 ToString 调用)将是正确的方法。我不认为您仅拆分投影的方法会有所帮助-除非您具体化查询或使用 AsEnumerable,否则它仍将在数据库中执行。
    • 我刚刚测试过:如果源数据类型不是字符串,错误消息还提到System.String ToString()
    【解决方案3】:

    因为它试图将其转换为 SQL,但它不能。将电话挂断至ToString,并在返回呼叫者之前进行投影。因此,将您的 select 子句替换为

    select m.PricingSecurityID
    

    然后说

    return pricingSecurityID
               .AsEnumerable()
               .Select(x => x.ToString())
               .Select(x => new SelectListItem { Text = x, Value = x })
               .ToList();
    

    另外,我注意到您将 UI 问题和数据查询问题混为一谈。这通常是一种不好的做法。实际上,您应该只返回 ID 列表,并让代码的 UI 部分担心将其调整为正确的形式。

    【讨论】:

      【解决方案4】:

      这个怎么样。在此示例中,db 中的 VDN 字段和 Skill 字段都是整数。我正在寻找两个字段的匹配项,所以我有 2 个比较。

      包括这个:

      using System.Data.Objects.SqlClient; // needed to convert numbers to strings for linq
      

      比较数字时这样做:

              // Search Code
                  if (!String.IsNullOrEmpty(searchString))
                  {
                      depts = depts.Where(d => SqlFunctions.StringConvert((double)d.VDN).Contains(searchString.ToUpper())
                      || SqlFunctions.StringConvert((double)d.Skill).Contains(searchString.ToUpper()));
                  }
              // End Search Code
      

      上班族。

      【讨论】:

      • 您介意编辑您的答案以与问题更密切相关吗?连接不是很清楚。
      【解决方案5】:

      遗憾的是 EF 不知道如何转换 .ToString() 您必须使用嵌入式函数 SqlFunctions.StringConvert:http://msdn.microsoft.com/en-us/library/dd466292.aspx 而且 int 没有重载,因此您必须将类型转换为 double :-(

      var vendors = 
         from v in Vendors  
         select new
         {             
             Code = SqlFunctions.StringConvert((double)v.VendorId)
         }; 
      

      【讨论】:

        【解决方案6】:

        我了解此问题已得到解答,并且我同意使用 AsEnumerable() 是可行的方法。不过,我想强调一下我经常遇到的一个常见场景,即 AsEnumerable() 用于解决此错误的效率很低。

        来自.NET Language-Integrated Query for Relational Data

        与 ToList() 和 ToArray() 不同,AsEnumerable() 运算符不会导致执行查询。它仍然被推迟。 AsEnumerable() 运算符仅更改查询的静态类型,将 IQueryable 转换为 IEnumerable,诱使编译器将查询的其余部分视为本地执行。

        参考文献

        1. Am I misunderstanding LINQ to SQL .AsEnumerable()?
        2. Understanding .AsEnumerable() in LINQ to SQL

        低效的方式

        IEnumerable<InvoiceDTO> inefficientEnumerable = 
             (from a in db.Invoices
             where a.Practice_Key == practiceKey.FirstOrDefault()
             select a
             ).AsEnumerable().
             Select(x => new InvoiceDTO
                                     {
                                         InvoiceID = x.InvoiceID,
                                         PracticeShortName = x.Dim_Practice.Short_Name,
                                         InvoiceDate = x.InvoiceDate,
                                         InvoiceTotal = x.InvoiceAmount,
                                         IsApproved = x.IsApproved,
                                         InvoiceStatus = (
                                                          x.IsApproved == null ? "Pending" :
                                                          x.IsApproved == true ? "Approved" :
                                                          x.IsApproved == false ? "Rejected" : "Unknown"
                                                        ),
                                         InvoicePeriodStartDateText = x.InvoicePeriodStart.ToShortDateString(),
                                         InvoicePeriodEndDateText = x.InvoicePeriodEnd.ToShortDateString(),
                                         InvoicePeriodStartDate = x.InvoicePeriodStart,
                                         InvoicePeriodEndDate = x.InvoicePeriodEnd
                                     }
                                     );
        
                    invoices = inefficientEnumerable.ToList();
        

        这里AsEnumerable 用于整个表。尽管不需要,但所有列都被选中。

        更好的方法

         IQueryable<InvoiceDTO> invoicesQuery = 
           (from a in db.Invoices
           where a.Practice_Key == practiceKey.FirstOrDefault()
           select new InvoiceDTO
                    {
                     InvoiceID = a.InvoiceID,
                     PracticeShortName = a.Dim_Practice.Short_Name,
                     InvoiceDate = a.InvoiceDate,
                     InvoiceTotal = a.InvoiceAmount,
                     IsApproved = a.IsApproved,
                     InvoiceStatus = (
                                       a.IsApproved == null ? "Pending" :
                                       a.IsApproved == true ? "Approved" :
                                       a.IsApproved == false ? "Rejected" :"Unknown"
                                       ),
                     InvoicePeriodStartDate = a.InvoicePeriodStart,
                     InvoicePeriodEndDate = a.InvoicePeriodEnd
                  });
        
        
                  IEnumerable<InvoiceDTO> betterEnumerable = invoicesQuery.AsEnumerable().
                  Select(x => new InvoiceDTO
                                         {
                                             InvoiceID = x.InvoiceID,
                                             PracticeShortName = x.PracticeShortName,
                                             InvoiceDate = x.InvoiceDate,
                                             InvoiceTotal = x.InvoiceTotal,
                                             IsApproved = x.IsApproved,
                                             InvoiceStatus = x.InvoiceStatus,
                                             InvoicePeriodStartDateText = x.InvoicePeriodStartDate.ToShortDateString(),
                                             InvoicePeriodEndDateText = x.InvoicePeriodEndDate.ToShortDateString(),
                                             InvoicePeriodStartDate = x.InvoicePeriodStartDate,
                                             InvoicePeriodEndDate = x.InvoicePeriodEndDate
                                         }
                                         );
        

        【讨论】:

          【解决方案7】:

          使用 VB.NET 试试这个,重要的是你需要得到答案中提到的 AsEnumerable 结果。

          Dim _EventsDaysResult = From ED In TAdbContext.EventPolicies.AsEnumerable
                                              Where ED.EventID = EID
                                              Select New With {ED.EventID, 
                                              .DayInfo = 
                                              ED.EventDay.GetValueOrDefault.ToShortDateString & " ( " & ED.EventDayTitle & " ) "}
          

          【讨论】:

            【解决方案8】:
            return dbContext.Reporting_DailyNAV_Pricing.AsEnumerable().Select(x => new SelectListItem
            {
                Text = x.PricingSecurityID.ToString(),
                Value = x.PricingSecurityID.ToString()
            }).ToList();
            

            【讨论】:

              猜你喜欢
              • 2017-08-08
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2015-07-25
              • 2014-12-26
              • 2013-07-13
              • 1970-01-01
              相关资源
              最近更新 更多