Linq到DocumentDB:按日期时间字段过滤

时间:2016-08-03 15:38:20

标签: linq azure-cosmosdb

我正在使用LINQ to DocumentDB,我目前正在尝试按日期时间字段过滤返回的记录。我的查询如下:

      var mycollection = Client.CreateDocumentQuery<Test>(MyCollection.DocumentsLink)
                        .Where(d => d.Time >= DateTime.Now)
                        .AsEnumerable();

但是,此查询始终与消息崩溃:

ExceptionMessage=The 'ObjectContent`1' type failed to serialize the response body for content type 'application/json; charset=utf-8'.
ExceptionType=System.InvalidOperationException
ExceptionMessage=Constant of type 'System.DateTime' is not supported.
ExceptionType=Microsoft.Azure.Documents.Linq.DocumentQueryException

发生此错误是因为我使用datetime字段进行过滤。如果我要过滤任何字符串字段,那就完美了。如何防止此错误?

2 个答案:

答案 0 :(得分:1)

DateTime不是受支持的时间,您必须将DateTime转换为int,以便JSON看起来像这样(例如):

{
    "Time": 1408318702
}

您需要使用JsonConverter并将DateTime属性视为纪元。此代码借用this source here

public class FooBar
{
     [JsonConverter(typeof(EpochDateTimeConverter))]
     public DateTime Time { get; set; }
}


public class EpochDateTimeConverter : JsonConverter
{
    public override void WriteJson(JsonWriter writer, 
                                  object value, 
                                   JsonSerializer serializer)
    {
        int seconds;
        if (value is DateTime)
        {
            DateTime dt = (DateTime)value;
            if (!dt.Equals(DateTime.MinValue))
                seconds = dt.ToEpoch();
            else
                seconds = int.MinValue;
        }
        else
        {
            throw new Exception("Expected date object value.");
        }

        writer.WriteValue(seconds);
    }

    public override object ReadJson(JsonReader reader, 
                                    Type type, 
                                    object value, 
                                    JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.None || reader.TokenType == JsonToken.Null) 
            return null;

        if (reader.TokenType != JsonToken.Integer)
        {
            throw new Exception(
                 string.Format("Unexpected token parsing date. Expected Integer, got {0}.",
                               reader.TokenType));
        }

        int seconds = (int)reader.Value;
        return new DateTime(1970, 1, 1).AddSeconds(seconds);
    }
}

.ToEpoch扩展方法定义为:

public static class Extensions
{
    public static int ToEpoch(this DateTime date)
    {
        if (date == null) return int.MinValue;
        DateTime epoch = new DateTime(1970, 1, 1);
        TimeSpan epochTimeSpan = date - epoch;
        return (int)epochTimeSpan.TotalSeconds;
    }
}

答案 1 :(得分:0)

默认情况下,DocumentDB中的DateTime对象被序列化为ISO 8601字符串格式,例如:&#34; 2016-08-08T22:10:50.000000Z&#34;

在这种情况下,您可以使用SQL语法而不是LINQ,因为不支持DateTime对象。

请注意,您可以在查询中将EnableScanInQuery设置为true作为FeedOptions,或者在时间字段上设置精度为-1的范围索引。

您可以将日期存储为大卫提到的时代,但您不必这样做。

以下是您的查询内容:

string currentTime = DateTime.UtcNow.ToString(&#34; o&#34;);

var myQuery = Client.CreateDocumentQuery(MyCollection.DocumentsLink,                          &#34; SELECT * FROM c WHERE c.Time&gt; =&#39;&#34; + currentTime +&#34;&#39;&#34;,new FeedOptions {EnableScanInQuery = true})                         .AsEnumerable();