如何使用 DocumentDb 查询 DateTimeOffset

How to query DateTimeOffset with DocumentDb

假设我将记录插入到以下模型的 Azure DocumentDb 中:

public class Message
{
    [JsonProperty(PropertyName = "tid")]
    public string Id { get; set; }

    [JsonProperty(PropertyName = "start")]
    public DateTimeOffset StartAt { get; set; }
}

它们都自动存储为字符串。我希望能够查询StartAt,所以我在上面添加了一个RngeIndex。我使用 Azure 门户验证索引是否正常工作。

除此之外,我加载了 DocumentDb .NET SDK 并尝试以下查询:

var since = DateTimeOffset.UtcNow.Subtract(duration);
return Client.CreateDocumentQuery<T>(Collection.DocumentsLink)
    .Where(m => m.AtStart > since)
    .AsEnumerable();

但是我收到错误

[DocumentQueryException: Constant of type 'System.DateTimeOffset' is not supported.]
   Microsoft.Azure.Documents.Linq.ExpressionToSql.VisitConstant(ConstantExpression inputExpression) +3204
   Microsoft.Azure.Documents.Linq.ExpressionToSql.VisitBinary(BinaryExpression inputExpression, TranslationContext context) +364
   Microsoft.Azure.Documents.Linq.ExpressionToSql.VisitBinary(BinaryExpression inputExpression, TranslationContext context) +349
   Microsoft.Azure.Documents.Linq.ExpressionToSql.VisitScalarLambda(Expression inputExpression, TranslationContext context) +230
   Microsoft.Azure.Documents.Linq.ExpressionToSql.VisitWhere(ReadOnlyCollection`1 arguments, TranslationContext context) +55
   Microsoft.Azure.Documents.Linq.ExpressionToSql.VisitMethodCall(MethodCallExpression inputExpression, TranslationContext context) +799
   Microsoft.Azure.Documents.Linq.ExpressionToSql.Translate(Expression inputExpression, TranslationContext context) +91
   Microsoft.Azure.Documents.Linq.ExpressionToSql.TranslateQuery(Expression inputExpression) +46
   Microsoft.Azure.Documents.Linq.SQLTranslator.TranslateQuery(Expression inputExpression) +20
   Microsoft.Azure.Documents.Linq.<ExecuteAllAsync>d__7.MoveNext() +177
   System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +179
   System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +66
   System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task task) +30
   Microsoft.Azure.Documents.Linq.<GetEnumeratorTAsync>d__10.MoveNext() +632

有没有办法在不改变底层模型的情况下执行类型安全的查询?

您可以对日期执行范围查询,但不能作为 "type-safe" 查询。

这是因为 DocumentDB 没有日期时间数据类型。相反,DocumentDB 严格遵守支持的数据类型(字符串、数字、布尔值、数组、对象和空值)的 JSON 规范。因此,当您尝试使用 LINQ 提供程序直接查询 DateTimeOffset 时,会出现异常 Constant of type 'System.DateTimeOffset' is not supported

默认情况下,DocumentDB Client SDK 将日期时间对象属性序列化为 ISO 8601 格式的字符串,如下所示:2014-09-15T23:14:25.7251173Z。在字符串上添加范围索引将允许您对日期执行字符串范围查询。您可以将 var since = DateTimeOffset.UtcNow.Subtract(duration); 序列化为 ISO 8601 字符串以在您的代码片段中执行查询。

查看此 blog post 以更深入地讨论如何使用日期。请注意,该博客略有过时,因为自该博客 post 最初创作以来就添加了对字符串范围索引和查询的支持。