无法在NHibernate中删除一对多关系中的子实体

时间:2012-05-31 20:46:26

标签: nhibernate nhibernate-mapping

我有一个测试代码:

        using (var session = factory.OpenSession())
        {
            var animalsCategory = session.Query<Category>().Where(c => c.Name == "Animals").Single();
            Assert.AreEqual(3, animalsCategory.Products.Count());
            animalsCategory.Products.ForEach(x => session.Delete(x));
            session.Flush();
        }

类别&amp;的映射产品类:

public class ProductMap : ClassMap<Product>
{
    public ProductMap()
    {
        Id(x => x.ID);
        Map(x => x.Name).Not.Nullable().Length(50);
        Map(x => x.Description).Length(4000);
        Map(x => x.UnitPrice).Not.Nullable();
        Map(x => x.ReorderLevel).Not.Nullable();
        Map(x => x.Discontinued);

        References(x => x.Category).Not.Nullable();
    }
}

public class CategoryMap : ClassMap<Category>
{
    public CategoryMap()
    {
        Id(x => x.ID);
        Map(x => x.Name);
        Map(x => x.Description);
        HasMany<Product>(x => x.Products).Inverse().Cascade.AllDeleteOrphan();
    }
}

此外,还有以下课程:

public class Product : Entity<Product>
{
    public virtual string Name { get; set; }
    public virtual string Description { get; set; }
    public virtual Category Category { get; set; }
    public virtual decimal UnitPrice { get; set; }
    public virtual int ReorderLevel { get; set; }
    public virtual bool Discontinued { get; set; }
}

public class Category : Entity<Category>
{
    private List<Product> products = null;

    public virtual string Name { get; set; }
    public virtual string Description { get; set; }
    public virtual IEnumerable<Product> Products { get { return products; } }
}

现在,当我运行测试代码时,我得到一个例外:

N * Hibernate.ObjectDeletedException:已删除的对象将通过级联重新保存(从关联中删除已删除的对象)[Model.Product#1] *

这很好,我想我明白了:)

所以我在类别类中创建了一个方法:

    public virtual void ClearProducts()
    {
        products.Clear();
    }

我已将测试代码更改为以下内容:

        using (var session = factory.OpenSession())
        {
            var animalsCategory = session.Query<Category>().Where(c => c.Name == "Animals").Single();
            Assert.AreEqual(3, animalsCategory.Products.Count());
            //animalsCategory.Products.ForEach(x => session.Delete(x));
            animalsCategory.ClearProducts();
            session.Flush();
        }

我已将 ForEach 替换为 ClearProducts 。现在我得到例外:

System.IndexOutOfRangeException:索引超出了System.Array.Clear数组的边界(数组数组,Int32索引,Int32长度) 在System.Collections.Generic.List`1.Clear()

我还使用 while(products.Count&gt; 0)循环从集合中删除所有产品,但我也有一个例外。有人可以告诉我,如果我不能将它们从集合中移除,我该如何删除子对象?

由于

编辑1:我惊呆了......我刚刚改变了收集类型(和字段定义):

    private List<Product> products = null;

为:

    private IList<Product> products = null;

和代码有效。有人可以告诉我为什么吗?

1 个答案:

答案 0 :(得分:2)

问题#1 - 您不能直接从子集合中删除对象。要删除它们,您将从Products中删除一个项目,然后保存父类别对象。因此,在DDD术语中,您应该只在aggregate root object上执行删除,但您已经想到了这一点。

问题#2 - 如果您使用延迟加载,则需要在公共实例成员上使用虚拟关键字并使用接口进行收集,以便NHibernate可以使用知道如何知道的代理替换您的属性首次访问时延迟加载。这是一个类似的question with a good answer

你确定你的Category和CategoryMap类现在看起来像那样吗?不确定像你这样的映射是如何工作的,因为你的公共属性上没有setter,也没有在映射中定义不同的访问策略。