LINQ to实体无法识别方法“System.String格式(System.String、System.Object、System.Object)”
我有一个linq查询: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
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。