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
相关产品推荐
相关产品推荐

