在C#mongodb驱动程序中,如何在序列化程序中将dateOnly设置为可为null的datetime对象?

时间:2018-12-19 13:21:44

标签: c# mongodb

我有一个模型,该模型的属性类型为X(假设称为DateTime?)。
我想设置为[BsonDateTimeOptions(DateOnly = true)],但在mongo c#驱动程序中使用类映射器,例如:

BsonClassMap.RegisterClassMap<MyModel>(cm =>
{
    cm.AutoMap();
    cm.MapMember(c => c.X).SetSerializer(new DateTimeSerializer(dateOnly: true));
});

但是由于某种原因,由于属性为Nullable,对于正常的DateTime类型,它可以正常工作,因此出现错误。

为什么我需要这样做,因为我只需要将X的值保存为不带时区的日期。

我已经尝试构建自定义序列化程序,但是反序列化时出现错误:

  

ReadBsonType仅在State为Type时才能调用,而在State为   值

这是自定义序列化器:

public class DateTimeNullableSerialzier : DateTimeSerializer, IBsonSerializer
{
    public object Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
    {
        if (context.Reader.CurrentBsonType == BsonType.Null)
            return null;

        return base.Deserialize(context, args);
    }

    public void Serialize(BsonSerializationContext context, BsonSerializationArgs args, object value)
    {
        if (value is null)
            context.Writer.WriteNull();
        else
            base.Serialize(context, args, (DateTime)value);
    }
}

2 个答案:

答案 0 :(得分:0)

实际上,我是如何实现序列化器的,问题是,在进行了一些修复后,序列化器可用于任何可为空的DateTime属性(DateTime?),并接受与DateTimeSerializer中相同的构造函数参数(但不适用于DateTime类型,出于某种原因):

public class DateTimeNullableSerializer : IBsonSerializer
{
    public Type ValueType { get; }
    private DateTimeSerializer dateTimeSerializer;
    /// <summary>
    /// Initializes a new instance of the <see cref="T:DateTimeNullableSerializer" /> class.
    /// </summary>
    public DateTimeNullableSerializer()
    {
        ValueType = typeof(DateTime?);
        dateTimeSerializer = new DateTimeSerializer(DateTimeKind.Utc, BsonType.DateTime);
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="T:DateTimeNullableSerializer" /> class.
    /// </summary>
    /// <param name="dateOnly">if set to <c>true</c> [date only].</param>
    public DateTimeNullableSerializer(bool dateOnly)
    {
        ValueType = typeof(DateTime?);
        dateTimeSerializer = new DateTimeSerializer(dateOnly);
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="T:DateTimeNullableSerializer" /> class.
    /// </summary>
    /// <param name="dateOnly">if set to <c>true</c> [date only].</param>
    /// <param name="representation">The representation.</param>
    public DateTimeNullableSerializer(bool dateOnly, BsonType representation)
    {
        ValueType = typeof(DateTime?);
        dateTimeSerializer = new DateTimeSerializer(dateOnly, representation);
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="T:DateTimeNullableSerializer" /> class.
    /// </summary>
    /// <param name="representation">The representation.</param>
    public DateTimeNullableSerializer(BsonType representation)
    {
        ValueType = typeof(DateTime?);
        dateTimeSerializer = new DateTimeSerializer(DateTimeKind.Utc, representation);
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="T:DateTimeNullableSerializer" /> class.
    /// </summary>
    /// <param name="kind">The kind.</param>
    public DateTimeNullableSerializer(DateTimeKind kind)
    {
        ValueType = typeof(DateTime?);
        dateTimeSerializer = new DateTimeSerializer(kind, BsonType.DateTime);
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="T:DateTimeNullableSerializer" /> class.
    /// </summary>
    /// <param name="kind">The kind.</param>
    /// <param name="representation">The representation.</param>
    public DateTimeNullableSerializer(DateTimeKind kind, BsonType representation)
    {
        ValueType = typeof(DateTime?);
        dateTimeSerializer = new DateTimeSerializer(kind, representation);
    }

    public object Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
    {
        if (context.Reader.CurrentBsonType == BsonType.Null)
        {
            context.Reader.ReadNull();
            return null;
        }

        return dateTimeSerializer.Deserialize(context, args);
    }

    public void Serialize(BsonSerializationContext context, BsonSerializationArgs args, object value)
    {
        if (value is null)
            context.Writer.WriteNull();
        else
            dateTimeSerializer.Serialize(context, args, (DateTime)value);
    }
}

答案 1 :(得分:0)

如果有人正在阅读本文并遇到同样的问题,实际上有一种方法可以在不实现您自己的序列化程序的情况下做到这一点。不过,这是驱动程序的 2.x 版本。

默认情况下,mongo 将为您的 NullableSerializer<T> 字段使用 DateTime?,但默认情况下没有设置 dateOnly。但是,NullableSerializer<T> 只是为 <T> 类型包装了一个普通的序列化程序,并且有一种方法可以为其提供您自己配置为使用 dateOnly 的实例:

var dateSerializer = new DateTimeSerializer(dateOnly: true);
var nullableDateOnlySerializer = new NullableSerializer<DateTime>().WithSerializer(dateSerializer));
BsonClassMap.RegisterClassMap<MyModel>(cm =>
{
    cm.AutoMap();
    cm.MapMember(c => c.X).SetSerializer(nullableDateOnlySerializer);
});