You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在EF Core中检查指定日期范围是否被数据表日期范围完全覆盖?

解决方案

首先明确两种需求场景,对应不同的实现方式:

场景1:找单个SupportItem完全包含检查范围

如果你的需求确实是给定日期范围完全落在某一条SupportItem的日期区间内(即检查的开始日期≥SupportItem.StartDate,检查的结束日期≤SupportItem.EndDate),那你原来的代码逻辑是正确的,但你的示例2预期结果应该是false(因为没有任何一条SupportItem的区间能包含09/02/2023 - 23/02/2023)。如果要优化代码的可读性,可以简化嵌套的Where和Any:

var checkStart = checkRequest.ActivityStartDate.Date;
var checkEnd = checkRequest.ActivityEndDate.Date;

var isSingleRangeCovered = activePlans
    .SelectMany(z => z.ServicePlanBudgetTypes)
    .SelectMany(y => y.SupportItems)
    .Any(x => x.StartDate.Date <= checkStart 
           && x.EndDate.HasValue 
           && x.EndDate.Value.Date >= checkEnd);

场景2:检查范围被多个SupportItem的区间联合覆盖

从你的示例来看,实际需求应该是给定日期范围的每一天都被至少一个SupportItem的区间覆盖(比如09/02/2023属于第一条,10/02-23/02属于第二条,联合覆盖整个检查范围)。这种情况需要先获取所有与检查范围有交集的SupportItem区间,合并连续/重叠的区间后,再检查是否能完全覆盖目标范围:

步骤1:获取相关的SupportItem区间

var checkStart = checkRequest.ActivityStartDate.Date;
var checkEnd = checkRequest.ActivityEndDate.Date;

// 获取所有与检查范围有交集的SupportItem,处理EndDate为null的情况(视为永久有效)
var relevantRanges = activePlans
    .SelectMany(z => z.ServicePlanBudgetTypes)
    .SelectMany(y => y.SupportItems)
    .Where(x => x.StartDate.Date <= checkEnd 
             && (x.EndDate == null || x.EndDate.Value.Date >= checkStart))
    .Select(x => new {
        Start = x.StartDate.Date,
        End = x.EndDate?.Date ?? DateTime.MaxValue.Date
    })
    .OrderBy(r => r.Start)
    .ToList();

步骤2:合并连续/重叠的区间

if (!relevantRanges.Any())
{
    // 没有任何相关区间,直接返回false
    return false;
}

var mergedRanges = new List<(DateTime Start, DateTime End)>();
mergedRanges.Add((relevantRanges[0].Start, relevantRanges[0].End));

foreach (var range in relevantRanges.Skip(1))
{
    var lastMerged = mergedRanges.Last();
    // 如果当前区间的开始日期与上一个合并区间连续或重叠,则合并
    if (range.Start <= lastMerged.End.AddDays(1))
    {
        var newEnd = lastMerged.End > range.End ? lastMerged.End : range.End;
        mergedRanges.RemoveAt(mergedRanges.Count - 1);
        mergedRanges.Add((lastMerged.Start, newEnd));
    }
    else
    {
        mergedRanges.Add((range.Start, range.End));
    }
}

步骤3:检查合并后的区间是否完全覆盖目标范围

bool isFullyCovered = true;
DateTime currentDate = checkStart;

foreach (var range in mergedRanges)
{
    if (currentDate > checkEnd)
        break;
    
    // 存在未覆盖的缺口
    if (range.Start > currentDate)
    {
        isFullyCovered = false;
        break;
    }
    
    // 更新当前覆盖到的日期(range.End是包含的,所以下一个要检查的是range.End+1)
    currentDate = range.End.AddDays(1);
}

// 检查是否覆盖到了检查范围的结束日期之后
if (currentDate <= checkEnd)
{
    isFullyCovered = false;
}

// isFullyCovered就是最终结果

这个实现会处理你的示例场景:

  • 示例1(09/02-24/02):24/02不在任何区间内,isFullyCovered返回false
  • 示例2(09/02-23/02):合并后的区间是08/02-23/02,完全覆盖目标范围,返回true

内容的提问来源于stack exchange,提问作者hanushi-thana

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 04:46:48