简体   繁体   中英

Using a custom serializer in MongoDB for a nested object interferes with filters using that object

I have models defined like below (I ommited parts not directly related to the problem):

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
}

And the serializer code:

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

And this code is what I use to register the serializer:

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

Now, when I issue a count query agains my MongoDB instance, I get an error saying:

System.InvalidOperationException: Convert({document}{State}.Representation, Int32) is not supported.

It's obvious that the serializer is to blame, because when I remove the SetSerializer call everything works fine. You may say that what I'm doing looks weird, however please understand that this AbstractState implementation above is the minimal version - in reality it has a bit more code and that code needs to be initialized in a way that MongoDB can't operate. My goal here is to have a clean aggregate - holding only the business logic and not the construction logic. That's why I'd rather have some infrastructural code in place (like that custom serializer) to initialize the state object. Any ideas on how to make it work?

The key to success was to implement the IBsonDocumentSerializer . If anyone's interested, my implementation below:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM