2

私はテストコードを持っています:

        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();
        }

カテゴリ製品クラスのマッピング:

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] *

それは結構です、そして私はそれを理解したと思います:)

そこで、Categoryクラス内にメソッドを作成しました。

    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();
        }

ForEachClearProducts呼び出しに置き換えました。そして今、私は例外を受け取ります:

System.IndexOutOfRangeException : System.Collections.Generic.List`1.Clear() の System.Array.Clear(Array array, Int32 index, Int32 length) でインデックスが配列の境界外でした

コレクションからすべての製品を削除するためにwhile(products.Count >0)ループも使用しましたが、例外も発生しました。コレクションから子オブジェクトを削除できない場合、子オブジェクトを削除する方法を教えてもらえますか?

ありがとう

EDIT 1:私は唖然としています...コレクションのタイプ(およびフィールド定義)を次から変更しました:

    private List<Product> products = null;

に:

    private IList<Product> products = null;

コードが機能します。誰かが私の理由を教えてください。

4

1 に答える 1

2

問題 #1 - 子コレクションからオブジェクトを直接削除することはできません。それらを削除するには、Products から項目を削除してから、親の Category オブジェクトを保存します。したがって、DDD の用語では、集約ルート オブジェクトに対してのみ削除を実行する必要がありますが、それは既に理解しています。

問題 2 - 遅延読み込みを使用している場合は、パブリック インスタンス メンバーに virtual キーワードを設定し、コレクション用のインターフェイスを使用する必要があります。これにより、NHibernate は、最初にアクセスしたときに遅延読み込みの方法を知っているプロキシでプロパティを置き換えることができます。これは、良い答えのある同様の質問です。

Category および CategoryMap クラスがそのようになっていることは確かですか? パブリックプロパティにセッターがなく、マッピングで別のアクセス戦略を定義していないため、そこにあるようなマッピングがどのように機能するかわかりません。

于 2012-05-31T22:20:58.543 に答える