从对象

时间:2015-07-31 15:51:29

标签: c# linq linq-to-sql

我已阅读了一些主题并且不确定如何从一个范围中获取最早和最晚的日期。

数据示例(为简洁而跳过大多数列)

CustID StartDate   EndDate
1       01/01/2015  01/01/2015
2       03/01/2015  03/01/2015
3       03/01/2015  05/01/2015
4       03/01/2015  10/01/2015

用户界面允许用户从日历控件中选择日期。然后它应该获得落在上述范围内的所有日期,因此如果用户选择

02/01/2015 - 由于没有startDateEndDate与此日期/范围匹配,因此不会返回任何内容

如果他们选择01/01/2015,那么我希望得到以下日期

01/01/2015
03/01/2015
04/01/2015
05/01/2015
.... to 10/01/2015

请注意日期 02/01/2015不包含

如果用户选择03/01/2015,那么它将返回截至2015年1月10日的所有日期。

为了达到这个目的,我编写了代码

public List<DateTime> GetDates()
{

    IEnumerable<Customers> Dates = dc.Customers.Where(d => d.StartDate.Value >= DateTime.Now );

    DateTime FromDate = Dates.Where(f => f.StartDate.HasValue).Min(f => f.StartDate).Value;
    DateTime ToDate = Dates.Where(t => t.EndDate.HasValue).Max(f => f.EndDate).Value;

    IEnumerable<DateTime> AllDates = Enumerable.Range(0, int.MaxValue)
                 .Select(x => FromDate.Date.AddDays(x))
                 .TakeWhile(x => x <= ToDate.Date);

    return AllDates.ToList();
}

但它没有返回我预期的日期。使用此代码,如果我选择01/01/2015,它会返回所有日期?我哪里错了?

2 个答案:

答案 0 :(得分:0)

我的猜测是,他正在尝试使用其他客户已经选择的日期来填充日历控件,因此用户无法选择它们,但他正在尝试减少返回到较小集合的项目数。当然,示例数据是错误的,因为它已经有重叠的日期,所以......

第一遍:

public List<DateTime> GetDates()
{

    IEnumerable<Customers> Dates = dc.Customers
      .Where(d => d.StartDate.Value >= DateTime.Now);

    var FromDate = Dates.Where(f => f.StartDate.HasValue)
      .Min(f => f.StartDate).Value;
    var ToDate = Dates.Where(t => t.EndDate.HasValue)
      .Max(f => f.EndDate).Value;


    IEnumerable<DateTime> AllDates = Enumerable.Range(0, int.MaxValue)
                 .Select(x => FromDate.Date.AddDays(x))
                 .TakeWhile(x => x <= ToDate.Date)
                 .Where(x=>dc.Customers.Any(c=>x>=c.StartDate && x<=c.EndDate));

    return AllDates.ToList();
}

这是一个更好的解决方案,但返回所有范围内的所有日期,通过在需要的地方添加where子句进一步减少。如果你真的想要排除没有startdate&gt; =你的选择的所有范围,或者如果你真的想要包含它们,那么将它放在.ToList之前,但不要返回部分是&lt;你的选择(更有可能)。

public List<DateTime> GetDates()
{
    return db.Customers
      .ToList()
      .Select(pair =>
             Enumerable.Range(0,(int)(pair.EndDate - pair.StartDate).TotalDays+1)
                       .Select(days => pair.StartDate.AddDays(days)))
      .SelectMany(x=>x)
      .Distinct();
}

加成:

/* DateTime extension for ranges of dates */
public static class DateTimeExtensions
{
    public static IEnumerable<DateTime> EnumerableTo(this DateTime self, DateTime toDate)
    {
        for(var d=self;d<=toDate;d=d.Date.AddDays(1))
           yield return d;
    }
}
void Main()
{
    /* Your example data */
    var Customers=new [] {
      new { id=1,StartDate=new DateTime(2015,1,1),EndDate=new DateTime(2015,1,1)},
      new { id=2,StartDate=new DateTime(2015,1,3),EndDate=new DateTime(2015,1,3)},
      new { id=3,StartDate=new DateTime(2015,1,3),EndDate=new DateTime(2015,1,5)},
      new { id=4,StartDate=new DateTime(2015,1,3),EndDate=new DateTime(2015,1,10)},
    };

    /* The query */
    var results=Customers
       .Select(pair => pair.StartDate.EnumerableTo(pair.EndDate))
       .SelectMany(x=>x)
       .Distinct();

    results.Dump();
}

答案 1 :(得分:0)

如果你想要的是所有客户的开始日期和结束日期的联合,其中startdate大于用户选择的日期,那么为什么不是

return (from costumer in dc.Customers select costumer.startdate
           where costumer.startdate > UserSelectedDate)
   .Union
       (from costumer in dc.Customers select costumer.enddate
           where costumer.startdate > UserSelectedDate)
   .Distinct()

如果您想要的是所有用户选择的开始日期和结束日期都在该范围内,那么您可以

return (from costumer in dc.Customers select costumer.startdate
           where costumer.startdate <= UserSelectedDate and
                 UserSelectedDate <= costumer.enddate)
   .Union
       (from costumer in dc.Customers select costumer.enddate
           where costumer.startdate <= UserSelectedDate and
                 UserSelectedDate <= costumer.enddate)
   .Distinct()