次のクラスがあります。
[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; }
}
DB でのこれのインスタンスの例:
{ "_id" : 2993644, "Widgets" : [ { "_t" : "Widget", "_id" : ObjectId("504797b327e10b1e80c838ac"), "Title" : "My Notes", "Position" : 1, "Kind" : 0, "IsActive" : true } ] }
次に、"Widgets" 配列内の要素を除外して、"IsActive" が true である要素のみを返す集約コマンドを用意しました。この場合、コマンドはオブジェクト全体を返すだけです。
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 のケースになる可能性があることは知っていますが、それは今のところ問題ではありません。逆シリアル化のポイントまでコードをデバッグし、「result」変数に上記とまったく同じ BSON が含まれていることを確認しました。結果を逆シリアル化しようとすると、次のメッセージが表示されます。
デシリアライザーに '_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;