首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >NodaTime with MongoDB:值类NodaTime.ZonedDateTime不能反序列化

NodaTime with MongoDB:值类NodaTime.ZonedDateTime不能反序列化
EN

Stack Overflow用户
提问于 2013-07-26 13:37:08
回答 2查看 2K关注 0票数 4

我正在使用NodaTimeMongo DB官方司机的最新版本。我有一个简单的POCO类,它使用NodaTime的ZonedDateTime代替几个属性中的.NET DateTime。

代码语言:javascript
复制
public class MyPOCO
{
    [BsonId]
    [Key]
    public ObjectId SomeId { get; set; }

    public string SomeProperty { get; set; }

    public ZonedDateTime SomeDateTime { get; set; }
}

我可以很容易地将模型放到集合中,但是当我尝试读取查询模型时,我得到了以下MongoDB.Bson.BsonSerializationException

值类NodaTime.ZonedDateTime不能反序列化

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

更新

在发布了我的解决方案问题后,我面临着一个可能的新问题.当我查询集合并在查询中使用DateTime时,就像可以计算where子句之前的DateTime一样。这看起来是一个很大的性能问题,不是吗?我真的必须考虑再回到BCL DateTime,即使这很痛。

更新2

我正在使用ZonedDateTimeSerializer接受我的解决方案,但我对NodaTime与MongoDB的结合感到不舒服,而这两者都是很棒的单独解决方案。但是,在没有重大操纵的情况下,它们目前并不能很好地合作。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-07-26 16:14:38

最后,经过大量的阅读和实验,我终于找到了答案。我编写了一个自定义BsonBaseSerializer实现来处理ZonedDateTime

这是我的ZonedDateTimeSerializer代码

代码语言:javascript
复制
/// <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);
    }
}

不要忘记注册序列化程序。我无法找到如何按类型注册序列化程序,但您可以按类型注册它,如下所示:

代码语言:javascript
复制
BsonClassMap.RegisterClassMap<MyPOCO>(cm =>
{
    cm.AutoMap();
    cm.GetMemberMap(a => a.SomeDateTime).SetSerializer(ZonedDateTimeSerializer.Instance);
});

希望这能有所帮助。

票数 5
EN

Stack Overflow用户

发布于 2017-07-07 00:36:00

下面是thmshd类的修改版本,它也存储时区信息:

代码语言:javascript
复制
public class ZonedDateTimeSerializer : IBsonSerializer<ZonedDateTime>
{
    public static ZonedDateTimeSerializer Instance { get; } = new ZonedDateTimeSerializer();

    object IBsonSerializer.Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
    {
        return Deserialize(context, args);
    }

    public void Serialize(BsonSerializationContext context, BsonSerializationArgs args, ZonedDateTime value)
    {
        if (value == null)
            throw new ArgumentNullException(nameof(value));

        var zonedDateTime = value;

        SerializeAsDocument(context, zonedDateTime);
    }

    private static void SerializeAsDocument(BsonSerializationContext context, ZonedDateTime zonedDateTime)
    {
        context.Writer.WriteStartDocument();
        context.Writer.WriteString("tz", zonedDateTime.Zone.Id);
        context.Writer.WriteInt64("ticks", zonedDateTime.ToInstant().Ticks);
        context.Writer.WriteEndDocument();
    }

    public ZonedDateTime Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
    {
        var bsonType = context.Reader.GetCurrentBsonType();

        if (bsonType != BsonType.Document)
        {
            throw new InvalidOperationException($"Cannot deserialize ZonedDateTime from BsonType {bsonType}.");
        }

        context.Reader.ReadStartDocument();
        var timezoneId = context.Reader.ReadString("tz");
        var ticks = context.Reader.ReadInt64("ticks");
        var timezone = DateTimeZoneProviders.Tzdb.GetZoneOrNull(timezoneId);

        if (timezone == null)
        {
            throw new Exception($"Unknown timezone id: {timezoneId}");
        }

        context.Reader.ReadEndDocument();

        return new Instant(ticks).InZone(timezone);
    }

    public void Serialize(BsonSerializationContext context, BsonSerializationArgs args, object value)
    {
        if (value == null)
        {
            throw new ArgumentNullException(nameof(value));
        }

        var zonedDateTime = (ZonedDateTime)value;

        SerializeAsDocument(context, zonedDateTime);
    }

    public Type ValueType => typeof(ZonedDateTime);
}

它可以在全球注册,如下所示:

代码语言:javascript
复制
BsonSerializer.RegisterSerializer(ZonedDateTimeSerializer.Instance);

编辑:与其序列化到子文档,不如利用NodaTimes内置的字符串解析。

序列化:

代码语言:javascript
复制
context.Writer.WriteString(ZonedDateTimePattern.CreateWithInvariantCulture("G", DateTimeZoneProviders.Tzdb).Format(zonedDateTime));

反序列化:

代码语言:javascript
复制
        var zonedDateTimeString = context.Reader.ReadString();
        var parseResult = ZonedDateTimePattern.CreateWithInvariantCulture("G", DateTimeZoneProviders.Tzdb)n.Parse(zonedDateTimeString);

        if (!parseResult.Success)
        {
            throw parseResult.Exception;
        }

        return parseResult.Value;
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/17882795

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档