我正在使用NodaTime和Mongo 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; }
}我可以很容易地将模型放到集合中,但是当我尝试读取查询模型时,我得到了以下MongoDB.Bson.BsonSerializationException
值类NodaTime.ZonedDateTime不能反序列化
解决/解决这个问题的好办法或最佳做法是什么?
更新
在发布了我的解决方案问题后,我面临着一个可能的新问题.当我查询集合并在查询中使用DateTime时,就像可以计算where子句之前的DateTime一样。这看起来是一个很大的性能问题,不是吗?我真的必须考虑再回到BCL DateTime,即使这很痛。
更新2
我正在使用ZonedDateTimeSerializer接受我的解决方案,但我对NodaTime与MongoDB的结合感到不舒服,而这两者都是很棒的单独解决方案。但是,在没有重大操纵的情况下,它们目前并不能很好地合作。
发布于 2013-07-26 16:14:38
最后,经过大量的阅读和实验,我终于找到了答案。我编写了一个自定义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);
}
}不要忘记注册序列化程序。我无法找到如何按类型注册序列化程序,但您可以按类型注册它,如下所示:
BsonClassMap.RegisterClassMap<MyPOCO>(cm =>
{
cm.AutoMap();
cm.GetMemberMap(a => a.SomeDateTime).SetSerializer(ZonedDateTimeSerializer.Instance);
});希望这能有所帮助。
发布于 2017-07-07 00:36:00
下面是thmshd类的修改版本,它也存储时区信息:
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);
}它可以在全球注册,如下所示:
BsonSerializer.RegisterSerializer(ZonedDateTimeSerializer.Instance);编辑:与其序列化到子文档,不如利用NodaTimes内置的字符串解析。
序列化:
context.Writer.WriteString(ZonedDateTimePattern.CreateWithInvariantCulture("G", DateTimeZoneProviders.Tzdb).Format(zonedDateTime));反序列化:
var zonedDateTimeString = context.Reader.ReadString();
var parseResult = ZonedDateTimePattern.CreateWithInvariantCulture("G", DateTimeZoneProviders.Tzdb)n.Parse(zonedDateTimeString);
if (!parseResult.Success)
{
throw parseResult.Exception;
}
return parseResult.Value;https://stackoverflow.com/questions/17882795
复制相似问题