这里我使用下面的查询,并且花费大约14到15秒的时间来检索大量数据。 在下面的Query中,CreatedDate是DateTimeOffset数据类型。
var naId = UnitOfWork.SalesPhases.FirstOrDefault(p => p.PhaseName =="NA").SalesPhaseId;
var rejectedId = UnitOfWork.SalesPhases.FirstOrDefault(p => p.PhaseName =="Rejected").SalesPhaseId;
var data = UnitOfWork.Leads.Query().AsEnumerable()
.Where(p =>(p.SalesPhaseId == naId || p.SalesPhaseId == rejectedId) &&
p.CreatedDate.Date >= fromDate && p.CreatedDate.Date <= toDate).Select(m =>
new
{
m.LeadId,
m.LeadOwnerId,
m.SalesPhaseId,
m.LeadActivities,
m.Employee,
m.SalesPhase,
m.CompanyName,
m.CreatedDate,
m.LeadHistories,
m.LeadAddresses
}).ToList();
我尝试使用AsQueryable而不是AsEnumerable,但它给出了以下错误:
“LINQ to Entities不支持指定的类型成员'Date'。仅支持初始值设定项,实体成员和实体导航属性。”
你能帮我减少查询的执行时间吗?
答案 0 :(得分:2)
您对AsEnumerable
的使用迫使过滤在本地完成。它会将所有数据拉入其中,然后在您的应用中对其进行过滤。这显然非常低效。现在,您的查询的一部分似乎无法直接在LINQ to SQL中表达。我在这里看到两个选择。
首先,您可以在SQL中进行大多数过滤,但随后在本地进行日期过滤:
var data = UnitOfWork.Leads.Query()
// Do this part of the query in SQL
.Where(p => p.SalesPhaseId == naId ||
p.SalesPhaseId == rejectedId)
.AsEnumerable()
// Do the rest of the query in-process
.Where(p => p.CreatedDate.Date >= fromDate &&
p.CreatedDate.Date <= toDate)
.Select(...)
如果第一部分将大量过滤掉它,那么它是合适的,然后你只需要对一小组数据进行本地处理。
或者,您可以根据DateTime
计算出日期过滤的含义。看起来你可以做到:
// This may not be required, depending on the source.
fromDate = fromDate.Date;
// This will be, although you may be able to get rid of the ".Date" part.
toDate = toDate.Date.AddDays(1);
var data = UnitOfWork.Leads.Query()
// Do this part of the query in SQL
.Where(p => (p.SalesPhaseId == naId ||
p.SalesPhaseId == rejectedId) &&
p.CreatedDate >= fromDate &&
p.CreatedDate < toDate)
.Select(...)
它创建了等效查询,但未在查询本身中使用Date
属性。
答案 1 :(得分:0)
AsEnumerable()之后的所有内容在本地执行而不是在服务器上执行。另见
https://stackoverflow.com/a/2013876/141172
这意味着表中的所有行都是从数据库返回的,然后在C#代码中进行过滤。
删除该调用,以便在服务器端进行过滤。
编辑
注意到Jon的评论,它提醒我他重新实现了LINQ to Objects作为学习练习。他关于AsEnumerable()重新实现的评论值得一读
我可以很容易地描述它的行为:它返回源。
就是这样。没有参数验证,它不会创建另一个迭代器。它只是返回源。
你可能想知道重点是什么......而且都是关于改变表达式的编译时类型。我将在另一篇文章中讨论IQueryable(虽然可能没有实现与之相关的任何内容),但希望你知道它通常用于“进程外”查询 - 最常见的是在数据库中。
现在,想要在数据库中执行查询的某些方面,然后在.NET中进行更多操作并不是完全不常见的 - 特别是如果有些方面你基本上无法在LINQ to SQL(或任何提供程序)中实现你正在使用)。例如,您可能希望构建一个特定的内存表示形式,该表示形式不适合提供者的模型。
答案 2 :(得分:0)
您的代码应该是这样的..
var naId = UnitOfWork.SalesPhases.FirstOrDefault(p => p.PhaseName =="NA").SalesPhaseId;
var rejectedId = UnitOfWork.SalesPhases.FirstOrDefault(p => p.PhaseName =="Rejected").SalesPhaseId;
var data = UnitOfWork.Leads.Query().AsQueryable()
.Where(p =>(p.SalesPhaseId == naId || p.SalesPhaseId == rejectedId) &&
p.CreatedDate>= fromDate.Date && p.CreatedDate <= toDate.Date).Select(m =>
new
{
m.LeadId,
m.LeadOwnerId,
m.SalesPhaseId,
m.LeadActivities,
m.Employee,
m.SalesPhase,
m.CompanyName,
m.CreatedDate,
m.LeadHistories,
m.LeadAddresses
}).ToList();
首先,您需要使用.ToQueryable而不是.ToIEnumerable()。 其次,您不能在实体框架linq查询中使用.Date到datetime属性。这仅适用于列表和数组等内存中的集合。