我正在使用OData Query v4和SQL Server 2012运行一个简单的.NET Core WebApi应用程序。
这可行,但是速度非常慢:
GET /api-endpoint?$filter=date(MyDateTimeField) ge 2018-01-01&$top=100
上面的URL生成的SQL查询:
SELECT TOP 100 * FROM MyTable WHERE ((((DATEPART(year, [MyDateTimeField]) * 10000) + (DATEPART(month, [MyDateTimeField]) * 100)) + DATEPART(day, [MyDateTimeField])) >= (((2018 * 10000) + (1 * 100)) + 1))
当我尝试这样做时:
GET /api-endpoint?$filter=MyDateTimeField ge 2018-01-01T00:00:00.00Z&$top=100
它将生成以下SQL查询:
SELECT TOP 100 * FROM MyTable WHERE [MyDateTimeField] > '2018-01-01T00:00:00.0000000'
哪个返回此错误:
从字符转换日期和/或时间时转换失败 字符串。
OData查询语法将是什么以生成与此类似的SQL查询?
SELECT TOP 100 * FROM MyTable WHERE [MyDateTimeField] > '2018-01-01'
答案 0 :(得分:0)
假设MyDateTimeField
的字段是 datetime
而不是 datatime2
,请用{列注释 MyDateTimeField
首先:
[Column(TypeName="datetime")]
要使用public class MyTable
{
// ... other props
[Column(TypeName="datetime")]
public DateTime MyDateTimeField {get;set;}
}
进行查询,请 datetime
到 cast
:
DateTimeOffset
生成的?$filter=MyDateTimeField ge cast(2018-01-01T00:00:00.00Z,Edm.DateTimeOffset)
类似于:
sql
请注意,上面的 SELECT ..., [$it].[MyDateTimeField],
FROM [MyTable] AS [$it]
WHERE [$it].[MyDateTimeField] >= '2018-01-01T08:00:00.000'
是 datetime
,而不是 2018-01-01T08:00:00.000
。
演示的屏幕截图:
答案 1 :(得分:0)
淹没在自己的挫败中后,我终于找到了一个解决方案,该解决方案不会迫使我的api使用者将DateTime字符串转换为一个丑陋,冗长,令人不安的表达式。 我还希望我的模型透明地看起来像使用 DateTimeOffset 而不是 DateTime ,这将使我将来能够重构数据库并最终使用DateTimeOffset,即使到目前为止我仍然不这样做无需处理时区。 我的局限性是我无法更新旧数据库,因此解决方案就在这里。
这是您的解决方案吗?
此解决方案仅在以下情况下有用:
解决方案
public class MyEntity {
[...]
public DateTimeOffset CreatedDateTime { get; set; }
public DateTimeOffset ModifiedDateTime { get; set; }
[...]
}
public static class ValueConvertes
{
public static ValueConverter<DateTimeOffset, DateTime> DateTimeToDateTimeOffset =
new ValueConverter<DateTimeOffset, DateTime>(
model => model.DateTime,
store => DateTime.SpecifyKind(store, DateTimeKind.UTC));
}
public void Configure(EntityTypeBuilder<QuestionQML> builder)
{
builder.ToTable("MyEntityTable");
builder.Property(e => e.CreatedDateTime)
.HasColumnName("CreatedDateTime") // On DB datetime Type
.HasConversion(ValueConvertes.DateTimeToDateTimeOffset);
builder.Property(e => e.ModifiedDateTime)
.HasColumnName("ModifiedDateTime") // On DB datetime Type
.HasConversion(ValueConvertes.DateTimeToDateTimeOffset);
[...]
}
这使您可以通过以下方式进行过滤:
?$ filter = CreatedDateTime gt 2010-01-25T02:13:40Z ?$ filter = CreatedDateTime gt 2010-01-25T02:13:40.01234Z ?$ filter = CreatedDateTime gt 2010-01-25
特别感谢chris-clark
编辑: 当数据库中存储的日期时间为UTC时,可以使用更正后的代码DateTimeKind.UTC;如果您将其存储在其他时区中,则需要将“种类”设置为所使用的时区,但这会更改日期时间在“时间”中显示的方式结果,显示的是英国时区,例如Z(GMT time)或+01:00(BST时间)。