使用Mongo C#驱动程序持久化派生对象

时间:2011-06-12 03:57:07

标签: mongodb mongodb-.net-driver

我有以下类层次结构

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

如果我这样保存命​​令:

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

然后查询数据库,我没有看到派生属性保持不变。

{“_ id”:“4df43312c4c2ac12a8f987e4”,“_ t”:“MoveCommand”}

我希望Name属性作为文档中的键。 我做错了什么?

另外,有没有办法避免在基类上使用BsonKnowTypes属性来持久化派生实例?我没有看到基类需要知道派生类的原因。这是糟糕的OO设计,并且被BSON库强制在我的类层次结构上。我在这里错过了什么吗?

1 个答案:

答案 0 :(得分:7)

1. Name属性未保存到数据库中,因为它没有设置。序列化程序不会序列化没有设置器的属性(因为如果序列化程序序列化这样的属性,它将无法将其反序列化)。因此,如果你想序列化Name属性,那么只需添加假的setter(进入ICommand需要添加它):

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

2.如果您不想使用BsonKnownTypes属性,则有另一种方法可以通知序列化程序在反序列化期间可能遇到的已知类型。只需在app start事件中注册一次地图:

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

因此,您应该为每个多态类使用或KnownTypes属性或注册BsonClassMap,否则在反序列化期间您将收到“未知的描述符”错误:

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

3你说:

  

这是糟糕的OO设计并且正在存在   强迫我的班级层次结构   BSON图书馆。

即使没有KnownTypes,也可以通过BsonId属性使用Bson lib来解析您的代码。 如果你想避免它,你可以:

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

现在,您可以从域代码库中删除对Mongodb.Bson lib的引用。