使用MongoDB的NodaTime:值类NodaTime.ZonedDateTime无法反序列化

thm*_*shd 4 c# mongodb nodatime mongodb-.net-driver

我正在使用最新版本的NodaTimeMongo DB官方驱动程序.我有一个简单的POCO类,它使用NodaTime ZonedDateTime作为一些属性中.NET DateTime的替代品.

public class MyPOCO
{
    [BsonId]
    [Key]
    public ObjectId SomeId { get; set; }

    public string SomeProperty { get; set; }

    public ZonedDateTime SomeDateTime { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

我可以轻松地将Model放入集合中,但是当我尝试读取查询的模型时,我得到以下内容MongoDB.Bson.BsonSerializationException:

值类NodaTime.ZonedDateTime无法反序列化

什么是解决/解决这个问题的好或最佳做法?

UPDATE

在发布我的问题解决方案后,我面临一个可能的新问题......当我查询集合并在我的查询中使用DateTime时,就像where SomeDateTime < now' (where现在is a variable I create from system time) it seems that each document must be deserialized using myZonedDateTimeSerializer`可以在where子句之前进行评估.这看起来像是一个很大的性能问题,不是吗?我真的要考虑再次回到BCL DateTime,即使它会受到伤害.

更新2

我正在接受我的解决方案ZonedDateTimeSerializer,但我对NodaTime与MongoDB的结合感到不舒服,而两者都是很好的个性化解决方案.但是他们目前在没有大量操纵的情况下一起工作得不好.

thm*_*shd 5

没关系,最后经过多次阅读和实验,终于找到了它.我写了一个自定义BsonBaseSerializer实现来处理ZonedDateTime.

这是我的代码ZonedDateTimeSerializer:

/// <summary>
/// Serializer for the Noda
/// </summary>
public class ZonedDateTimeSerializer : BsonBaseSerializer
{
    private static ZonedDateTimeSerializer __instance = new ZonedDateTimeSerializer();

    /// <summary>
    /// Initializes a new instance of the ZonedDateTimeSerializer class.
    /// </summary>
    public ZonedDateTimeSerializer()
    {
    }

    /// <summary>
    /// Gets an instance of the ZonedDateTimeSerializer class.
    /// </summary>
    public static ZonedDateTimeSerializer Instance
    {
        get { return __instance; }
    }

    /// <summary>
    /// Deserializes an object from a BsonReader.
    /// </summary>
    /// <param name="bsonReader">The BsonReader.</param>
    /// <param name="nominalType">The nominal type of the object.</param>
    /// <param name="actualType">The actual type of the object.</param>
    /// <param name="options">The serialization options.</param>
    /// <returns>
    /// An object.
    /// </returns>
    public override object Deserialize(BsonReader bsonReader, Type nominalType, Type actualType, IBsonSerializationOptions options)
    {
        VerifyTypes(nominalType, actualType, typeof(ZonedDateTime));

        var bsonType = bsonReader.GetCurrentBsonType();
        if (bsonType == BsonType.DateTime)
        {
            var millisecondsSinceEpoch = bsonReader.ReadDateTime();
            return new Instant(millisecondsSinceEpoch).InUtc();
        }

        throw new InvalidOperationException(string.Format("Cannot deserialize ZonedDateTime from BsonType {0}.", bsonType));
    }

    /// <summary>
    /// Serializes an object to a BsonWriter.
    /// </summary>
    /// <param name="bsonWriter">The BsonWriter.</param>
    /// <param name="nominalType">The nominal type.</param>
    /// <param name="value">The object.</param>
    /// <param name="options">The serialization options.</param>
    public override void Serialize(BsonWriter bsonWriter, Type nominalType, object value, IBsonSerializationOptions options)
    {
        if (value == null)
            throw new ArgumentNullException("value");

        var ZonedDateTime = (ZonedDateTime)value;
        bsonWriter.WriteDateTime(ZonedDateTime.ToInstant().Ticks);
    }
}
Run Code Online (Sandbox Code Playgroud)

不要忘记注册Serializer.我无法找到如何为每种类型注册Serializer,但您可以按类型注册它,如下所示:

BsonClassMap.RegisterClassMap<MyPOCO>(cm =>
{
    cm.AutoMap();
    cm.GetMemberMap(a => a.SomeDateTime).SetSerializer(ZonedDateTimeSerializer.Instance);
});
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助.

  • 这似乎是序列化等同的"瞬间",对吧?我想你会想要序列化一对`DateTimeZone.Id`字符串和`OffsetDateTime`值.否则,为什么不直接使用"Instant"类型? (2认同)