4

NodaTimeMongo DB Official Driverの最新バージョンを使用しています。ZonedDateTimeいくつかのプロパティで、.NET DateTime の代わりにNodaTime を使用する単純な POCO クラスがあります。

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 句を評価する前に ZonedDateTimeSerializer` のwhere SomeDateTime < now' (whereようになります。is a variable I create from system time) it seems that each document must be deserialized using myこれは大きなパフォーマンスの問題のようですね。たとえそれが痛いとしても、BCL DateTime に戻ることを本当に考えなければなりません。

更新 2

を使用してソリューションを受け入れていますZonedDateTimeSerializerが、NodaTime と MongoDB の組み合わせには満足していませんが、どちらも優れた個々のソリューションです。しかし、現時点では、重い操作なしではうまく連携できません。

4

2 に答える 2

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);
    }
}

シリアライザーを登録することを忘れないでください。タイプごとにシリアライザーを登録する方法を見つけることができませんでしたが、次のようにタイプごとに登録できます。

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

お役に立てれば。

于 2013-07-26T16:14:38.520 に答える