Search code examples
c#nhibernatenhibernate-mappingnhibernate-cascade

collection cascade type in nhibernate


I am using NHibernate 3.2, and using Mapping by Code.

The test case is pretty straight-forward - I have a Store and a Product, linked by a many-to-many collection. The many-to-many collection in the StoreMap is mapped as follows:

Set(x => x.Products, x =>
        {
            x.Fetch(CollectionFetchMode.Subselect);
            x.Key(key =>
            {
                key.Column("StoreId");
                key.ForeignKey("FK_StoreProducts_Store");
            });
            x.Table("StoreProducts");
            x.Cascade(Cascade.None);
            x.Inverse(true);

        },

If I am correct, the Cascade option should allow you to choose whether you want to cascade operations on the class, to the collection as well. NHibernate 3.2 allows these options, which are not really straightforward for me:

[Flags]
public enum Cascade
{
    None = 0,
    Persist = 2,
    Refresh = 4,
    Merge = 8,
    Remove = 16,
    Detach = 32,
    ReAttach = 64,
    DeleteOrphans = 128,
    All = 256,
}

The example I am using is the one below, where I am creating a test Store, and a test Product, and assigning it to the store. Then I am reloading the Store, retrieving the first Product, updating it, and saving the Store.

Even though the cascade is set as 'None', the Product still updates! Is it normal that this should happen?

using (var session = SessionFactory.OpenSession())
        {
            long storeId = 5;
            using (var t = session.BeginTransaction())
            {
                Product p1 = new Product();
                p1.Name = "Product 1";
                session.Save(p1);

                Store store = new Store();
                store.Name = "Tesco";
                session.Save(store);

                p1.Stores.Add(store);
                store.Products.Add(p1);
                session.Save(store);

                storeId = store.Id;
                t.Commit();
            }

            using (var t = session.BeginTransaction())
            {
                Store s = session.Get<Store>(storeId);
                Product p = s.Products.FirstOrDefault();
                p.Name = "Product 1 Updated";
                session.Save(s);
                t.Commit(); // <-- Product is still being updated here!

            }
            session.Flush();
        }

Solution

  • Feature that you are facing is called change tracking, and has nothing to do with cascading options. NHibernate tracks all objects that are associated with a session and sends all changes to DB when transaction is committed.

    If you don't need it you can use Stateless session in order to get non tracked entities. But in this case you will not have lazy loading. Also you can try to use FlushMode.Never in order to prevent NHibernate from automatic flushing changes to DB