在子文档中不使用区分符的情况下将C#类序列化到MongoDB

我正在编写C#代码,该代码将写入现有Web应用程序(用PHP编写)所使用的Mongo数据库中,因此无需更改数据库的现有结构。数据库结构如下所示:

{
    "_id": ObjectId("5572ee670e86b8ec0ed82c61")
    "name": "John Q. Example",
    "guid": "12345678-1234-5678-abcd-fedcba654321",
    "recordIsDeleted": false,
    "address":
    {
        "line1": "123 Main St.",
        "city": "Exampleville"
    }
}

我将其读入如下所示的类中:

public class Person : MongoMappedBase
{
    public ObjectId Id { get; set; }
    public Guid Guid { get; set; }
    public bool RecordIsDeleted { get; set; }
    public string Name { get; set; }
    public AddressData Address { get; set; }
    // etc.
}

public class AddressData : MongoMappedBase
{
    public string Line1 { get; set; }
    public string City { get; set; }
    // etc.
}

阅读代码如下所示:

var collection = db.GetCollection<Person>("people");
List<Person> people = collection.Find<Person>(_ => true).ToListAsync().Result;

(注意:我仍在开发中。在生产中,我将一次切换到ToCursorAsync()并遍历数据,因此不必担心我会将整个列表拉入内存的事实。)

到现在为止还挺好。

但是,当我写出数据时,它是这样的:

{
    "_id": ObjectId("5572ee670e86b8ec0ed82c61")
    "name": "John Q. Example",
    "guid": "12345678-1234-5678-abcd-fedcba654321",
    "recordIsDeleted": false,
    "address":
    {
        "_t": "MyApp.MyNamespace.AddressData, MyApp",
        "_v":
        {
            "line1": "123 Main St.",
            "city": "Exampleville"
        }
    }
}

注意该address字段看起来如何那不是我想要的 我希望地址数据看起来像地址数据输入(否_t_v字段)。换句话说,最后作为内容的部分_v是我想要作为address字段值保留在Mongo数据库中的内容

现在,如果我只是从自己的C#代码中使用Mongo数据库,那可能很好:如果我要反序列化此数据结构,则我假设(尽管我尚未验证)Mongo将使用_tand_v字段来创建正确类型(AddressData)的实例,并将其放在实例Address属性中Person在这种情况下,一切都会好起来的。

但是,我与一个PHP Web应用程序共享了该数据库,该Web应用程序希望在地址数据中看到这些_t_v值,并且不知道如何处理它们。我要告诉蒙戈“请不要序列化的类型Address属性。姑且认为它始终将是一个AddressData实例,只是序列化的内容没有任何鉴别。”

我当前用于将对象持久保存到Mongo的代码如下所示:

public UpdateDefinition<TDocument> BuildUpdate<TDocument>(TDocument doc) {
    var builder = Builders<TDocument>.Update;
    UpdateDefinition<TDocument> update = null;
    foreach (PropertyInfo prop in typeof(TDocument).GetProperties())
    {
        if (prop.PropertyType == typeof(MongoDB.Bson.ObjectId))
            continue; // Mongo doesn't allow changing Mongo IDs
        if (prop.GetValue(doc) == null)
            continue; // If we didn't set a value, don't change existing one
        if (update == null)
            update = builder.Set(prop.Name, prop.GetValue(doc));
        else
            update = update.Set(prop.Name, prop.GetValue(doc));
    }
    return update;
}

public void WritePerson(Person person) {
    var update = BuildUpdate<Person>(person);
    var filter = Builders<Person>.Filter.Eq(
        "guid", person.Guid.ToString()
    );
    var collection = db.GetCollection<Person>("people");
    var updateResult = collection.FindOneAndUpdateAsync(
        filter, update
    ).Result;
}

在那儿的某个地方,我需要告诉Mongo:“我不在乎_tAddress属性字段,我什至都不希望看到它。我知道我在该字段中坚持使用哪种类型的对象,它们永远一样。” 但是我还没有在Mongo文档中找到任何可以告诉我如何做的东西。有什么建议么?

我想到了。我确实确实遇到了https://groups.google.com/forum/#!topic/mongodb-user/QGctV4Hbipk描述的问题,其中Mongo希望使用基本类型,但要使用派生类型。鉴于上面的代码,Mongo期望的基本类型实际上是object我发现这builder.Set()实际上是一个通用方法,builder.Set<TField>可以TField从第二个参数(字段数据)的类型中找出其类型参数。由于我正在使用prop.GetValue(),并且返回object,因此Mongoobject在我的Address字段(以及我遗漏的其他字段)中期望有一个实例,因此将_t所有这些字段放进去。

答案是显式转换从中返回的对象prop.GetValue(),以便在这种情况下builder.Set()可以调用正确的泛型方法(builder.Set<AddressData>()而不是builder.Set<object>())。以下内容有些丑陋(我希望有一种方法可以在运行时通过反射来获取特定的泛型函数重载,因为我可以将整个switch语句转换为基于反射的单个方法调用),但它确实有效:

public UpdateDefinition<TDocument> BuildUpdate<TDocument>(TDocument doc) {
    var builder = Builders<TDocument>.Update;
    var updates = new List<UpdateDefinition<TDocument>>();
    foreach (PropertyInfo prop in typeof(TDocument).GetProperties())
    {
        if (prop.PropertyType == typeof(MongoDB.Bson.ObjectId))
            continue; // Mongo doesn't allow changing Mongo IDs
        if (prop.GetValue(doc) == null)
            continue; // If we didn't set a value, don't change existing one
        switch (prop.PropertyType.Name) {
        case "AddressData":
            updates.add(builder.Set(prop.Name, (AddressData)prop.GetValue(doc)));
            break;
        // Etc., etc. Many other type names here
        default:
            updates.add(builder.Set(prop.Name, prop.GetValue(doc)));
            break;
        }
    }
    return builder.Combine(updates);
}

这导致了Address现场,并正在坚持没有任何所有我在我真正的代码遇到问题,其他领域_t_v领域,就像我想要的。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

如何在不使用 File.ReadAllLines 的情况下从 json 文件读取序列化对象?C#

如何在不使用 C# 中的序列化的情况下重新打开表单时在按钮上获取选定的组合框项目和文本

在使用Jackson进行类序列化时添加类型信息,以便可以在不使用注释的情况下使用接口类型反序列化?

如何在不使用类C#的情况下查找子列表的索引

在不使用唯一属性名称的情况下反序列化JSON

JSON.net在不使用模式的情况下反序列化JSON

如何在不使用序列化的情况下制作Java对象的深层副本?

如何在不使用 C# 中创建类的情况下解析此 json 结果

在 C# 中不使用序列化的值复制

在不使用C#中使用ODBC.DataReader的情况下将数据传递到另一个类

在某些问题未解决的情况下,如何在C#中反序列化json

在没有$运算符的情况下使用mongodb中的子数组元素更新多个文档

在不创建反序列化类的情况下访问 json 中的某个变量

具有从非通用基类继承的通用类的MongoDB C#驱动程序类型区分符

使用C#在MongoDB中反序列化接口-未知标识符值

在不使用管道运算符%>%的情况下将传单地图集成到Shiny中

如何在不使用 Builders 的情况下使用 .net(c#) 驱动程序更新 mongo db 中的文档?

如何在不进行序列化的情况下Redis缓存大型C#对象?

如何在不使用文件的情况下序列化一个对象(例如HashMap)?

JSON.net:如何在不使用默认构造函数的情况下反序列化?

有没有一种方法可以在不使用python GIL的情况下进行序列化/反序列化

如何使用c#而不是数组将JSON对象列表序列化到文件中

如何在不使用“_id”键的情况下使用 c# 在 MongoDB 中避免重复插入?

在不使用初始化方法的情况下将哈希传递给类

C#使用proto-buf序列化继承的类而不使用ProtoInclude

每个子类的表(不使用区分符)

在不使用数组的情况下打印C中相邻的整数和序列

如何在不使用C#定义静态类的情况下访问const值?

使用.htaccess动态重定向到子文件夹,在不使用域名的情况下将子文件夹隐藏在url中