使用 MongoDb 和 C# 将架构依赖类转换为无架构文档

发布于 2024-11-28 00:08:03 字数 816 浏览 0 评论 0原文

假设我们有一个存储客户的文档,其中包含固定字段和额外字段。 所以这里是我们为客户端提供的示例类:

public class Client
{
     public string Name{ get; set; }
     public string Address{ get; set; }
     public List<ExtraField> ExtraFields{ get; set; } //these fields are extra ones
}

在额外的字段类中,我们有这样的东西:

public class ExtraField
{
    public string Key{ get; set; }
    public string Type { get; set; }
    public string Value { get; set; }
}

如果我使用标准驱动程序的行为进行序列化,我会得到这样的东西:

{{Name:VName, Address:VAddress,  ExtraFields:[{Key:VKey,Type:VType,
Value:VValue},...]}, document2,...,documentn}

虽然我希望有这样的东西:

{{Name:VName, Address:VAddress, VKey:VValue,...}, document2,...,documentn}

这会改善搜索性能,通常是文档方向的重点。

如何以这种方式自定义序列化?

Let us suppose we have a document to store our client which has fixed and extra fields.
So here goes our sample class for the client:

public class Client
{
     public string Name{ get; set; }
     public string Address{ get; set; }
     public List<ExtraField> ExtraFields{ get; set; } //these fields are extra ones
}

In extra field class we have something like this:

public class ExtraField
{
    public string Key{ get; set; }
    public string Type { get; set; }
    public string Value { get; set; }
}

If I use standard driver's behaviour for serialization I would get smth like this:

{{Name:VName, Address:VAddress,  ExtraFields:[{Key:VKey,Type:VType,
Value:VValue},...]}, document2,...,documentn}

While I would like to have something like this:

{{Name:VName, Address:VAddress, VKey:VValue,...}, document2,...,documentn}

This would improve the search performance and is generally the point of document orientation.

How can I customize the serialization to such a way?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

萌无敌 2024-12-05 00:08:03

这是我解决它的方法(它工作正常)并解决了问题。

using System; 
using System.Collections.Generic; 
using System.Linq; using System.Text; 
using MongoDB.Bson;
using MongoDB.Bson.Serialization; 
using MongoDB.Bson.Serialization.Serializers;

namespace TestDataGeneration {
    public class FieldsWrapper : IBsonSerializable
    {
        public List<DataFieldValue> DataFieldValues { get; set; }


        public object Deserialize(MongoDB.Bson.IO.BsonReader bsonReader, Type nominalType, IBsonSerializationOptions options)
        {
        if (nominalType != typeof(FieldsWrapper)) throw new ArgumentException("Cannot deserialize anything but self");
        var doc = BsonDocument.ReadFrom(bsonReader);
        var list = new List<DataFieldValue>();
        foreach (var name in doc.Names)
        {
            var val = doc[name];
            if (val.IsString)
                list.Add(new DataFieldValue {LocalIdentifier = name, Values = new List<string> {val.AsString}});
            else if (val.IsBsonArray)
            {
                DataFieldValue df = new DataFieldValue {LocalIdentifier = name};
                foreach (var elem in val.AsBsonArray)
                {
                    df.Values.Add(elem.AsString);
                }
                list.Add(df);
            }
        }
        return new FieldsWrapper {DataFieldValues = list};
        }


        public void Serialize(MongoDB.Bson.IO.BsonWriter bsonWriter, Type nominalType, IBsonSerializationOptions options)
        {
            if (nominalType != typeof (FieldsWrapper))
                throw new ArgumentException("Cannot serialize anything but self");
            bsonWriter.WriteStartDocument();
            foreach (var dataFieldValue in DataFieldValues)
            {

                bsonWriter.WriteName(dataFieldValue.LocalIdentifier);
                if (dataFieldValue.Values.Count != 1)
                {
                    var list = new string[dataFieldValue.Values.Count];
                    for (int i = 0; i < dataFieldValue.Values.Count; i++)
                        list[i] = dataFieldValue.Values[i];
                    BsonSerializer.Serialize(bsonWriter, list); 
                }
                else
                {
                    BsonSerializer.Serialize(bsonWriter, dataFieldValue.Values[0]); 
                }
            }
            bsonWriter.WriteEndDocument();
        }

    } }

Here is the way I solved it (it works fine) and solved the issue.

using System; 
using System.Collections.Generic; 
using System.Linq; using System.Text; 
using MongoDB.Bson;
using MongoDB.Bson.Serialization; 
using MongoDB.Bson.Serialization.Serializers;

namespace TestDataGeneration {
    public class FieldsWrapper : IBsonSerializable
    {
        public List<DataFieldValue> DataFieldValues { get; set; }


        public object Deserialize(MongoDB.Bson.IO.BsonReader bsonReader, Type nominalType, IBsonSerializationOptions options)
        {
        if (nominalType != typeof(FieldsWrapper)) throw new ArgumentException("Cannot deserialize anything but self");
        var doc = BsonDocument.ReadFrom(bsonReader);
        var list = new List<DataFieldValue>();
        foreach (var name in doc.Names)
        {
            var val = doc[name];
            if (val.IsString)
                list.Add(new DataFieldValue {LocalIdentifier = name, Values = new List<string> {val.AsString}});
            else if (val.IsBsonArray)
            {
                DataFieldValue df = new DataFieldValue {LocalIdentifier = name};
                foreach (var elem in val.AsBsonArray)
                {
                    df.Values.Add(elem.AsString);
                }
                list.Add(df);
            }
        }
        return new FieldsWrapper {DataFieldValues = list};
        }


        public void Serialize(MongoDB.Bson.IO.BsonWriter bsonWriter, Type nominalType, IBsonSerializationOptions options)
        {
            if (nominalType != typeof (FieldsWrapper))
                throw new ArgumentException("Cannot serialize anything but self");
            bsonWriter.WriteStartDocument();
            foreach (var dataFieldValue in DataFieldValues)
            {

                bsonWriter.WriteName(dataFieldValue.LocalIdentifier);
                if (dataFieldValue.Values.Count != 1)
                {
                    var list = new string[dataFieldValue.Values.Count];
                    for (int i = 0; i < dataFieldValue.Values.Count; i++)
                        list[i] = dataFieldValue.Values[i];
                    BsonSerializer.Serialize(bsonWriter, list); 
                }
                else
                {
                    BsonSerializer.Serialize(bsonWriter, dataFieldValue.Values[0]); 
                }
            }
            bsonWriter.WriteEndDocument();
        }

    } }
卸妝后依然美 2024-12-05 00:08:03

本质上你只需要自己实现两个方法。第一个根据需要序列化对象,第二个将对象从数据库反序列化到您的 Client 类:

1 序列化客户端类:

public static BsonValue ToBson(Client client)
{
  if (client == null)
    return null;

  var doc = new BsonDocument();
  doc["Name"] = client.Name;
  doc["Address"] = client.Address;
  foreach (var f in client.ExtraFields)
  {
    var fieldValue = new BsonDocument();
    fieldValue["Type"] = f.Type;
    fieldValue["Value"] = f.Value;
    doc[f.Key] = fieldValue;
  }

  return doc;
}

2 反序列化客户端对象:

public static Client FromBson(BsonValue bson)
{
  if (bson == null || !bson.IsBsonDocument)
    return null;

  var doc = bson.AsBsonDocument;

  var client = new Client
  {
    ExtraFields = new List<ExtraField>(),
    Address = doc["Address"].AsString,
    Name = doc["Name"].AsString
  };
  foreach (var name in doc.Names)
  {
    var val = doc[name];
    if (val is BsonDocument)
    {
      var fieldDoc = val as BsonDocument;
      var field = new ExtraField
      {
        Key = name,
        Value = fieldDoc["Value"].AsString,
        Type = fieldDoc["Type"].AsString
      };
       client.ExtraFields.Add(field);
     }
   }

 return client;
}

3 完整的测试示例:

我在上面添加了您的客户端类的两种方法。

var server = MongoServer.Create("mongodb://localhost:27020");
var database = server.GetDatabase("SO");

var clients = database.GetCollection<Type>("clients");


var client = new Client() {Id = ObjectId.GenerateNewId().ToString()};
client.Name = "Andrew";
client.Address = "Address";
client.ExtraFields = new List<ExtraField>();
client.ExtraFields.Add(new ExtraField()
{
  Key = "key1",
  Type = "type1",
  Value = "value1"
});
client.ExtraFields.Add(new ExtraField()
{
  Key = "key2",
  Type = "type2",
  Value = "value2"
});

 //When inseting/saving use ToBson to serialize client
clients.Insert(Client.ToBson(client));

//When reading back from the database use FromBson method:
var fromDb = Client.FromBson(clients.FindOneAs<BsonDocument>());

4 数据库中的数据结构:

{
  "_id" : ObjectId("4e3a66679c66673e9c1da660"),
  "Name" : "Andrew",
  "Address" : "Address",
  "key1" : {
    "Type" : "type1",
    "Value" : "value1"
  },
  "key2" : {
    "Type" : "type2",
    "Value" : "value2"
  }
}

顺便说一句:查看序列化教程 也是如此。

Essentially you just need to implement two methods yourself. First one to serialize an object as you want and second to deserialize an object from db to your Client class back:

1 Seialize client class:

public static BsonValue ToBson(Client client)
{
  if (client == null)
    return null;

  var doc = new BsonDocument();
  doc["Name"] = client.Name;
  doc["Address"] = client.Address;
  foreach (var f in client.ExtraFields)
  {
    var fieldValue = new BsonDocument();
    fieldValue["Type"] = f.Type;
    fieldValue["Value"] = f.Value;
    doc[f.Key] = fieldValue;
  }

  return doc;
}

2 Deserialize client object:

public static Client FromBson(BsonValue bson)
{
  if (bson == null || !bson.IsBsonDocument)
    return null;

  var doc = bson.AsBsonDocument;

  var client = new Client
  {
    ExtraFields = new List<ExtraField>(),
    Address = doc["Address"].AsString,
    Name = doc["Name"].AsString
  };
  foreach (var name in doc.Names)
  {
    var val = doc[name];
    if (val is BsonDocument)
    {
      var fieldDoc = val as BsonDocument;
      var field = new ExtraField
      {
        Key = name,
        Value = fieldDoc["Value"].AsString,
        Type = fieldDoc["Type"].AsString
      };
       client.ExtraFields.Add(field);
     }
   }

 return client;
}

3 Complete test example:

I've added above two method to your client class.

var server = MongoServer.Create("mongodb://localhost:27020");
var database = server.GetDatabase("SO");

var clients = database.GetCollection<Type>("clients");


var client = new Client() {Id = ObjectId.GenerateNewId().ToString()};
client.Name = "Andrew";
client.Address = "Address";
client.ExtraFields = new List<ExtraField>();
client.ExtraFields.Add(new ExtraField()
{
  Key = "key1",
  Type = "type1",
  Value = "value1"
});
client.ExtraFields.Add(new ExtraField()
{
  Key = "key2",
  Type = "type2",
  Value = "value2"
});

 //When inseting/saving use ToBson to serialize client
clients.Insert(Client.ToBson(client));

//When reading back from the database use FromBson method:
var fromDb = Client.FromBson(clients.FindOneAs<BsonDocument>());

4 Data structure in a database:

{
  "_id" : ObjectId("4e3a66679c66673e9c1da660"),
  "Name" : "Andrew",
  "Address" : "Address",
  "key1" : {
    "Type" : "type1",
    "Value" : "value1"
  },
  "key2" : {
    "Type" : "type2",
    "Value" : "value2"
  }
}

BTW: Take a look into serialization tutorial as well.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文