9

I'm developing a sample application so that I can learn the ins and outs of NHibernate. I am struggling with a delete issue. I wish to be able to delete a child record by removing it from its parent’s collection and then saving the parent. I have setup a bidirectional one-to-many relationship and inserting/updating is working great.

Here are my mappings

Basket:

<bag name="Items" inverse="true" cascade="all"> <key column="BasketId" /> <one-to-many class="BasketItem" /> </bag>

BasketItem:

<many-to-one not-null="true" name="Basket" column="BasketId" />

I would like to call basket.RemoveBasketItem(BasketItem item) then Session.SaveUpdate(basket) so that the basket item will be deleted. Is this possible?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129

4 Answers4

18

Change cascade="all" into cascade="all-delete-orphan".

cascade="all" will only delete your child records if the parent gets deleted.

mookid8000
  • 18,258
  • 2
  • 39
  • 63
  • When my RemoveBasketItem looks like this: this.basketItems.Remove(itemToRemove); I get this error: A collection with cascade="all-delete-orphan" was no longer referenced by the owning entity instance: Basket.Items –  Jun 12 '09 at 10:56
  • 7
    Sounds like you somehow overwrote the `IList` reference holding your basket items. You can only put your own implementation of `IList` in there when the list reference is null - if you load a basket from the DB, NH will put its own `PersistentBag` as the `IList` implementation - and you must leave this reference alone for cascade to work properly. – mookid8000 Jun 12 '09 at 11:01
  • 1
    I got it to work! Thanks for your help :-) I was having problems because my basket.Items property was newing up a read-only List. Now I am simply returning the private instance of my items. –  Jun 12 '09 at 11:05
  • This change means my basket items could be modified by client code :-( basket.Items.Add(). I will need to look into this a bit more. –  Jun 12 '09 at 11:08
  • 3
    I usually make AddItem/RemoveItem methods, and then have my property return only an IEnumerable - this way, the consuming code must new up their own List or whatever they want to do, and they never accidentally modify the persistent list. – mookid8000 Jun 12 '09 at 11:17
  • This answer has nothing with the question. – mynkow Apr 01 '11 at 10:57
2

I have same scenario and ive used cascade="all-delete-orphan" in bagList but when i delete a single child item in a collection it deletes the parent object as well.

0

I was having a problem where my children elements where returning an Ordered enumerable.

private readonly IList<Child> children;

public virtual IEnumerable<Child> Children { get { return children.OrderBy(c => c.Position); } }

public virtual void DeleteChild(Child item)
{
    children.Remove(item);
}

I moved the ordering to my mapping and returned the children as it is for the IEnumerable. This worked for me!

Adauto
  • 569
  • 3
  • 5
0

I was having the same problem as initforthemoney due to returning a new list as ReadOnly from my collection getter. I found I could continue to use the ReadOnly list by changing the property access strategy of the collection from nosetter to field.

John Galambos
  • 2,801
  • 2
  • 26
  • 24