views:

61

answers:

2

I would like to delete the ICollection PriceBreaks from Product.

I'm using the following method. However they dont seem to delete. What am i missing. When i step thru. i notice that "product.PriceBreaks.Clear();" doesn't actually clear the items. Do i need to flush or something?

public void RemovePriceBreak(int productId) {

using (ISession session = EStore.Domain.Helpers.NHibernateHelper.OpenSession())
using (ITransaction transaction = session.BeginTransaction())
{
    var product = session.Get<Product>(productId); 
   // i can see 20 PriceBreak records, tho nh prof saids PriceBreak table hasn't been hit
    product.PriceBreaks.Clear();
    session.SaveOrUpdate(product);
    transaction.Commit(); // PriceBreak table is hit here with select statement, no delete?
}

}

Here are my hbm files

  <class name="Product" table="Products">
    <id name="Id" type="Int32" column="Id" unsaved-value="0">
      <generator class="identity"/>
    </id>
    <property name="CompanyId" column="CompanyId" type="Int32" not-null="true" />
    <property name="Name" column="Name"/>
    <set name="PriceBreaks" table="PriceBreaks" generic="true" cascade="all-delete-orphan" inverse="true" >
      <key column="ProductId" />
      <one-to-many class="EStore.Domain.Model.PriceBreak, EStore.Domain" />
    </set>    
  </class>



<class name="PriceBreak" table="PriceBreaks">
    <id name="Id" type="Int32" column="Id" unsaved-value="0">
      <generator class="identity"/>
    </id> 
    <many-to-one name="Product" column="ProductId"  not-null="true"  class="EStore.Domain.Model.Product, EStore.Domain" />    
  </class>

My Entities

 public class Product
    {

        public virtual int Id { get; set; }
    public virtual ICollection<PriceBreak> PriceBreaks { get; set; }
        public virtual void AddPriceBreak(PriceBreak priceBreak)
        {
            priceBreak.Product = this;
            PriceBreaks.Add(priceBreak);
        }
    }




 public class PriceBreak
    {
        public virtual int Id { get; set; }
        public virtual Product Product { get; set; }  
    }

Here is the sql from nhprof

// SELECT product0_.Id as Id0_0_ FROM Products product0_ WHERE product0_.Id = 23 /* @p0 */

and then

SELECT pricebreak0_.ProductId as ProductId1_, pricebreak0_.Id as Id1_, pricebreak0_.Id as Id1_0_, pricebreak0_.ProductId as ProductId1_0_, FROM PriceBreaks pricebreak0_ WHERE pricebreak0_.ProductId = 23 /* @p0 */

there is no update or select

+1  A: 

Product probably needs to be associated with that session. It looks like you are trying to save a detached object. Which means there is no session to track that call to clear the PriceBreaks. Change it to this...

public void RemovePriceBreak(int productId)
{

    using (ISession session = EStore.Domain.Helpers.NHibernateHelper.OpenSession())
    using (ITransaction transaction = session.BeginTransaction())
    {
        var product = session.Get<Product>(productId);
        product.PriceBreaks.Clear();
        session.SaveOrUpdate(product);
        transaction.Commit();
    }
}

or move the session and transaction management further up. Which would basically eliminate the need for this method.

dotjoe
hmm, gave this a go. Still no joy. I've updated the question above with the new method.
frosty
Can you show us your entities and how you manage relationship between these two. It looks like you are exposing you collection as a list. You might want to re-think that. What would for example product.PriceBreaks[0].product = someOtherProduct mean?
epitka
epitka, i've added the entites. What alternative to list do you suggest.
frosty
Are you sure PriceBreaks exist for the product? Is any SQL being executed? Maybe try changing key property to `<key column="ProductId" not-null="true" />` or it might be mismatch between `set` and `ICollection`. I generally use `bag` and `IList` or `set` and `Iesi.Collections.HashedSet`
dotjoe
thanks dotjoe really helpful! so looking in nhprof i see some interesting results ( see comments in RemovePriceBreak method above. I've changed ICollection to ISet. There are definately results in the product.PriceBreak so i didn't change the key.
frosty
Yes, it shouldn't issue the deletes until the commit, so that is normal. NH will keep track of all the needed db operations and wait for a flush, commit, or possibly another query to trigger the execution. When you say "PriceBreak table is hit", what is the generated SQL?
dotjoe
@frosty also, like @mathieu said, you don't need the cascade="all" on the PriceBreak side. This might be causing unknown behavior because both sides want to cascade operations to each other.
dotjoe
i've included the sql, can you clarify, are my cascade settings correct above
frosty
hmm, I think when you `Clear()` the collection, that will result in the collection being fetched (via the 2nd select). It needs to be fetched so the individual deletes can be issued. I think there are ways to make Clear do a batch delete. Either way, something else is wrong. How do you initialize the ISet? In the Product constructor?
dotjoe
+1  A: 

Have you tried deleting the cascade="all" on the PriceBreak side ?

Have you tried using session.Save() instead of SaveOrUpdate() ?

mathieu
1) I've removed cascade="all" from priceBreak in product.hmb. I edit the above to how i have it now. 2) do you mean session.Save
frosty