MongoDB插入与复杂类型的更新序列化差异

时间:2017-09-07 13:27:44

标签: c# mongodb

有谁知道更新和插入的序列化有什么区别,以及如何使它相等?我遇到的问题就像休耕一样:
假设我们有以下类(忽略它没有MongoId,因为它不相关)

class Custom
{
    public string ID { get; set; }
    public Dictionary<string, string> Dict { get; set; }
}

当我使用Insert命令时,Json看起来像这样

{
    "ID" : "id",
    "Dict" :
    {
        "Key": "Val"
    }
}

这是预期的,但在使用Update命令后,Json更改为此

{
    "ID" : "id",
    "Dict" :
    {
        "_t" : "System.Collections.Generic.Dictionary`2[System.String,System.String]",
        "_v" :
        {
            "Key": "Val"
        }
    }
}

这个问题是BsonSerializer在遇到_t / _v语法时会抛出错误。那么,我如何使Update序列化与Insert?

相同

注意:
驱动程序版本为2.4.4
IMongoCollection的TDocument始终是BsonDocument
字典只是一个例子,任何具有复杂值的数据类型都会发生这种情况,包括数组

修改
这是代码的简单版本。

static void Main(string[] args)
{
    MongoDB.Driver.MongoClient client = new MongoDB.Driver.MongoClient("mongodb://localhost");
    MongoDB.Driver.IMongoDatabase db = client.GetDatabase("TestBase");
    MongoDB.Driver.IMongoCollection<MongoDB.Bson.BsonDocument> coll = db.GetCollection<MongoDB.Bson.BsonDocument>("TestColl");
    Dictionary<string, string> tmpDict = new Dictionary<string, string>();
    object tmpDict_o = null;

    tmpDict.Add("Key", "Val");
    tmpDict_o = tmpDict;

    coll.DeleteMany(MongoDB.Driver.Builders<MongoDB.Bson.BsonDocument>.Filter.Empty);

    coll.InsertOne(MongoDB.Bson.BsonDocumentWrapper.Create(new Custom() { ID = "id", Dict = tmpDict }));

    Console.ReadLine();

    coll.UpdateMany(MongoDB.Driver.Builders<MongoDB.Bson.BsonDocument>.Filter.Empty, MongoDB.Driver.Builders<MongoDB.Bson.BsonDocument>.Update.Set("Dict", tmpDict_o));
    }

如果在UpdateMany中将tmpDict_o更改为tmpDict,它将按预期工作,但由于我不知道变量将具有哪种类型的值,因此必须将其存储在对象中。 (原始函数将采用任何类型并使用反射提取属性值)

编辑2
通过MongoDB.Driver进行调试我发现mongo遏制的类型是通过查看IMongoCollection的TDocument来键入字段,并且通过使用BsonDocument它将始终采用默认的序列化器(对于System.Object)。所以我的下一个解决方案是打开两个系列;一个用于插入的BsonDocument,另一个用于更新的类型(在此示例中为Custom)。在这种情况下,字典的更新进展顺利,但阵列更糟糕。字符串数组被序列化为字符串,其值为“String [] Array”,复杂类型的数组仍然具有_t / _v语法。

1 个答案:

答案 0 :(得分:0)

回答我自己的问题。我在编辑2 中写的部分是正确的,如果TDocument是BsonDocument,文档序列化器将被设置为BsonDocumentSerializer,但是字段序列化器将在UpdateDefinitionBuilder的Set方法中解析。因为变量被声明为

object tmpDict_o = null;

TField永远是对象。要修复此行为,您可以将变量声明为

dynamic tmpDict_o = null; 

所以TField将被设置为正确的类型。

注意:
虽然此解决方案有效,但您必须始终将您的类声明为public,否则由于某种原因它将回退到_t / _v语法。