如何使用LINQ查询商品,但还包括缺少的商品?
时间:2020-03-06 14:53:30 来源:igfitidea点击:
我正在尝试在我们的注册系统中绘制每天的注册数量。我在sql server中有一个Attendee表,该表具有smalldatetime字段A_DT,这是该人注册的日期和时间。
我从这个开始:
var dailyCountList = (from a in showDC.Attendee let justDate = new DateTime(a.A_DT.Year, a.A_DT.Month, a.A_DT.Day) group a by justDate into DateGroup orderby DateGroup.Key select new RegistrationCount { EventDateTime = DateGroup.Key, Count = DateGroup.Count() }).ToList();
效果很好,但是不会包含没有注册的日期,因为这些日期没有与会者记录。我希望包括每个日期,并且当没有给定日期的数据时,计数应仅为零。
所以这是我目前可以使用的解决方案,但我知道这很糟糕。
我在上面的代码中添加了以下内容:
// Create a new list of data ranging from the beginning to the end of the first list, specifying 0 counts for missing data points (days with no registrations) var allDates = new List<RegistrationCount>(); for (DateTime date = (from dcl in dailyCountList select dcl).First().EventDateTime; date <= (from dcl in dailyCountList select dcl).Last().EventDateTime; date = date.AddDays(1)) { DateTime thisDate = date; // lexical closure issue - see: http://www.managed-world.com/2008/06/13/LambdasKnowYourClosures.aspx allDates.Add(new RegistrationCount { EventDateTime = date, Count = (from dclInner in dailyCountList where dclInner.EventDateTime == thisDate select dclInner).DefaultIfEmpty(new RegistrationCount { EventDateTime = date, Count = 0 }).Single().Count }); }
因此,我创建了另一个列表,并循环查询根据查询中的第一个和最后一个注册生成的日期序列,对于日期序列中的每个项目,我查询第一个查询的结果以获取有关给定信息的信息日期,如果没有任何反应,则提供默认值。因此,我最终在这里进行了子查询,因此我想避免这种情况。
谁能提供一个优雅的解决方案?还是至少一个没有那么尴尬的东西?
解决方案
O(n)有2个枚举。尝试执行此操作之前,最好将这些项目拉到内存中。数据库有足够的工作要做而无需考虑这些东西。
if (!dailyCountList.Any()) return; //make a dictionary to provide O(1) lookups for later Dictionary<DateTime, RegistrationCount> lookup = dailyCountList.ToDictionary(r => r.EventDateTime); DateTime minDate = dailyCountList[0].EventDateTime; DateTime maxDate = dailyCountList[dailyCountList.Count - 1].EventDateTime; int DayCount = 1 + (int) (maxDate - minDate).TotalDays; // I have the days now. IEnumerable<DateTime> allDates = Enumerable .Range(0, DayCount) .Select(x => minDate.AddDays(x)); //project the days into RegistrationCounts, making up the missing ones. List<RegistrationCount> result = allDates .Select(d => lookup.ContainsKey(d) ? lookup[d] : new RegistrationCount(){EventDateTime = d, Count = 0}) .ToList();
那么,左外部联接的这种语法在SP1之后是否不再有效?
通常,我们应该能够执行以下操作,但是我们需要将SQL数据库中的各种日历表与注册表中的日期键(在日期ID字段上带有外键)相结合,然后尝试:
var query = from cal in dataContext.Calendar from reg in cal.Registrations.DefaultIfEmpty() select new { cal.DateID, reg.Something };
问题是我们不执行查询就没有日期范围。因此,我们可以选择一个日期范围,对数据库运行SELECT MAX和SELECT MIN,或者执行查询,然后添加缺少的日期。
var allDailyCountList = from d in Range(dc[0].EventDateTime, dc[dc.Count - 1].EventDateTime) // since you already ordered by DateTime, we don't have to search the entire List join dc in dailyCountList on d equals dc.EventDateTime into rcGroup from rc in rcGroup.DefaultIfEmpty( new RegistrationCount() { EventDateTime = d, Count = 0 } ) // gives us a left join select rc; public static IEnumerable<DateTime> Range(DateTime start, DateTime end) { for (DateTime date = start, date <= end; date = date.AddDays(1)) { yield return date; } }