2012-09-05 24 views
6

我有以下类:MongoDB的反序列化随着鉴别版本

[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。尝试反序列化结果时收到此消息:“在反序列化Community.Widgets.WidgetCollection类的Widgets属性时发生错误:预期的元素名称为'_v',而不是'_id'”。

为什么解串器期望'_v'元素?

UPDATE
我固定上述问题通过改变小部件属性的类型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; 
+1

你为什么不走一步,自己调试驱动程序?源代码就在这里:https://github.com/mongodb/mongo-csharp-driver –

+0

良好的通话。它看起来像试图反序列化数组中的元素,它会查找_t字符串,然后查找不存在的_v字符串。我试图寻找_v元素的目的是什么,但我找不到任何东西。 – anthv123

+0

我对BlinkSerializer的参数中使用的有点困惑。反序列化...你使用的是Widget还是WidgetCollection? –

回答

2

我无法重现此问题。我使用了下面的程序。所以,因为我在这里使用了一个相对简单的管道,所以你的问题可能是你的聚合文档在映射时没有返回。你能发布你的聚合命令吗?

using MongoDB.Bson; 
using MongoDB.Bson.Serialization; 
using MongoDB.Bson.Serialization.Attributes; 
using MongoDB.Driver; 
using System.Collections.Generic; 
using System.Collections.ObjectModel; 
using System.Linq; 

namespace TestConsole_Source 
{ 
    class Program 
    { 
     [BsonIgnoreExtraElements] 
     public class WidgetCollection 
     { 
      [BsonId] 
      public int AccountId { get; set; } 
      public ReadOnlyCollection<Widget> Widgets { get; set; } 
     } 


     [BsonIgnoreExtraElements] 
     [BsonDiscriminator(RootClass = true)] 
     public class Widget 
     { 
      public string Title { get; set; } 
      public int Position { get; set; } 
      public bool IsActive { get; set; } 
     } 

     static void Main(string[] args) 
     { 
      var server = MongoServer.Create(); 
      server.Connect(); 

      var db = server.GetDatabase("widgettest"); 
      var collection = db.GetCollection<WidgetCollection>("widgets"); 
      collection.Drop(); 

      var widgets = new WidgetCollection(); 
      var widget1 = new Widget { Title = "One", Position = 0, IsActive = true }; 
      var widget2 = new Widget { Title = "Two", Position = 1, IsActive = true }; 
      var widget3 = new Widget { Title = "Three", Position = 2, IsActive = false }; 
      widgets.Widgets = new List<Widget> { widget1, widget2, widget3 }.AsReadOnly(); 

      collection.Save(widgets); 

      var command = new CommandDocument(
       new BsonElement("aggregate", "widgets"), 
       new BsonElement("pipeline", new BsonArray(new [] { 
        new BsonDocument(
         new BsonElement("$project", new BsonDocument("Widgets", 1)))}))); 

      var response = db.RunCommand(command); 
      var rawDoc = response.Response["result"].AsBsonArray.SingleOrDefault().AsBsonDocument; 

      var doc = BsonSerializer.Deserialize<WidgetCollection>(rawDoc); 

      //Console.ReadKey(); 
     } 
    } 
} 

更新: 使用上述新的信息,我纠正了聚集查询才能正常工作。您需要使用一个组才能将结果恢复为驾驶员期望的相同格式。

var command = new CommandDocument(
     new BsonElement("aggregate", "widgets"), 
     new BsonElement("pipeline", new BsonArray(new[] { 
      new BsonDocument(
       new BsonElement("$unwind", "$Widgets")), 
      new BsonDocument(
       new BsonElement("$match", new BsonDocument("Widgets.IsActive", true))), 
      new BsonDocument(
       new BsonElement("$group", new BsonDocument(
        new BsonElement("_id", "$_id"), 
        new BsonElement("Widgets", new BsonDocument("$addToSet", "$Widgets")))))}))); 

即使这个工作,我仍然建议不要通过这个过程,只是过滤Widgets客户端。

+0

我已将此命令添加到问题中。我敢肯定,这不是错误的,因为就像我所说的,我可以调试到AggregateResult.Result并检查返回的Json结果,并验证只返回了设置为true的'IsActive'的Widgets。 – anthv123

+0

你真的只是每次都返回一个文档吗? $ match:{_id:“myid”}?如果是这样,在这种情况下没有理由使用聚合框架... –

+0

是的,这就是我正在做的。我想使用聚合框架的原因是过滤Db端的数组项,而不是应用端。 – anthv123