我需要编写一个/多个LINQ查询来获取我将为报告显示的一些数据。
我需要使用的表是StaffingResources,StaffingForecastEvents(将StaffingResource链接到项目)和StaffingForecasts(链接到StaffingForecastEvents并包含每周的小时数)。每个StaffingResource可以有0多个StaffingForecastEvents,而StaffingForecastEvent可以有0多个StaffingForecasts。
我需要编写LINQ查询,对于每个资源,它将包含他们拥有ForecastEvents的所有项目,以及每个项目在给定日期范围内的所有预测(12周或6个月) 。这是我到目前为止所做的,而且运行速度很慢。
// Get date ranges
var dates = new List<DateTime>();
var startDate = range == (int)RangeTypes.WEEKLY
? DateTime.Today.AddDays(DayOfWeek.Monday - DateTime.Today.DayOfWeek)
: new DateTime(DateTime.Today.Year, DateTime.Today.Month, 1);
for (var i = 0; i < (range == (int)RangeTypes.WEEKLY ? 4 : 6); i++)
{
dates.Add(range == (int)RangeTypes.WEEKLY ? startDate.AddDays(i * 7) : startDate.AddMonths(i));
}
var endDate = dates[dates.Count-1];
// Get resources
var resources = from r in context.StaffingResourceDatas
where r.EmployeeId.HasValue
&& (resourceIds.Count == 0 || resourceIds.Contains(r.EmployeeId.Value))
&& (resourceDivisions.Count == 0 || resourceDivisions.Contains(r.ResourceDivisionId))
&& (resourceTitles.Count == 0 || resourceTitles.Contains(r.ResourceTitleId))
&& (resourceLocations.Count == 0 || resourceLocations.Contains(r.ResourceLocationId))
&& (supervisors.Count == 0 || supervisors.Contains(r.ReportsToId))
&& (showAllResources || (!showAllResources && !exclusionList.Contains(r.ResourceTitleId)))
join fe in context.StaffingForecastEvents
.Include(x => x.StaffingForecasts)
.Include(x => x.StaffingUser)
.Include(x => x.StaffingUser1)
.Include(x => x.StaffingForecasts.Select(y => y.StaffingUser))
.Include(x => x.StaffingForecasts.Select(y => y.StaffingUser1))
on r.ResourceId equals fe.ResourceId into g1
from fe in g1.DefaultIfEmpty()
join p in context.StaffingProjectDatas on fe.JobNumber equals p.JobNumber into g2
from p in g2.DefaultIfEmpty()
group new { ForecastEvent = fe, Project = p } by r into g3
select new
{
ResourceId = g3.Key.ResourceId,
Name = g3.Key.ResourceName,
Title = g3.Key.ResourceTitle,
Division = g3.Key.ResourceDivision,
Location = g3.Key.ResourceLocation,
AvailableDate = g3.Key.AvailableDate,
SupervisorEmail = g3.Key.ManagerEmail,
Projects = g3.Where(p => p.ForecastEvent != null).Select(p => new
{
JobNumber = p.ForecastEvent.JobNumber,
Description = p.Project.ProjectDescription,
Name = p.Project.ProjectName,
Division = p.Project.ProjectDivision,
ProjectManager = p.Project.PMName,
Notes = p.ForecastEvent.Notes,
LogDate = p.ForecastEvent.LogDate,
LogUser = p.ForecastEvent.StaffingUser.Name,
AckDate = p.ForecastEvent.AcknowledgeDate,
AckUser = p.ForecastEvent.StaffingUser1 != null ? p.ForecastEvent.StaffingUser1.Name : null,
Usages = dates.Select(d => new
{
Date = d,
Hours = (range == (int)RangeTypes.WEEKLY)
? (p.ForecastEvent.StaffingForecasts.Where(f => f.Date == d).Any() ? p.ForecastEvent.StaffingForecasts.Where(f => f.Date == d).Sum(f => f.Hours) : 0)
: (p.ForecastEvent.StaffingForecasts.Where(f => f.Date.Year == d.Year && f.Date.Month == d.Month).Any() ? p.ForecastEvent.StaffingForecasts.Where(f => f.Date.Year == d.Year && f.Date.Month == d.Month).Sum(f => f.Hours) : 0),
LogDate = (range == (int)RangeTypes.WEEKLY)
// Get acknowledge or log date for week
? (p.ForecastEvent.StaffingForecasts.Where(f => f.Date == d).Any()
? ((p.ForecastEvent.StaffingForecasts.FirstOrDefault(f => f.Date == d).AcknowledgeDate) != null)
? (p.ForecastEvent.StaffingForecasts.FirstOrDefault(f => f.Date == d).AcknowledgeDate)
: (p.ForecastEvent.StaffingForecasts.FirstOrDefault(f => f.Date == d).LogDate)
: null)
// Get acknowledge or log date for most recent forecast for month
: (p.ForecastEvent.StaffingForecasts.Where(f => f.Date.Year == d.Year && f.Date.Month == d.Month).Any()
? ((p.ForecastEvent.StaffingForecasts.Where(f => f.Date.Year == d.Year && f.Date.Month == d.Month).OrderByDescending(f => f.LogDate).FirstOrDefault().AcknowledgeDate) != null)
? (p.ForecastEvent.StaffingForecasts.Where(f => f.Date.Year == d.Year && f.Date.Month == d.Month).OrderByDescending(f => f.LogDate).FirstOrDefault().AcknowledgeDate)
: (p.ForecastEvent.StaffingForecasts.Where(f => f.Date.Year == d.Year && f.Date.Month == d.Month).Max(f => f.LogDate))
: null),
LogUser = (range == (int)RangeTypes.WEEKLY)
// Get acknowledge or log user for week
? (p.ForecastEvent.StaffingForecasts.Where(f => f.Date == d).Any()
? ((p.ForecastEvent.StaffingForecasts.FirstOrDefault(f => f.Date == d).AcknowledgeDate) != null)
? (p.ForecastEvent.StaffingForecasts.FirstOrDefault(f => f.Date == d).StaffingUser1.Name)
: (p.ForecastEvent.StaffingForecasts.FirstOrDefault(f => f.Date == d).StaffingUser.Name)
: null)
// Get acknowledge or log user for most recent forecast for month
: (p.ForecastEvent.StaffingForecasts.Where(f => f.Date.Year == d.Year && f.Date.Month == d.Month).Any()
? ((p.ForecastEvent.StaffingForecasts.Where(f => f.Date.Year == d.Year && f.Date.Month == d.Month).OrderByDescending(f => f.LogDate).FirstOrDefault().AcknowledgeDate) != null)
? (p.ForecastEvent.StaffingForecasts.Where(f => f.Date.Year == d.Year && f.Date.Month == d.Month).OrderByDescending(f => f.LogDate).FirstOrDefault().StaffingUser1.Name)
: (p.ForecastEvent.StaffingForecasts.Where(f => f.Date.Year == d.Year && f.Date.Month == d.Month).OrderByDescending(f => f.LogDate).FirstOrDefault().StaffingUser.Name)
: null),
})
})
};
我还需要为每个日期范围获取每个资源的总计。
我觉得瓶颈可能出现在所有&#34; Where&#34; s循环过去的日期,但我不知道还能做什么。有什么想法吗?
答案 0 :(得分:1)
作为起点,您可以使用IQueryable<T>
将其拆分为多个表达式。它还可以帮助您简化where子句。这看起来像是:
var queryable = context.StaffingResourceDatas.Where(r => r.EmployeeId.HasValue);
if(resourceIds.Any())
{
queryable = queryable.Where(r => resourceIds.Contains(r.EmployeeId.Value))
}
请注意,仅当resourceIds不为空时,这将生成与resourceIds过滤相关的SQL,从而可能节省在生成的查询本身中检查它的开销。
您可以使用与此类似的方式编写其余过滤器。另请注意,在您调用ToList()
之前,查询将不会执行。因此,您可以继续添加任意数量的子句,直到您完成构建它。
但是在一天结束时你可能会考虑在原始SQL中编写这个,因为它只是,你知道,这是巨大的。