Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Persist derived objects using Mongo C# driver

I have the following class hierarchy

[BsonKnownTypes(typeof(MoveCommand))]
public abstract class Command : ICommand
{
    public abstract string Name
    {
        get;
    }

    public abstract ICommandResult Execute();
}
    public class MoveCommand : Command
{
    public MoveCommand()
    {
        this.Id = ObjectId.GenerateNewId().ToString();
    }

    [BsonId]
    public string Id { get; set; }

    public override string Name
    {
        get { return "Move Command"; }
    }

    public override ICommandResult Execute()
    {
        return new CommandResult { Status = ExecutionStatus.InProgress };
    }
}

if I save the command like so:

 Command c = new MoveCommand();
MongoDataBaseInstance.GetCollection<Command>("Commands").Save(c);

and then query the DB, I don't see the derived properties persisted.

{ "_id" : "4df43312c4c2ac12a8f987e4", "_t" : "MoveCommand" }

I would expect a Name property as a key in the document. What am I doing wrong?

Also, is there a way to avoid having a BsonKnowTypes attribute on the base class for persisting derived instances? I don't see the why a base class needs to know about derived classes. This is bad OO design and is being forced on my class hierarchy by the BSON library. Am I missing something here?

like image 778
Abhijeet Patel Avatar asked Jun 12 '11 03:06

Abhijeet Patel


1 Answers

1.Name property was not saved into database because it haven't setter. Serializers not serialize properties that's haven't setters (because if serializer serialize such property it will not able deserialize it back). So if you want serialize Name property then just add fake setter(into ICommand need to add it also):

  public override string Name
  {
    get { return "Move Command"; }
    set{}
  }

2.If you don't want use BsonKnownTypes attribute there is another way to notify serializer about know types it might encounter during deserialization. Just Register maps once, on app start event:

BsonClassMap.RegisterClassMap<MoveCommand>();
//all other inherited from ICommand classes need register here also

So you should use or KnownTypes attribute or register BsonClassMap for each polymorphic class, otherwise you will get 'unknown descriminator' error during deserializtion:

  var commands = col.FindAllAs<ICommand>().ToList();

3 You said:

This is bad OO design and is being forced on my class hierarchy by the BSON library.

In any way even without KnownTypes atribute your code using Bson lib through BsonId attribute. If you want avoid it you can:

   BsonClassMap.RegisterClassMap<MoveCommand>(cm => {
        cm.AutoMap();
        cm.SetIdMember(cm.GetMemberMap(c => c.Id));
    });

So now you can remove reference to Mongodb.Bson lib from your domain code lib.

like image 112
Andrew Orsich Avatar answered Dec 17 '22 06:12

Andrew Orsich