Cosmos DB DocumentClient 的 DateTime 处理中的错误

Bug in DateTime handling of Cosmos DB DocumentClient

此问题与 Microsoft.Azure.DocumentDB.Core v2.11.2 中的 DocumentClient 有关。 (更新:该错误也存在于 Microsoft.Azure.Cosmos。)

当查询包含带尾随零的 DateTime 值时,Cosmos DB 的 LINQ 提供程序中似乎存在错误。考虑以下代码:

string dateTimeWithTrailingZero = "2000-01-01T00:00:00.1234560Z"; // trailing zero will be truncated by LINQ provider :-(
DateTime datetime = DateTime.Parse(dateTimeWithTrailingZero, CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal);

IQueryable<Dictionary<string, object>> query =
    client.CreateDocumentQuery<Dictionary<string, object>>(collectionUri)
        .Where(x => (DateTime) x["datetime"] <= datetime);

query 的结果包括 个文档,其中 属性 datetime 例如"2000-01-01T00:00:00.1234567Z"(尽管 不应该 )。

query 的结果 不包括 文档,其中 datetime"2000-01-01T00:00:00.1234560Z"(即使它 应该).

有什么方法可以使用 DocumentClient 和 LINQ 正确查询 DateTime 属性吗? (我知道使用原始 SQL 是有效的——出于各种原因,我 必须 使用 LINQ/IQueryable。)

LINQ 是 removing/truncating 'Z' 之前的最后一个“0”,因此最终查询的工作方式如下:

query":"SELECT VALUE root FROM root WHERE (root[\"datetime\"] < \"2000-01-01T00:00:00.123456Z\") "

这就是为什么会产生不需要的结果的原因。这是一种奇怪的行为,我认为在那里可以做的不多。

您将字符串设为 string dateTimeWithTrailingZero = "2000-01-01T00:00:00.1234561Z",这样就可以正常工作了。

另一种方法是:

string dateTimeWithTrailingZero = "2000-01-01T00:00:00.1234560Z";
DateTime datetime = DateTime.Parse(dateTimeWithTrailingZero, CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal);

var result= client.CreateDocumentQuery(UriFactory.CreateDocumentCollectionUri("demoDb", "demoDocCollection"),"select * from c where c.datetime < '" + datetime.ToString("o") + "'").ToList();

解决方法是使用自定义 JsonConverter。不幸的是,对于 DocumentClient,在 DocumentClient 的构造函数中设置 JsonConverter 不会 起作用!转换器只有在全局(静态)JSON.NET 默认设置 (JsonConvert.DefaultSettings) 中指定时才能正确拾取。

对于较新的CosmosClient,在构造函数中设置自定义CosmosSerializer是必要且足够的。要编写允许您指定自定义 JsonSerializerSettings 的自定义 CosmosSerializer,您可以反编译内部 class CosmosJsonDotNetSerializer 并将其用作基础。

自定义 JsonConverter 看起来像这样:

/// <summary>
/// <see cref="JsonConverter" /> for Cosmos DB needed as long as the DateTime handling
/// problem has not been fixed. 
/// </summary>
public class CosmosDbDateTimeJsonConverter : IsoDateTimeConverter
{
    public CosmosDbDateTimeJsonConverter()
    {
        this.DateTimeFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss.fffffffK";
    }

    #region Overrides of JsonConverter

    /// <inheritdoc />
    public override bool CanRead => false;

    #endregion
}