4

我们目前正在使用 Simple.Data 和 MongoDb 适配器。当我们检索到一个文档时,我们将其转换为 POCO,例如:

(User)db.Users.FindById(1234);

首先,这很好用(哎呀,没有模式!)。但是,如果我们改变 User 对象的结构(例如添加一个新字段,或者改变一个字段的数据类型),那么我们就不能再转换原始文档,因为它与我们的新类结构不匹配。

为了解决这个问题,到目前为止,我们已经尝试了两种最直接的方法:

  1. 手动数据更新以反映文档结构的变化。目前还可以,但当项目跨多个环境部署/投入生产时无法管理
  2. 手动映射;例如。将 SimpleRecord 转换为字典并手动评估成员。我担心这种方法的性能,尽管尚未对其进行基准测试。我还担心在不使用目标类型的反射来识别成员名称的情况下,我还没有找到一种使其通用的方法。

我们还研究了使用RubyPython解决此问题的方法。前者更具吸引力(在 Ming 中维护旧模式版本似乎可能是矫枉过正)。

在我跑掉并移植一些疯狂的东西之前,有没有人用 Simple.Data 解决了这个问题?任何人都可以提供有关在无模式数据库中处理文档结构更改的最佳实践的任何指导吗?

4

1 回答 1

2

查看自定义序列化。在我的情况下,它既快速又有用:

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-09-19T20:01:56.563 回答