Использование собственного сериализатора в MongoDB для вложенного объекта мешает фильтрам, использующим этот объект - PullRequest
0 голосов
/ 20 апреля 2020

У меня есть модели, определенные как показано ниже (я опустил части, не связанные напрямую с проблемой):

public class AnObjectWithState {
    public AbstractState State { get; private set; }
}

public abstract class AbstractState {
    public State Representation { get; protected set; }
}

public enum State {
    State1,
    State2,
    State3
}

И код сериализатора:

public class AbstractStateSerializer : SerializerBase<AbstractState>
{
    public override AbstractState Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args) =>
        StateFactory.CreateFor(base.Deserialize(context, args));
}

И этот код - то, что я используйте для регистрации сериализатора:

cm.MapField(c => c.State).SetSerializer(new AbstractStateSerializer());

Теперь, когда я запускаю запрос на подсчет снова моего экземпляра MongoDB, я получаю сообщение об ошибке:

System.InvalidOperationException: Convert ({ document} {State} .Representation, Int32) не поддерживается.

Очевидно, что виноват сериализатор, потому что когда я удаляю вызов SetSerializer, все работает нормально. Вы можете сказать, что то, что я делаю, выглядит странно, однако, пожалуйста, поймите, что приведенная выше реализация AbstractState является минимальной версией - на самом деле она содержит немного больше кода, и этот код необходимо инициализировать так, как MongoDB не может работать. Моя цель здесь состоит в том, чтобы иметь чистый агрегат - содержащий только бизнес-логику c, а не строительную логику c. Вот почему я предпочел бы иметь некоторый инфраструктурный код (например, этот пользовательский сериализатор) для инициализации объекта состояния. Любые идеи о том, как заставить это работать?

1 Ответ

0 голосов
/ 21 апреля 2020

Ключом к успеху было внедрение IBsonDocumentSerializer. Если кому-то интересно, моя реализация ниже:

public class AbstractStateSerializer : SerializerBase<AbstractState>, IBsonDocumentSerializer
{
    public override AbstractState Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
    {
        context.Reader.ReadStartDocument();
        context.Reader.ReadBsonType();
        context.Reader.SkipName();

        var value = context.Reader.ReadInt32();

        context.Reader.ReadEndDocument();

        var state = // here I construct a graph of objects based on the above value variable

        return state;
    }

    public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, AbstractState value)
    {
        context.Writer.WriteStartDocument();
        context.Writer.WriteName(nameof(value.Representation));
        context.Writer.WriteInt32((int)value.Representation);
        context.Writer.WriteEndDocument();
    }

    public bool TryGetMemberSerializationInfo(string memberName, out BsonSerializationInfo serializationInfo)
    {
        switch (memberName)
        {
            case "Representation":
                serializationInfo = new BsonSerializationInfo("Representation", new EnumSerializer<State>(), typeof(State));
                return true;
            default:
                serializationInfo = null;
                return false;
        }
    }
}
...