C# MongoDB 多类型序列化

Posted

技术标签:

【中文标题】C# MongoDB 多类型序列化【英文标题】:C# MongoDB multiple type serialization 【发布时间】:2022-01-02 00:21:28 【问题描述】:

我使用 MongoDB C# 驱动程序 (2.13.2),并且我使用集合中的此类输入数据,其中一个 Value 字段可以是 nulltrue、“字符串值” 或一个对象


  "ItemId": UUID("13202a78-668d-4b17-9aac-78524d50925e"),
  "FieldValue": 
    "FieldName" : "IsCity",
    "Value": true
  
,

  "ItemId": UUID("26566f9a-712d-44fe-9baa-722aa53e0038"),
  "FieldValue": 
    "FieldName" : "Address",
    "Value": "Address"
,

  "ItemId": UUID("6640a83a-a47d-4016-9d50-70c41425e099"),
  "FieldValue": 
    "FieldName" : "Address",
    "Value": 
      "Data1": "String",
      "Data2": [
        UUID("a9bde160-22af-4cf7-a201-57db8b392c4d")
      ]
    
  

这是我的序列化类:

class MyData 
  public Guid ItemId  get; set; 
  public MyFieldValue FieldValue  get; set; 


class MyFieldValue 
  public string FieldName  get; set; 
  public Dictionary<string, object> Value  get; set; 

我尝试使用字典或 BSON 文档,但由于 truefalse 值,在序列化过程中出现异常:无法反序列化 'Dictionary' 来自 BsonType 'Boolean'。 如何序列化一个可能非常不同的 Value

或者,在序列化时,将布尔值或字符串转换为 "value": "true" 形式的对象。然后所有的值都将是一个字典。但是怎么做呢?

【问题讨论】:

也许您只想要BsonValue 而不是Dictionary&lt;string, object&gt; 如果Value 属性的数据类型在编译时未知,您可以使用objectdynamic(基本上是object 加上一些编译器魔法)。跨度> 【参考方案1】:

您正在讨论的主题称为“架构版本控制”。见https://www.mongodb.com/blog/post/building-with-patterns-the-schema-versioning-pattern。

对于 C#,MongoDB 驱动程序有一些模式版本控制策略。见https://mongodb.github.io/mongo-csharp-driver/2.13/reference/bson/mapping/schema_changes/

在线文档中未描述的一个主题是使用泛型类型并转换为您的特定类型的能力。这不是首选方法,因为它需要对应用程序进行额外的工作来序列化和转换,但如果您不关心这些性能影响,那么这可能是一个值得考虑的想法。

这是一个使用泛型类型 (BsonDocument) 的示例,以说明对数据没有 C# 类型限制。我在您的原始问题(帖子)中使用了您的确切文件。

Test.cs

using MongoDB.Driver;

public class Test

    private MongoDB.Driver.IMongoClient client;
    private MongoDB.Driver.IMongoDatabase database; 
    private MongoDB.Driver.IMongoCollection<MongoDB.Bson.BsonDocument> collection;

    public Test()
    
        #pragma warning disable 0618
        MongoDB.Bson.BsonDefaults.GuidRepresentationMode = MongoDB.Bson.GuidRepresentationMode.V3;
        MongoDB.Bson.Serialization.BsonSerializer.RegisterSerializer(new MongoDB.Bson.Serialization.Serializers.GuidSerializer(MongoDB.Bson.GuidRepresentation.Standard));
        
        string uri = "mongodb://testuser:mysecret@localhost:50011,localhost:50012,localhost:50013/csharptest?replicaSet=replSet&authSource=admin&retryWrites=true&readConcernLevel=majority";
    
        this.client = new MongoDB.Driver.MongoClient(uri);
        this.database = client.GetDatabase("csharptesting");
        this.collection = database.GetCollection<MongoDB.Bson.BsonDocument>("somecollection");

        // CLEAR OUT ALL THE PRIOR TEST RECORDS
        this.collection.DeleteMany(new MongoDB.Bson.BsonDocument());
    

    public void insertRecords() 
    
        System.Console.WriteLine("Begin insert record 1...");
        MongoDB.Bson.BsonDocument document1 = new MongoDB.Bson.BsonDocument 
             "ItemId", new MongoDB.Bson.BsonBinaryData(new System.Guid("13202a78-668d-4b17-9aac-78524d50925e"), MongoDB.Bson.GuidRepresentation.Standard),
             "FieldValue", 
                new MongoDB.Bson.BsonDocument 
                    "FieldName", "IsCity",
                    "Value", true
                
             
        ;
        this.collection.InsertOne(document1);
        System.Console.WriteLine("End insert record 1");

        System.Console.WriteLine("Begin insert record 2...");
        MongoDB.Bson.BsonDocument document2 = new MongoDB.Bson.BsonDocument 
             "ItemId", new MongoDB.Bson.BsonBinaryData(new System.Guid("26566f9a-712d-44fe-9baa-722aa53e0038"), MongoDB.Bson.GuidRepresentation.Standard),
             "FieldValue", 
                new MongoDB.Bson.BsonDocument 
                    "FieldName", "Address",
                    "Value", "Address"
                
             
        ;
        this.collection.InsertOne(document2);
        System.Console.WriteLine("End insert record 2");


        System.Console.WriteLine("Begin insert record 3...");
        MongoDB.Bson.BsonDocument document3 = new MongoDB.Bson.BsonDocument 
             "ItemId", new MongoDB.Bson.BsonBinaryData(new System.Guid("6640a83a-a47d-4016-9d50-70c41425e099"), MongoDB.Bson.GuidRepresentation.Standard),
             "FieldValue", 
                new MongoDB.Bson.BsonDocument 
                    "FieldName", "Address",
                    "Value", 
                        new MongoDB.Bson.BsonDocument 
                             "Data1", "String" ,
                             "Data2", new MongoDB.Bson.BsonBinaryData(new System.Guid("a9bde160-22af-4cf7-a201-57db8b392c4d"), MongoDB.Bson.GuidRepresentation.Standard)
                        
                    
                
             
        ;
        this.collection.InsertOne(document3);
        System.Console.WriteLine("End insert record 3");
    

    public void find()
    
        System.Console.WriteLine("Find data...");

        foreach(MongoDB.Bson.BsonDocument record in this.collection.Find(new MongoDB.Bson.BsonDocument()).ToList())
        
            System.Console.WriteLine(record);
        

        System.Console.WriteLine("End find data");
    

Program.cs

namespace Full_Example

    class Program
    
        static void Main(string[] args)
        
            var test = new Test();
            test.insertRecords();
            test.find();
        
    

输出

Begin insert record 1...
End insert record 1
Begin insert record 2...
End insert record 2
Begin insert record 3...
End insert record 3
Find data...
 "_id" : ObjectId("619d15d9bd6b57dece960714"), "ItemId" : UUID("13202a78-668d-4b17-9aac-78524d50925e"), "FieldValue" :  "FieldName" : "IsCity", "Value" : true  
 "_id" : ObjectId("619d15d9bd6b57dece960715"), "ItemId" : UUID("26566f9a-712d-44fe-9baa-722aa53e0038"), "FieldValue" :  "FieldName" : "Address", "Value" : "Address"  
 "_id" : ObjectId("619d15d9bd6b57dece960716"), "ItemId" : UUID("6640a83a-a47d-4016-9d50-70c41425e099"), "FieldValue" :  "FieldName" : "Address", "Value" :  "Data1" : "String", "Data2" : UUID("a9bde160-22af-4cf7-a201-57db8b392c4d")   
End find data

结论

您可以使用通用类型访问查询的文档,例如 BsonDocument() 并逐字段访问。使用这种方法,您可以将此 BsonDocument 转换为您的特定类型,但这需要自定义转换器方法。

【讨论】:

一个很好的答案,也许 BsonDocument 的整个对象很多,而 @Llama 建议的一个字段就可以了。

以上是关于C# MongoDB 多类型序列化的主要内容,如果未能解决你的问题,请参考以下文章

在 C# 中从序列化为 JSON 的 mongodb 文档中删除 ObjectId

如何在 C# 中序列化时删除列表类型属性名称以及 和 [] 括号

无论如何在 C# 中反序列化之前检查对象的类类型?

C# 类型序列化不作为键值对的集合

反序列化 json,其中属性与内置数据类型同名,在 C# 中

C# Json反序列化 数据协定类型 无法反序列化 由于未找到必需的数据成员