【问题标题】:How to query DateTimeOffset with DocumentDb如何使用 DocumentDb 查询 DateTimeOffset
【发布时间】:2015-11-14 03:21:42
【问题描述】:

假设我将记录插入以下模型的 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

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

【问题讨论】:

    标签: azure-cosmosdb


    【解决方案1】:

    您可以对日期执行范围查询,但不能作为“类型安全”查询。

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

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

    查看blog post,了解有关使用日期的更深入讨论。请注意,该博客有些过时,因为从最初撰写博客文章开始就添加了对字符串范围索引和查询的支持。

    【讨论】:

    • 我建议通过在不同的时区/偏移中存储不同的时间并确保按预期排序来进行测试。只是比较字符串只有在它们都在同一个时区时才有效,即 UTC 以 Z 结尾。此转换将丢弃捕获的时区/偏移信息,这可能对您的应用程序有问题,更糟糕的是,如果您需要计算出观察到的本地时间是历史事件的时间,将来会出现问题。多年来,各国改变了他们的时区规则,因此这可能是一项重要的工作。谨慎使用财务和审计应用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多