You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MongoDB .NET Driver无法创建三层嵌套文档问题求助

三层嵌套MongoDB文档插入失败问题解决

问题描述

使用MongoDB .NET Driver v3.7开发控制台应用时,插入三层嵌套文档后,三级的Review数据未被保存到数据库中。顶层LibraryUser包含二级Book列表,二级Book包含三级Review列表,但查询数据库时仅能看到前两层数据。尝试手动注册Review类的BsonClassMap无效。

文档类定义

public class LibraryUser
{
    [BsonRepresentation(BsonType.ObjectId)]
    public string Id { get; set; } = ObjectId.GenerateNewId().ToString();
    public required int UserId { get; set; }
    public List<Book> Books { get; set; } = [];
    public void AddBook(Book book)
    {
        Books.Add(book);
    }
}
public class Book
{
    [BsonRepresentation(BsonType.ObjectId)]
    public string Id { get; set; } = ObjectId.GenerateNewId().ToString();
    public string BookTitle { get; set; }
    public int Price { get; set; }
    List<Review> Reviewers { get; set; } = [];
    public void addReview(Review review)
    {
        Reviewers.Add(review);
    }
}
public class Review
{
    [BsonRepresentation(BsonType.ObjectId)]
    public string Id { get; set; } = ObjectId.GenerateNewId().ToString();
    public string Reviewer { get; set; }
    public int Grade { get; set; }
}

插入代码

iMongoDatabase.CreateCollection("LibraryUsers");
LibraryUsersCollection = iMongoDatabase!.GetCollection<LibraryUser>("LibraryUsers");
LibraryUser userDoc = new()  
{
    UserId = 999999
};
Book book = new()  
{
    BookTitle = "Old Yeller",
    Price = 11
};
Review review = new() 
{
    Reviewer = "Corin",
    Grade = 55
};
book.addReview(review); 
userDoc.AddBook(book);  
LibraryUsersCollection.InsertOne(userDoc);

数据库查询结果

db.LibraryUsers.find()
[
  {
    _id: ObjectId('69e22dcac06b765666fcda19'),
    UserId: 999999,
    Books: [
      {
        _id: ObjectId('69e22dcac06b765666fcda1a'),
        BookTitle: 'Old Yeller',
        Price: 11
      }
    ]
  }
]

原因分析

MongoDB .NET Driver默认仅序列化公共成员,Book类中的Reviewers是私有属性(缺少public修饰符),驱动无法识别并序列化这个字段,因此插入时不会将Review数据写入数据库。手动注册Review的类映射无效,因为问题根源不在Review类本身,而是Book类中对Review列表的访问权限。

解决方案

有两种可行的修改方式,推荐第一种符合C#编码规范的方案:

方案1:将Reviewers改为公共属性

修改Book类,把Reviewers字段改为公共属性,同时修正方法名首字母大写(符合C#命名规范):

public class Book
{
    [BsonRepresentation(BsonType.ObjectId)]
    public string Id { get; set; } = ObjectId.GenerateNewId().ToString();
    public string BookTitle { get; set; }
    public int Price { get; set; }
    // 改为公共属性
    public List<Review> Reviewers { get; set; } = [];
    // 修正方法名首字母大写
    public void AddReview(Review review)
    {
        Reviewers.Add(review);
    }
}

方案2:保留私有字段并添加BsonElement标记

如果需要保持字段私有,可以添加[BsonElement]特性让驱动识别:

public class Book
{
    [BsonRepresentation(BsonType.ObjectId)]
    public string Id { get; set; } = ObjectId.GenerateNewId().ToString();
    public string BookTitle { get; set; }
    public int Price { get; set; }
    // 添加BsonElement标记私有字段
    [BsonElement("Reviewers")]
    List<Review> Reviewers { get; set; } = [];
    public void addReview(Review review)
    {
        Reviewers.Add(review);
    }
}

验证结果

修改后重新执行插入代码,查询数据库即可看到三级Review数据:

db.LibraryUsers.find()
[
  {
    _id: ObjectId('69e23a12c06b765666fcda1b'),
    UserId: 999999,
    Books: [
      {
        _id: ObjectId('69e23a12c06b765666fcda1c'),
        BookTitle: 'Old Yeller',
        Price: 11,
        Reviewers: [
          {
            _id: ObjectId('69e23a12c06b765666fcda1d'),
            Reviewer: 'Corin',
            Grade: 55
          }
        ]
      }
    ]
  }
]

补充说明

不需要手动注册Review类的BsonClassMap,驱动会自动识别公共成员并完成序列化。只有当需要自定义序列化逻辑(如字段重命名、忽略特定成员等)时,才需要手动配置类映射。

内容的提问来源于stack exchange,提问作者Skippy VonDrake

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.01 15:44:52