Hi There
I am working on a mvc app using nhibernate as the orm (ncommon framework)
I have parent/child entities: Product, Vendor & ProductVendors and a one to many relationship between them with Product having a ProductVendors collection Product.ProductVendors.
I currently am retrieving a Product object and eager loading the children and sending these down the wire to my asp.net mvc client.
A user will then modify the list of Vendors and post the updated Product back. I am using a custom model binder to generate the modified Product entity. I am able to update the Product fine and insert new ProductVendors.
My problem is that dereferenced ProductVendors are not cascade deleted when specifying Product.ProductVendors.Clear() and calling _productRepository.Save(product).
The problem seems to be with attaching the detached instance. Here are my mapping files:
ProductCode:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
                   assembly="Test.Domain"
                   namespace="Test.Domain">
  <class name="Product" table="Product" >
    <id name="Id">
      <generator class="guid.comb" />
    </id>
    <version name="LastModified"
                    unsaved-value="0"
                    column="LastModified"
                     />
    
    <property name="Name" type="String" length="250" />
    
    <many-to-one name="Category"
                 class="Category"
                 column="CategoryId"
                 not-null="false"
                 lazy="false"/>
    <bag name="ProductVendors" lazy="false" table="Product_Vendor" cascade="all-delete-orphan" inverse="true">
      <key column="ProductId" on-delete="cascade"/>
      <one-to-many class="ProductVendor" />
    </bag>
    
  </class>
</hibernate-mapping>
ProductVendorsCode:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
                   assembly="Test.Domain"
                   namespace="Test.Domain">
  <class name="ProductVendor" table="Product_Vendor">
    <id name="Id">
      <generator class="guid.comb" />
    </id>
    <version name="LastModified"
                    unsaved-value="0"
                    column="LastModified"
                     />
    
    <property name="Price" />
    <many-to-one
      name="Product"
      class="Product"
      column="ProductId"
      lazy="false"
      not-null="true"
       />
    <many-to-one
     name="Vendor"
     class="Vendor"
     column="VendorId"
     lazy="false"
     not-null="true"
       />
    
  </class>
</hibernate-mapping>
Custom Model Binder:Code:
using System;
using Test.Web.Mvc; using Test.Domain;
namespace Spoked.MVC { 
public class ProductUpdateModelBinder : DefaultModelBinder {
    private readonly ProductSystem ProductSystem;
    public ProductUpdateModelBinder(ProductSystem productSystem)
    {
        ProductSystem = productSystem;
    }
    protected override void OnModelUpdated(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        var product = bindingContext.Model as Product;
        if (product != null)
        {
            product.Category = ProductSystem.GetCategory(new Guid(bindingContext.ValueProvider["Category"].AttemptedValue));
            product.Brand = ProductSystem.GetBrand(new Guid(bindingContext.ValueProvider["Brand"].AttemptedValue));
            product.ProductVendors.Clear();
            if (bindingContext.ValueProvider["ProductVendors"] != null)
            {
                string[] productVendorIds = bindingContext.ValueProvider["ProductVendors"].AttemptedValue.Split(',');
                foreach (string id in productVendorIds)
                {
                    product.AddProductVendor(ProductSystem.GetVendor(new Guid(id)), 90m);
                }
            }
        }
    } 
}
}
Controller:Code:
    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Update(Product product)
    {
        using (var scope = new UnitOfWorkScope())
        {
            //product.ProductVendors.Clear();
            _productRepository.Save(product);
            scope.Commit();
        }
        using (new UnitOfWorkScope())
        {
            IList<Vendor> availableVendors = _productSystem.GetAvailableVendors(product);
            productDetailEditViewModel = new ProductDetailEditViewModel(product,
                                                                        _categoryRepository.Select(x => x).ToList(),
                                                                        _brandRepository.Select(x => x).ToList(),
                                                                        availableVendors);
        }
        return RedirectToAction("Edit", "Products", new {id = product.Id.ToString()});
    }
The following Test does pass however:
Code:
 [Test]
        [NUnit.Framework.Category("ProductTests")]
        public void Can_Delete_Product_Vendors_By_Dereferencing()
        {
            Product product;
            using(UnitOfWorkScope scope = new UnitOfWorkScope())
            {
                Console.Out.WriteLine("Selecting...");
                product = _productRepository.First();
                Console.Out.WriteLine("Adding Product Vendor...");
                product.AddProductVendor(_vendorRepository.First(), 0m);
                scope.Commit();
            }
            Console.Out.WriteLine("About to delete Product Vendors...");
            using (UnitOfWorkScope scope = new UnitOfWorkScope())
            {
                Console.Out.WriteLine("Clearing Product Vendor...");
                _productRepository.Save(product); // seems to be needed to attach entity to the persistance manager
                product.ProductVendors.Clear();
                scope.Commit();
            }
        }
Going nuts here as I almost have a very nice solution between mvc, custom model binders and nhibernate. Just not seeing my deletes cascaded. Any help greatly appreciated.
Chev