问题描述
||
我有2表,导入和期间。
导入具有以下结构:
AdminID,PeriodID,Some more fields
1,1
1,2
1,6
1,50
期间表具有以下结构:
PeriodID,PeriodType,StartDate,EndDate,Description
1,1,2007-01-01,2007-12-31,Year 2007
2,2,2007-03-31,Quarter 1 2007
3,2007-04-01,2007-06-30,Quarter 2 2007
4,2007-07-01,2007-09-30,Quarter 3 2007
5,2007-10-01,Quarter 4 2007
6,3,2007-01-31,January 2007
.
.
.
50,2011-01-01,2011-03-31,Quarter 1 2011
现在,我需要构建一个linq查询,以基于Imports表中的数据仅获取最大的周期(忽略较小的重叠周期)!
当我查询AdminID = 1时,我应该只获得PeriodID = 1和50,忽略/排除PeriodID 2和6,因为它们在1和50中重叠,因为还没有重叠的数据!
解决方法
您可以通过比较两个表中的PeriodID来最大程度地帮助您选择最大的期间并检索值。
,我不确定在数据库中是否有方便的方法,但是在本地提取数据时,如果合适的话,可以进行内存中的LINQ查询。您需要在您的步骤中执行此操作。
步骤1:定义一个
Range
类,使您可以对期间进行比较(请参见下文)。
步骤2:从数据库中提取期间:
var ranges = (
from period in context.Periods
where period.Imports.Any(i => i.AdminID == adminId)
select new Range(period.StartDate,period.EndDate.AddDays(1)))
.ToArray();
注意the4将所有东西都拉到本地。
步骤3:将所有期间汇总/合并为非重叠期间列表:
var mergedPeriods = (
from range in ranges
select ranges.Where(p => p.OverlapsWith(range))
.Aggregate((r1,r2) => r1.Merge(r2)))
.Distinct();
为此,您需要一个专门设计的包含2个类型的方法,其中包含7个方法,8个方法和9个方法。它可能看起来像这样:
public class Range : IEquatable<Range>
{
public Range(DateTime start,DateTime exclusiveEnd)
{
if (exclusiveEnd < start)
throw new ArgumentException();
this.Start = start; this.End = exclusiveEnd;
}
public DateTime Start { get; private set; }
public DateTime End { get; private set; }
public TimeSpan Duration { get { return this.End - this.Start; } }
public Range Merge(Range other)
{
if (!this.OverlapsWith(other)) throw new ArgumentException();
var start = this.Start < other.Start ? this.Start : other.Start;
var end = this.End > other.End ? this.End : other.End;
return new Range(start,end);
}
public bool Contains(Range other)
{
return this.Start <= other.Start && this.End > other.End;
}
public bool OverlapsWith(Range other)
{
return this.OverlapsOnStartWith(other) ||
other.OverlapsOnStartWith(this) ||
this.Contains(other) ||
other.Contains(this);
}
private bool OverlapsOnStartWith(Range other)
{
return this.Start >= other.Start && this.Start < other.End;
}
public bool Equals(Range other)
{
return this.Start == other.Start && this.End == other.End;
}
}
我希望这有帮助。
,好吧,经过长时间的奋斗,我确实找到了答案!用一个查询到数据库!
并且为每个人的利益张贴相同的内容。
var oImportPeriods =
from o in Imports
where o.Administration.AdminID == 143
orderby o.Period.PeriodID
select o.Period;
var oIgnorePeriodList = (
from oPeriod in oImportPeriods
from oSearchPeriod in oImportPeriods
.Where(o => o.PeriodID != oPeriod.PeriodID)
where oPeriod.StartDate >= oSearchPeriod.StartDate
where oPeriod.EndDate <= oSearchPeriod.EndDate
select oPeriod.PeriodID)
.Distinct();
var oDeletablePeriods = oAdministrationPeriods
.Where(o => !oIgnorePeriodList.Contains(o.PeriodID));
foreach(var o in oDeletablePeriods)
Console.WriteLine(o.Name);