【问题标题】:Linq to SQL to select rows whose DateTime field falls within any of a list of date rangesLinq to SQL 选择 DateTime 字段在任何日期范围列表中的行
【发布时间】:2023-03-07 09:42:01
【问题描述】:

我有一个包含 StartDate 和 EndDate 属性的 DateRange 对象列表。我需要从我的数据库中的表中选择所有行,这些行的 DateTime 字段属于这些 DateRanges 中的任何一个。所以我想做这样的事情:

// Using an IQueryable<DateRange> called dateRanges
var tests = from test in dbContext.Tests
            where dateRanges.Any(range => range.StartDate <= test.Date && range.EndDate >= test.Date)
            select test

这给了我一个错误,因为 DateRange 不是原始类型,因此 LINQ to SQL 无法使用它。有没有其他方法可以做我在这里想做的事情?几个小时以来一直在谷歌搜索和尝试不同的事情,我觉得我很接近但不能完全到达那里。提前致谢。

【问题讨论】:

  • 我对@9​​87654322@ 不太满意,但你能比较一下他们的.Ticks 的价值吗?
  • 好吧,问题不在于比较 DateTime 值,而是 DateRange 不是原始类型,因此它不能被转换为 SQL 可以使用的任何内容以使操作发生服务器端。
  • 你可以建立一个 TSQL 查询来代替吗?
  • @Malleus 对我来说有点奇怪,可以试试dateRanges.Any(x=&gt;true)吗?
  • 您的 StartDate 和 EndDate 属性是什么类型的?

标签: c# linq linq-to-sql linq-to-entities


【解决方案1】:

尝试使用 Linq2Sql 与动态查询类似

(p => value1.StartDate <= p.Date && value1.EndDate >= p.Date) || (p => value2.StartDate <= p.Date && value2.EndDate >= p.Date)

示例:Linq2SQL "or/and" operators (ANDed / ORed conditions)

【讨论】:

    【解决方案2】:

    为了保证没有不必要的数据被传输,我决定这样做的方法是在我的数据库上创建一个名为 GetTestsInDateRange 的存储过程,它接受开始和结束日期并返回其中的所有测试范围。然后在我的代码中,我循环遍历我的 DateRanges 列表,为每个 DateRange 调用一次存储过程,并将结果合并在一起。

    IEnumerable<Test> tests = new List<Test>();
    foreach (DateRange range in selectedDateRanges)
    {
        tests = tests.Union(dbContext.GetTestsInDateRange(range.StartDate, range.EndDate));
    }
    

    我不知道这是否是理想的解决方案(可能取决于选择了多少 DateRanges 以及它对数据库进行了多少单独调用),但它适用于我的场景。

    【讨论】:

      【解决方案3】:

      通过连接每个范围的条件来制作您自己的 SQL 语句,部分限制您返回的结果的一种方法是使用范围的最小和最大日期,然后在 Linq-To-Objects 中进一步过滤:

      var minStartDate = dateRanges.Min(r => r.StartDate);
      var maxEndDate = dateRanges.Max(r => r.EndDate);
      var tests = (from test in dbContext.Tests
                  where minStartDate <= test.Date && maxEndDate >= test.Date
                  select test)
                  .AsEnumerable()  // change to Linq-To-Objects
                  .Where(test => dateRanges.Any(range => range.StartDate <= test.Date 
                                                         && range.EndDate >= test.Date));
      

      这对于一个范围来说是完美的,除非你的范围之间有很大的差距,否则只会稍微差一点。

      【讨论】:

      • 如果您要比较大量数据,将所有数据全部取走,然后使用 linq2objects,这不是一个好主意。会杀死你的服务器
      猜你喜欢
      • 1970-01-01
      • 2019-09-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-03-15
      • 1970-01-01
      相关资源
      最近更新 更多