Linq-Entities:获取不包含重叠数据范围的数据,选择最大的周期

问题描述

|| 我有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);