【发布时间】: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&$filter=StartDate ge 2017-01-01&$count=true
随后生成的 SQL:
WHERE ([Extent1].[StartDate] >= convert(datetime2, ''2017-01-01 00:00:00.0000000'', 121))
这给了我正确的数据集。
【问题讨论】:
-
您是否考虑过以 UTC 时间转换和存储您的日期,并且只使用本地时间作为 UI?
-
我们正在这样做,但它有自己的一系列相关问题。理想情况下,我们根本不希望时间组件成为这里的一个因素。
-
好的,只要你们意识到时间也会影响用户在另一个时区并且接近午夜的日期。
-
是的,这正是导致问题的原因:(
-
前端应用程序必须知道准确的时间。在应用程序中,您必须在发送查询之前转换为服务器的时间
标签: c# entity-framework model-view-controller odata