2

让我们假设我们有一个文档来存储我们的客户端,它具有固定和额外的字段。所以这里是我们的客户端示例类:

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}

这将提高搜索性能,通常是文档方向的重点。

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

4

2 回答 2

1

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

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();
        }

    } }
于 2011-08-05T14:50:29.533 回答
0

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.

于 2011-08-04T09:44:28.643 回答