【问题标题】:How can I discard the time part of a DateTime in an OData query?如何在 OData 查询中丢弃 DateTime 的时间部分?
【发布时间】:2017-08-01 21:14:12
【问题描述】:

我们的数据库实体具有没有时间分量的日期属性,例如2017-01-01.

我们的第三方前端组件支持根据用户选择自动构建 OData 查询,因此,如果我想查找开始日期在 1/1/2017 之后的所有实体,生成的查询字符串如下所示:

http://localhost/odata/Entities?$top=20&$filter=StartDate ge 2017-01-01T00:00:00Z&$count=true

这很好,时间部分是零,所以应该没关系...除了...框架生成的 SQL 转换为:

WHERE ([Extent1].[StartDate] >= convert(datetime2, '2017-01-01 02:00:00.0000000', 121))

请注意,现在它添加了两个小时的时间偏移量(基于我们的时区),这意味着我们正在保存的日期 (2017-01-01) 超出了过滤器的范围。因此,如果我们想查看2017-01-01 的记录,我们需要将过滤器设置为2016-12-31

API 控制器上的代码如下所示:

[EnableQuery(MaxNodeCount = DefaultMaxNodeCount)] public IQueryable<Entity> Get() { IQueryable<Entity> entities = Service.GetViews(); return entities; }

然后代码进入依赖注入和实体框架等的兔子洞。如果我在那个 Get 方法上放置一个断点,那么entities 集合拥有所有数据,而没有应用 OData 魔法它。控制器确实是我唯一可以(也许?)更改传入查询以确保时间部分不会传递给 SQL 的点;也是我控制代码的唯一地方。但我不知道该怎么做。

我查看了创建一个继承自 FilterQueryValidator 的自定义属性。我希望这将是答案,但我不知道该怎么做。我可以看到正在过滤的字段的名称,但看不到实际的过滤器值,然后看起来它是只读的。

更新:

在使用 Postman 进行测试时,我发现如果我发送一个没有时间的日期,它会按预期工作;

http://localhost/odata/Entities?$top=20&amp;$filter=StartDate ge 2017-01-01&amp;$count=true

随后生成的 SQL:

WHERE ([Extent1].[StartDate] &gt;= convert(datetime2, ''2017-01-01 00:00:00.0000000'', 121))

这给了我正确的数据集。

【问题讨论】:

  • 您是否考虑过以 UTC 时间转换和存储您的日期,并且只使用本地时间作为 UI?
  • 我们正在这样做,但它有自己的一系列相关问题。理想情况下,我们根本不希望时间组件成为这里的一个因素。
  • 好的,只要你们意识到时间也会影响用户在另一个时区并且接近午夜的日期。
  • 是的,这正是导致问题的原因:(
  • 前端应用程序必须知道准确的时间。在应用程序中,您必须在发送查询之前转换为服务器的时间

标签: c# entity-framework model-view-controller odata


【解决方案1】:

没有时间的DateTime 的替代解决方案是使用Microsoft.OData.Edm.Date,这是一种没有时间组件的日期类型。 这是在 NuGet 包 Microsoft.OData.Edm 中定义的(仅支持 OData4)。

【讨论】:

  • 谢谢。几天前我研究了一下。当我使用 Postman 提交数据时效果很好,但是当我使用 3rd 方控件时,它们通过 DateTimeOffset 发送,并且 odata 抱怨 Edm.Date 和 DateTimeOffset 之间的类型不匹配,所以它没有解决问题.
  • 好的,第三方系统不兼容且无法更改,这不是解决方案。但对于那些控制双方的人来说,这可能是一个值得考虑的解决方案。
【解决方案2】:

DateTime.Date Property 将返回

与此实例具有相同日期的新对象,时间值设置为午夜 12:00:00 (00:00:00)。

如果您想摆脱时区信息,可以使用返回的DateTime.ToLocalTime Method ()

Kind 属性为 Local 的对象,其值为与当前 DateTime 对象的值等价的本地时间

所以基本上你可以把两者放在一起

var date = dateWithTimezone.ToLocalTime().Date

【讨论】:

  • 嗨@Ruapho,问题不在于如何操作 DateTime 对象以仅提取日期,而是更多如何操作 OData 查询以将 DateTime 组件替换为仅日期组件。
猜你喜欢
  • 2017-05-30
  • 1970-01-01
  • 2012-04-30
  • 1970-01-01
  • 1970-01-01
  • 2014-09-01
  • 2015-06-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多