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

Mongodb 使用Mongo C#驱动程序持久化派生对象,mongodb,mongodb-.net-driver,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

我有下面的类层次结构

[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);
Command c=new MoveCommand();
MongoDataBaseInstance.GetCollection(“命令”).Save(c);
然后查询数据库,我看不到派生属性持久化

{“_id”:“4df4312c2ac12a8f987e4”,“_t”:“MoveCommand”}

我希望文档中有一个Name属性作为键。 我做错了什么


另外,有没有一种方法可以避免在基类上使用BsonKnowTypes属性来持久化派生实例?我不明白为什么基类需要了解派生类。这是一个糟糕的OO设计,BSON库在我的类层次结构上强制这样做。我在这里遗漏了什么吗?

1。
Name
属性未保存到数据库中,因为它没有setter。序列化程序不会序列化没有设置程序的属性(因为如果序列化程序序列化此类属性,则无法将其反序列化回来)。因此,如果您想要序列化
Name
属性,那么只需添加伪setter(到
ICommand
中也需要添加它):

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

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

这是一个糟糕的OO设计,并且正在被改进 在我的类层次结构上由 博森图书馆

在任何情况下,即使没有
KnownTypes
a,也可以通过
BsonId
属性使用Bson lib编辑代码。 如果你想避免,你可以:

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

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

太棒了!非常感谢。如何注册ID生成器而不是使用this.ID=ObjectId.GenerateNewId().ToString();就像我的医生一样?有办法做到这一点吗?我回答了自己的问题:cm.SetIdMember(cm.GetMemberMap(c=>c.Id).SetIdGenerator(newStringObjectiveGenerator())@安德鲁·奥西奇:我无法在界面上使用FindAllAs。我尝试了FindAllAs,如您的回答中所示,但是我得到了以下错误:“没有为类型ICommand找到序列化程序”,如果我有一个基类而不是接口,那么它似乎可以正常工作。有什么想法吗?@AbhijeetPatel:我想你需要从数据库中删除旧数据,然后再试一次。一般来说,我尝试使用基类,但不尝试使用接口。所以我以后会用接口试试findallas。@Andrew:是的,我删除了所有旧数据并尝试了,但它不适用于接口,只适用于基类。我很想知道你的发现。
  var commands = col.FindAllAs<ICommand>().ToList();
   BsonClassMap.RegisterClassMap<MoveCommand>(cm => {
        cm.AutoMap();
        cm.SetIdMember(cm.GetMemberMap(c => c.Id));
    });