如何将嵌套对象存储在不同的MongoDB集合中?

4

我需要存储一些这些类的对象:

public class Category{
    public ObjectId Id {get;set;}
    public string Name {get;set;}
    public string Description {get;set;}
    public List<Product> Products {get;set;}
}

public class Product{
    public ObjectId Id {get;set;}
    public string Name {get;set;}
    public string Description {get;set;}
    public decimal Price {get;set;}
}

当我使用NoRM并使用mongo.GetCollection().Insert(Category)存储一个Category对象时,我可以在mongo shell中看到:

db.Category.find()
{ "_id" : ObjectId("82bbbf0179eae0141d020000"), "Name" : "Test products", "Descr
iption" : "This is test category", "Products" : [
        {
                "_id" : ObjectId("81bbbf0179eae0141d000000"),
                "Name" : "Product1",
                "Description" : "first product",
                "Price" : {

                }
        },
        {
                "_id" : ObjectId("82bbbf0179eae0141d010000"),
                "Name" : "Product2",
                "Description" : "second product",
                "Price" : {

                }
        }
] }

我可以将类别和产品对象存储在不同的集合中,并且只在类别记录中引用产品而不更改类的代码吗?(就像NHibernate一样)


Product和Category之间存在一对多的关系。我建议您将引用存储在多个实体中,就像在SQL数据库中一样。因此,产品将指向类别,而不是相反。优点是当您将产品移动到另一个类别时,您只需要更新产品中的引用。在您的设计中,您需要从旧类别中删除产品并将其添加到新类别中。如果您的示例仅用于演示问题,请忽略我的评论 :) - Niels van der Rest
1个回答

4
不行,至少不能自动完成。
SQL 数据库最适合在多个表中存储规范化的数据。表之间的关系由外键关系定义。NHibernate 使用这些外键关系将对象映射到多个表。
MongoDB 适用于存储文档。这些文档通常是数据的非规范化表示。其思想是将相关数据存储在单个文档中,而不是多个表中。由于这种哲学,MongoDB 不需要外键概念或联接集合的能力。
理论上,NoRM 可以在未来支持此类功能,但这将违背文档数据库的精神。因此,它不太可能得到支持。
手动解决方案
您可以通过应用 MongoIgnore 属性来告诉 NoRM 在保存类别时跳过 Products 属性。然后手动将产品与“参考”类别一起存储在单独的集合中。使用自定义集合可以自动跟踪产品的类别。代码看起来像这样:
public class ProductCollection : Collection<Product>
{
  private Category owner;

  public ProductCollection(Category owner)
  {
    // Remember who 'owns' the products in this collection.
    this.owner = owner;
  }

  protected override void InsertItem(int index, Product item)
  {
    // Tell the product to which category it belongs.
    item.CategoryId = this.owner.Id;

    base.InsertItem(index, item);
  }

  // Override other methods using the same pattern.
}

public class Category
{
  public Category()
  {
    this.Id = ObjectId.NewObjectId();
    this.Products = new ProductCollection(this);
  }

  public ObjectId Id { get; set; }
  public string Name { get; set; }
  public string Description { get; set; }

  [MongoIgnore]
  public ProductCollection Products { get; private set; }
}

public class Product
{
  public ObjectId Id { get; set; }
  public string Name { get; set; }
  public string Description { get; set; }
  public decimal Price { get; set; }
  public ObjectId CategoryId { get; set; }
}

现在,您可以将类别存储在一个集合中,产品存储在另一个集合中。属性 CategoryId 将指示产品所属的类别。


非常感谢您提供完整的答案。我将在我的项目中使用这个解决方案。 - Michael
你好,感谢你的回答。你能否为MongoDB 6提供一个更新的解决方案? - fatihyildizhan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接