LINQ to Entities无法识别方法'System.String Format(System.String,System.Object,System.Object)'

Ano*_*use 80 linq linq-to-entities entity-framework

我有这个linq查询:

private void GetReceivedInvoiceTasks(User user, List<Task> tasks)
{
    var areaIds = user.Areas.Select(x => x.AreaId).ToArray();

    var taskList = from i in _db.Invoices
                   join a in _db.Areas on i.AreaId equals a.AreaId
                   where i.Status == InvoiceStatuses.Received && areaIds.Contains(a.AreaId)
                   select new Task {
                       LinkText = string.Format(Invoice {0} has been received from {1}, i.InvoiceNumber, i.Organisation.Name),
                       Link = Views.Edit
                   };
}
Run Code Online (Sandbox Code Playgroud)

它有问题.我正在尝试创建任务.对于每个新任务,当我将链接文本设置为像"Hello"这样的常量字符串时,它很好.但是上面我试图使用发票的属性来构建属性linktext.

我收到此错误:

base {System.SystemException} = {"LINQ to Entities无法识别方法'System.String Format(System.String,System.Object,System.Object)'方法,并且此方法无法转换为商店表达式." }

谁知道为什么?有人知道这样做的另一种方法是让它起作用吗?

Bro*_*ass 140

实体框架试图在SQL端执行您的投影,其中没有相应的string.Format.使用AsEnumerable()给力的那部分的评价使用LINQ到对象.

基于我之前给出的答案,我将重构您的查询,如下所示:

int statusReceived = (int)InvoiceStatuses.Received;
var areaIds = user.Areas.Select(x=> x.AreaId).ToArray();

var taskList = (from i in _db.Invoices
               where i.Status == statusReceived && areaIds.Contains(i.AreaId)
               select i)
               .AsEnumerable()
               .Select( x => new Task()
               {
                  LinkText = string.Format("Invoice {0} has been received from {1}", x.InvoiceNumber, x.Organisation.Name),
                  Link = Views.Edit
                });
Run Code Online (Sandbox Code Playgroud)

此外,我看到您在查询中使用相关实体(Organisation.Name)确保您在查询中添加适当的实体Include,或者具体实现这些属性以供以后使用,即:

var taskList = (from i in _db.Invoices
               where i.Status == statusReceived && areaIds.Contains(i.AreaId)
               select new { i.InvoiceNumber, OrganisationName = i.Organisation.Name})
               .AsEnumerable()
               .Select( x => new Task()
               {
                  LinkText = string.Format("Invoice {0} has been received from {1}", x.InvoiceNumber, x.OrganisationName),
                  Link = Views.Edit
                });
Run Code Online (Sandbox Code Playgroud)

  • 我还建议选择一个匿名类型,其中包含所需的InvoiceNumber和Organisation.Name.如果发票实体很大,则使用后续AsEnumerable的select i将撤回每列,即使您只使用两个. (3认同)

Nik*_*lay 15

IQueryable源自IEnumerable,主要的相似之处在于,当您进行查询时,它以其语言发布到数据库引擎,您可以告诉C#处理服务器(不是客户端)上的数据或告诉SQL处理数据数据.

所以基本上当你说IEnumerable.ToString(),C#获取数据集合并调用ToString()对象.但是当你说IQueryable.ToString()C#告诉SQL调用ToString()该对象但SQL中没有这样的方法时.

缺点是当您在C#中处理数据时,在C#应用过滤器之前,必须在内存中构建您正在查看的整个集合.

最有效的方法是使查询IQueryable与您可以应用的所有过滤器一样.

然后在内存中构建它并在C#中进行数据格式化.

IQueryable<Customer> dataQuery = Customers.Where(c => c.ID < 100 && c.ZIP == 12345 && c.Name == "John Doe");

 var inMemCollection = dataQuery.AsEnumerable().Select(c => new
                                                  {
                                                     c.ID
                                                     c.Name,
                                                     c.ZIP,
                                                     c.DateRegisterred.ToString("dd,MMM,yyyy")
                                                   });
Run Code Online (Sandbox Code Playgroud)


d21*_*219 7

虽然 SQL 不知道如何处理 a,string.Format但它可以执行字符串连接。

如果运行以下代码,那么您应该获得所需的数据。

var taskList = from i in _db.Invoices
               join a in _db.Areas on i.AreaId equals a.AreaId
               where i.Status == InvoiceStatuses.Received && areaIds.Contains(a.AreaId)
               select new Task {
                   LinkText = "Invoice " + i.InvoiceNumber + "has been received from " + i.Organisation.Name),
                   Link = Views.Edit
               };
Run Code Online (Sandbox Code Playgroud)

一旦您实际执行查询,这应该比使用稍微快一些AsEnumerable(至少这是我在出现与您相同的原始错误后在自己的代码中发现的)。如果您正在使用 C# 做一些更复杂的事情,那么您仍然需要使用AsEnumerable

  • 根据数据库结构和相关列的数量,使用此方法而不是“AsEnumerable()”可能会更加高效。避免使用“AsEnumerable()”和“ToList()”,除非您确实希望将所有结果放入内存中。 (3认同)
  • 不知道为什么 Linq 无法适应使用 FORMATMESSAGE 函数 https://learn.microsoft.com/en-us/sql/t-sql/functions/formatmessage-transact-sql?view=sql-server-2017 在那之前你的是解决方案(不强制实现) (2认同)