【问题标题】:How to convert DateTime to TimeSpan in Entity Framework query如何在实体框架查询中将 DateTime 转换为 TimeSpan
【发布时间】:2016-10-02 22:57:25
【问题描述】:

我有这个使用 Entity Framework 6 的 LINQ 查询:

var timeCapturesQuery = Context.TimeCaptures
    .Where(t =>
        && t.StartDateTime.TimeOfDay < endTime
        && t.EndDateTime.TimeOfDay > startTime);

EndTime 和 StartTime 是 TimeSpan 类型的参数,StartDateTime 和 EndDateTime 是 datetime 表上的列。

不幸的是,我在运行时收到此错误:

LINQ to Entities 不支持指定的类型成员“TimeOfDay”。仅支持初始化程序、实体成员和实体导航属性。

如何在此 LINQ 查询中从 DateTime(即 SQL 中的 datetime 中的 time)获取 TimeSpan

【问题讨论】:

  • 抱歉,我看不出这有什么帮助。您将 DateTime 转换为字符串,然后再转换回 DateTime,然后调用引发错误的属性。另请记住,StartDateTime 是表中的列,而不是参数。
  • 什么 Paul said 可能有用。
  • 这个Solution怎么样

标签: c# sql-server entity-framework linq


【解决方案1】:

看起来DbFunctions.CreateTime 就是您要查找的内容:

当用作 LINQ to Entities 查询的一部分时,此方法调用 规范的 CreateTime EDM 函数来创建一个新的 TimeSpan 对象。

所以要在两次之间获得结果,您可以:

var timeCapturesQuery = Context.TimeCaptures.Where(t =>
        DbFunctions.CreateTime(t.StartDateTime.Hour, t.StartDateTime.Minute, t.StartDateTime.Second) < endTime &&
        DbFunctions.CreateTime(t.EndDateTime.Hour, t.EndDateTime.Minute, t.EndDateTime.Second) > startTime);

【讨论】:

  • 我猜这种方法的缺点是它会丢失亚秒级的 TimeSpan 值。
【解决方案2】:

LINQ to Entities 不支持 TimeOfDay 属性,因此您可以尝试改用 SqlFunctions.DatePart 方法。

您可能还应该将 TimeSpan 转换为 DateTimes 。

我认为这应该可行(假设 TimeSpan 是从一天开始的):

var now = DateTime.Now;
var today = new DateTime(now.Year, now.Month, now.Day); 

var endDateTime = today + endTime;
var startDateTime = today + startTime

var timeCapturesQuery = Context.TimeCaptures.Where(t => 
                            SqlFunctions.DatePart("timeofday", t.StartDateTime) < SqlFunctions.DatePart("timeofday", endDateTime)
                            && SqlFunctions.DatePart("timeofday", t.EndDateTime) > SqlFunctions.DatePart("timeofday", startDateTime));

编辑

如 cmets 中所述,DatePart 方法不支持特定属性 TimeOfTheDay。

也许EntityFunctions.DiffNanoseconds 方法会起作用:

var now = DateTime.Now;
var today = new DateTime(now.Year, now.Month, now.Day); 

var endDateTime = today + endTime;
var startDateTime = today + startTime

var timeCapturesQuery = Context.TimeCaptures.Where(t => 
                            EntityFunctions.DiffNanoseconds(t.StartDateTime, endDateTime).Value < 0
                            && EntityFunctions.DiffNanoseconds(t.EndDateTime, startDateTime).Value > 0);

编辑2

另一个更简单且我认为可行的选项就是比较日期时间。

我们已经将 TimeSpan 转换为 DateTimes,我们可以使用 LINQ to Entities 创建一个简单的条件,它应该可以工作,因为我们没有使用任何 DateTimes 属性。

var now = DateTime.Now;
var today = new DateTime(now.Year, now.Month, now.Day); 

var endDateTime = today + endTime;
var startDateTime = today + startTime

var timeCapturesQuery = Context.TimeCaptures.Where(t => t.StartDateTime < endDateTime && t.EndDateTime > startDateTime);

【讨论】:

  • DATEPART 没有“timeofday”参数。
【解决方案3】:

看起来Linq2db支持它。

https://github.com/linq2db/linq2db/blob/1ff760181717c73859ab3a5519f76943241d460f/Source/Linq/Expressions.cs

当然,使用新的 ORM 不是很好的选择。
但我认为这是 EF 表现后最薄弱的部分。
所以也许现在是重新考虑的好时机。

使用 Linq2db,您可以提供自定义 SQL 逻辑(您需要创建自己的表达式)。这对我来说从来没有必要,但您可以阅读this 了解更多详细信息。

【讨论】:

  • 不能选择退出 EF。
猜你喜欢
  • 2017-04-29
  • 2021-12-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多