我有以下课程:
[BsonIgnoreExtraElements]
public class WidgetCollection
{
[BsonId]
public int AccountId { get; set; }
public ReadOnlyCollection<Widget> Widgets { get; set; }
}
[BsonIgnoreExtraElements]
[BsonDiscriminator(RootClass = true)]
[BsonKnownTypes(typeof(OtherObject1), ...)]
public class Widget
{
public ObjectId Id { get; set; }
public string Title { get; set; }
public int Position { get; set; }
public WidgetKind Kind { get; set; }
public bool IsActive { get; set; }
}
数据库中此实例的示例:
{ "_id" : 2993644, "Widgets" : [ { "_t" : "Widget", "_id" : ObjectId("504797b327e10b1e80c838ac"), "Title" : "My Notes", "Position" : 1, "Kind" : 0, "IsActive" : true } ] }
然后我有一个聚合命令,它过滤掉“Widgets”数组中的元素,只返回“IsActive”为真的元素。在这种情况下,该命令只返回整个对象。
var command = new CommandDocument
{
{"aggregate", "myCollection" },
{"pipeline", commandArray }
};
var result = database.RunCommandAs<AggregateResult<WidgetCollection>>(command).Result;
return result;
这是 AggregateResult 类:
public class AggregateResult<T> : CommandResult
{
public T Result
{
get
{
var result = Response["result"].AsBsonArray.SingleOrDefault().AsBsonDocument;
return BsonSerializer.Deserialize<T>(result);
}
}
}
是的,我知道 SingleOrDefault().AsBsonDocument 可以处理 NRE,但这不是现在的问题。我已将代码调试到反序列化点,并验证“结果”变量包含与上面显示的完全相同的 BSON。我在尝试反序列化结果时收到此消息:“反序列化 Community.Widgets.WidgetCollection 类的 Widgets 属性时发生错误:预期元素名称为 '_v',而不是 '_id'”。
为什么反序列化器需要一个 '_v' 元素?
更新
我通过将 Widgets 属性的类型更改为ICollection
. 我现在收到这个错误:Unknown discriminator value 'Widget'.
对我来说,这没有任何意义,因为文档有"_t" : "Widget"
元素。
我还尝试插入一个派生类,之后“_t”元素的值现在"[ "Widget", "DerivedClass"]
符合预期,我得到了同样的错误。同样,这在使用时不会发生database.FindOneAs<>()
,只有在显式使用时才会发生BsonSerializer.Deserialize<>()
。我尝试在调用之前添加此代码Deserialize()
:
BsonClassMap.RegisterClassMap<Widget>(cm => { cm.AutoMap(); cm.SetIsRootClass(true); });
BsonClassMap.RegisterClassMap<RssFeedWidget>();
但是我不确定初始化代码应该放在哪里,而且我认为如果我在我的类上使用鉴别器属性,则不需要它。
这是我的聚合命令
BsonDocument documentMatch = new BsonDocument{{"$match", new BsonDocument{{"_id", documentId}}}};
BsonDocument unwindArray = new BsonDocument{{"$unwind", "$Widgets"}};
BsonDocument arrayMatch = new BsonDocument{{"$match", new BsonDocument{{"Widgets.IsActive", true}}}});
BsonArray commandArray = new BsonArray();
commandArray.Add(documentMatch);
commandArray.Add(unwindArray),
commandArray.Add(arrayMatch);
var command = new CommandDocument
{
{"aggregate", collectionName},
{"pipeline", commandArray}
}
var result = database.RunCommandAs<AggregateResult<WidgetCollection>>(command).Result;