如何仅比较 EF 中 DateTime 中的日期组件?

Posted

技术标签:

【中文标题】如何仅比较 EF 中 DateTime 中的日期组件?【英文标题】:How to compare only date components from DateTime in EF? 【发布时间】:2010-12-01 11:35:04 【问题描述】:

我有两个日期值,一个已存储在数据库中,另一个由用户使用 DatePicker 选择。用例是从数据库中搜索特定日期。

之前在数据库中输入的值始终具有 12:00:00 的时间分量,而从选取器输入的日期具有不同的时间分量。

我只对日期组件感兴趣,并想忽略时间组件。

在 C# 中进行这种比较的方法是什么?

另外,如何在 LINQ 中做到这一点?

更新: 在 LINQ to Entities 上,以下工作正常。

e => DateTime.Compare(e.FirstDate.Value, SecondDate) >= 0

【问题讨论】:

你也可以看看这个SO问题:***.com/questions/683037/how-to-compare-dates-in-c/… 【参考方案1】:

您可以为此使用 DbFunctions.TruncateTime() 方法。

e => DbFunctions.TruncateTime(e.FirstDate.Value) == DbFunctions.TruncateTime(SecondDate);

【讨论】:

【参考方案2】:

使用EntityFunctions 类来修剪时间部分。

using System.Data.Objects;    

var bla = (from log in context.Contacts
           where EntityFunctions.TruncateTime(log.ModifiedDate) ==  EntityFunctions.TruncateTime(today.Date)
           select log).FirstOrDefault();

来源:http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/84d4e18b-7545-419b-9826-53ff1a0e2a62/

更新

从 EF 6.0 及更高版本开始,EntityFunctions 被 DbFunctions 替换。

【讨论】:

仅注释EntityFunctions 已被弃用,取而代之的是System.Data.Entity.DbFunctions(至少)EF6。它可能比这更早。 我不会很快跳到这个解决方案,因为它真的很慢,更多信息:***.com/questions/22776843/… 似乎不适用于 SQLite 数据库。我得到“SQL 逻辑错误或缺少数据库没有这样的功能:TruncateTime”。【参考方案3】:

你也可以这样用:

DbFunctions.DiffDays(date1, date2) == 0

【讨论】:

【参考方案4】:

注意:在撰写此答案时,EF 关系尚不清楚(在撰写此答案后已将其编辑到问题中)。有关 EF 的正确方法,请查看Mandeeps answer。


您可以使用DateTime.Date 属性执行仅日期比较。

DateTime a = GetFirstDate();
DateTime b = GetSecondDate();

if (a.Date.Equals(b.Date))

    // the dates are equal

【讨论】:

比较日期很容易,但问题与无法将 .Date 属性转换为 SQL 的 LINQ to Entities 有关。 @MichaëlCarpentier:好点。显然它仍然解决了 OP 的问题。 这不会查询数据库,而是在事后处理 CLR/应用层中的数据。真正的解决方案是使用下面答案中指定的 EntityFunctions.TruncateTime(..) 函数,因为它将查询发送到数据库并允许在存储层完成处理。如果没有这个,您将无法在 Where / Count 子句中使用日期比较逻辑,然后对过滤后的数据进行进一步查询,因为您必须首先将部分结果拉入应用程序层,这在以下情况下可能会破坏交易处理大量数据。 @Marchy 是的,EntityFunctions.TruncateTime 这些天似乎是要走的路(它在 .NET 4 中可用,该版本是在提出这个问题后的第二年发布的)。 使用 System.Data.Entity.DbFunctions.TruncateTime() 方法。您需要添加对 EntityFramework 的引用【参考方案5】:

试试这个...比较两个 DateTimes 类型之间的 Date 属性效果很好:

PS。这是一个权宜之计,也是一种非常糟糕的做法,当您知道数据库可以带来数千条记录时,永远不要使用它......

query = query.ToList()
             .Where(x => x.FirstDate.Date == SecondDate.Date)
             .AsQueryable();

【讨论】:

P.S.:当 DateTimes 有 Time 值并且我只想比较 Date 时,我通常使用这种方式。 这是一个很糟糕的解决方案,查询会得到所有的记录,然后才过滤掉日期。如果数据库有数百万条记录,这将获取所有记录,然后才会过滤日期。非常糟糕的做法。 这是一个权宜之计,也是一种非常糟糕的做法,当您知道数据库可以带来数千条记录时,永远不要使用它。 如果您将评论添加到您的答案中,我将删除我的反对票。访问此页面的任何人都应该清楚您提出的解决方案是不好的,而无需阅读 cmets。 虽然一般来说是个坏主意,但这种方法极大地提高了小型记录集( 【参考方案6】:

我就是这样做的。

DateTime date_time_to_compare = DateTime.Now;
//Compare only date parts
context.YourObject.FirstOrDefault(r =>
                EntityFunctions.TruncateTime(r.date) == EntityFunctions.TruncateTime(date_to_compare));

【讨论】:

【参考方案7】:

如果你对 DB 实体使用 Date 属性,你会得到异常:

"The specified type member 'Date' is not supported in LINQ to Entities. Only initializers, entity members, and entity navigation properties are supported."

你可以这样使用:

  DateTime date = DateTime.Now.Date;

  var result = from client in context.clients
               where client.BirthDate >= date
                     && client.BirthDate < date.AddDays(1)
               select client;

【讨论】:

【参考方案8】:

您可以使用下面的链接来比较 2 个没有时间的日期:

private bool DateGreaterOrEqual(DateTime dt1, DateTime dt2)
        
            return DateTime.Compare(dt1.Date, dt2.Date) >= 0;
        

private bool DateLessOrEqual(DateTime dt1, DateTime dt2)
        
            return DateTime.Compare(dt1.Date, dt2.Date) <= 0;
        

比较函数返回 3 个不同的值:-1 0 1 表示 dt1>dt2, dt1=dt2, dt1

【讨论】:

为什么不直接返回 DateTime.Compare(dt1.Date, dt2.Date)?这满足了您的所有需求。【参考方案9】:

没有时间比这样尝试:

TimeSpan ts = new TimeSpan(23, 59, 59);
toDate = toDate.Add(ts);
List<AuditLog> resultLogs = 
    _dbContext.AuditLogs
    .Where(al => al.Log_Date >= fromDate && al.Log_Date <= toDate)
    .ToList();
return resultLogs;

【讨论】:

【参考方案10】:

//Linq 用户/编码员注意事项

这应该为您提供在使用来自用户的输入时检查日期是否在范围内的准确比较 - 例如日期选择器:

((DateTime)ri.RequestX.DateSatisfied).Date >= startdate.Date &&
        ((DateTime)ri.RequestX.DateSatisfied).Date <= enddate.Date

其中 startdate 和 enddate 是来自日期选择器的值。

【讨论】:

【参考方案11】:

这是一种不同的方法,但只有在 SecondDate 是您传入的变量时才有用:

DateTime startDate = SecondDate.Date;
DateTime endDate = startDate.AddDays(1).AddTicks(-1);
...
e => e.FirstDate.Value >= startDate && e.FirstDate.Value <= endDate

我觉得应该可以

【讨论】:

优秀。为我工作。这是我失踪的明确DateTime = x.Date;。如果我使用var,或者在比较中将值内联,它会失败并报告异常。谢谢。 很高兴它成功了,蒂姆。抱歉延迟回复 - 我有一段时间没有真正登录到 SO。 如果您将e.FirstDate.Value &lt;= endDate 更改为e.FirstDate.Value &lt; endDate,您可以删除.AddTicks(-1) @MarcodeZeeuw 你是对的,那肯定也可以。显示的条件表达式旨在用于精确开始和结束日期时间的包容性日期比较(假设日期范围值将传递给条件而不是在代码片段中设置。)IOW,条件被认为与日期时间值分开.【参考方案12】:

我认为这对你有帮助。

我做了一个扩展,因为我必须比较充满 EF 数据的存储库中的日期,因此 .Date 不是一个选项,因为它没有在 LinqToEntities 翻译中实现。

代码如下:

        /// <summary>
    /// Check if two dates are same
    /// </summary>
    /// <typeparam name="TElement">Type</typeparam>
    /// <param name="valueSelector">date field</param>
    /// <param name="value">date compared</param>
    /// <returns>bool</returns>
    public Expression<Func<TElement, bool>> IsSameDate<TElement>(Expression<Func<TElement, DateTime>> valueSelector, DateTime value)
    
        ParameterExpression p = valueSelector.Parameters.Single();

        var antes = Expression.GreaterThanOrEqual(valueSelector.Body, Expression.Constant(value.Date, typeof(DateTime)));

        var despues = Expression.LessThan(valueSelector.Body, Expression.Constant(value.AddDays(1).Date, typeof(DateTime)));

        Expression body = Expression.And(antes, despues);

        return Expression.Lambda<Func<TElement, bool>>(body, p);
    

那么你可以这样使用它。

 var today = DateTime.Now;
 var todayPosts = from t in turnos.Where(IsSameDate<Turno>(t => t.MyDate, today))
                                      select t);

【讨论】:

【参考方案13】:

要在 LINQ to Entities 中执行此操作,您必须使用 supported methods:

var year = someDate.Year;
var month = ...
var q = from r in Context.Records
        where Microsoft.VisualBasic.DateAndTime.Year(r.SomeDate) == year 
              && // month and day

很丑,但是可​​以,而且是在数据库服务器上完成的。

【讨论】:

【参考方案14】:

始终只比较 DateTime 的 Date 属性,而不是完整的日期时间。

当您进行 LINQ 查询时,请在查询中使用 date.Date,即:

var results = from c in collection
              where c.Date == myDateTime.Date
              select c;

【讨论】:

我收到错误消息“LINQ to Entities 不支持指定的类型成员 'Date'。仅支持初始化程序、实体成员和实体导航属性。”。有什么想法吗? 是的 - 您的提供商不直接处理 .Date 属性。你必须把它拿出来,然后再比较日期。 .Date 不能在 Linq To Entities 中使用,很遗憾。希望 MS 能尽快添加过载支持 总是比较 Date 属性?我用谷歌搜索了这条评论,因为我想知道这是否是最佳做法,即。 总是 使用 Date 属性,即使它类似于 candidate.Date &gt;= base.Date。从理论上讲,candidate.Date 时间必须 >= 12:00:00,因此使用 Date 属性是多余的,但我会坚持 Reed 的建议。

以上是关于如何仅比较 EF 中 DateTime 中的日期组件?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 EF 查询中执行日期比较?

如何仅比较 cosmos db 中的日期部分

向“datetime2”列添加值导致溢出。 EF Core 日期比较

在DateTime中,仅使用64位中的62位。负值不在规范中。我如何表示BC的日期?

仅更新 DATETIME 列中的 TZoffset

将模型中的DateTime格式化为仅在视图中的日期