Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/entity-framework/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
LINQ to实体无法识别方法“System.String格式(System.String、System.Object、System.Object)”_Linq_Entity Framework_Linq To Entities - Fatal编程技术网

LINQ to实体无法识别方法“System.String格式(System.String、System.Object、System.Object)”

LINQ to实体无法识别方法“System.String格式(System.String、System.Object、System.Object)”,linq,entity-framework,linq-to-entities,Linq,Entity Framework,Linq To Entities,我有一个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 equal

我有一个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
                   };
}
但它也有问题。我正在尝试创建任务。对于每个新任务,当我将链接文本设置为一个常量字符串(如Hello)时,一切正常。然而,在上面,我尝试使用发票的属性构建属性linktext

我得到这个错误:

base{System.SystemException}={LINQ to Entities无法识别方法'System.String FormatSystem.String,System.Object,System.Object'方法,此方法无法转换为存储表达式。}


有人知道为什么吗?有谁知道另一种方法可以让它工作吗?

Entity Framework正在尝试在SQL端执行您的投影,而SQL端没有与之等效的方法。用于强制使用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
                });
此外,我还看到您在查询组织中使用了相关实体。请确保您在查询中添加了适当的包含,或具体化这些属性以供以后使用,即:

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

而SQL不知道如何处理字符串。格式化它可以执行字符串连接

如果您运行以下代码,那么您应该得到您要查找的数据

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

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

是的,遗漏了最初可能的副本。除了由于表达式树转换,无法在服务器端执行“选择新任务”部分外,还应注意,这样做是不可取的。您可能希望在客户端创建任务。因此,查询和任务创建的分离可能更加明确。我还建议选择一个匿名类型,其中只包含所需的InvoiceNumber和Organization.Name。如果发票实体较大,则带有后续AsEnumerable的select i将拉回每一列,即使您只使用了两列。@Devin:Yes,我同意-事实上,这正是第二个查询示例所做的。不确定为什么Linq不能适应使用FORMATMESSAGE函数,直到那时,您的解决方案是不强制MaterializationDependent依赖于数据库结构和相关列的数量,使用此方法而不是AsEnumerable可以大大提高效率。在你真的想把所有结果都记在内存中之前,避免使用可数和ToList。