Can not directly mark a child object for deletion - use its parent collection?

Can not directly mark a child object for deletion - use its parent collection?

Old forum URL: forums.lhotka.net/forums/t/618.aspx


shahram posted on Friday, July 14, 2006

Hi!

What this means:

"Can not directly mark a child object for deletion - use its parent collection"

This is code in my object:

#region Data Access - Delete

protected virtual void DeleteChildren(SqlConnection cn)

{

_invoicePolicyCollection.Delete(cn, this); //step 2

}

protected override void ExecuteDelete(SqlConnection cn)

{

DeleteChildren(cn); // Step 1

using (SqlCommand cm = cn.CreateCommand())

{

}//using

}

#endregion //Data Access - Delete

and this is delete method in invoicePolicyCollection:

#region Data Access

 

internal void Delete<P>(SqlConnection cn, P parent) where P : ContractBase<P>

{

// loop through each child object

foreach (InvoicePolicy child in this)

{

child.Delete();//step 3, Here I get Exception

}

this.Update(cn, parent);

}

#endregion //Data Access

Regards

ajj3085 replied on Friday, July 14, 2006

You're calling BusinessBase.Delete directly on the child object, which is not allowed.

You need to remove it from the parent collection, by calling BusinessListBase.Remove( child );

HTH
Andy

shahram replied on Friday, July 14, 2006

Well, when I use

foreach (Contract child in this)

{child.Delete();}

it says no delete on child use parent collection...

and when I use this

foreach (Contract child in this)

{this.Remove(child);}

there is another exception that collection has been modified...

so the question is what exactly you must do to delete child objects?

RRorije replied on Friday, July 14, 2006

Well I think this is not a CSLA feature, but standard .NET.

The same thing happens when you do this:
<code>

Dim _arraylist As New Arraylist()
_arraylist.Add(1)
_arraylist.Add(2)
_arraylist.Add(3)
_arraylist.Add(4)

For Each i As Integer In _arrayList
    If _arraylist(i) % 2 = 0 Then
       _arraylist.Remove(i)
    End If
Next

</code>

A workaround is to iterate through the collection using the index, because the collection is not addressed then. Be sure to iterate through the collection reversely, because else indices will be altered.
this should work then

For index As Integer = childs.count -1 To 0 Step -1
    Me.removeAt(index)
Next


Sorry for replying in VB.Net instead of C#, but I am more customed to vb.net. Therefore typos are less likely to occur  ;)

matt tag replied on Friday, July 14, 2006

if you want to delete ALL child objects, use  the Clear method.

Yoursecond error is happening b/c your trying to modify a collection while iterating through it with "for each", which is not allowed. You could do this

for i as integer = me.count - 1 to 0 step -1
   child = me.item(i)
   me.remove(child)
next

or this

do while me.count > 0
  child = me.item(0)
  me.remove(child
loop

or just call the Clear method


matt tag

shahram replied on Friday, July 14, 2006

The Clear() method was my first choice but it seems that  clear() only removes items from the collection and do not delete them from database. Is it correct?

ajj3085 replied on Friday, July 14, 2006

That is correct; but using Remove to delete the children won't immediately delete them either.

You need to Save the parent collection to actually commit the changes (in this case, deletions) to the database.  Normally this isn't a problem.

Is there a reason they MUST be deleted from the database immediately?  I'm not sure how to do immediate deletion of child objects (I typically don't do deletions at all).

Andy

shahram replied on Friday, July 14, 2006

What is the difference between Clear() and ClearItems() methods?

shahram replied on Friday, July 14, 2006

The only thing I want to do is when deleting som object from database it's child become deleted from DB too!

Belive me this is not good when even simplest things get so unobvious and timecomsuming to do.

It was my first time and will be last time to use this CSLA. Maybe it a very good approch theoretically but not practical. It is not good for BUSINESS!

 

RockfordLhotka replied on Friday, July 14, 2006

I wouldn't recommend doing your deletes at the object level.

If you delete a parent object, it is typically a lot more efficient to have it delete its data and its child data, rather than having each child delete itself from the database. Why would you make that many database calls?

Other people prefer to use the database itself to do this. You can set up the database so when you delete the parent row, any child rows are automatically deleted by the database itself.

In short, if you mark a parent object as deleted, there should be no reason to go through all the work of marking its child objects as deleted  And if this is what you want to do, then you should be able to just call Clear() on the collection, because that will automatically mark all the child objects for deletion and move them to the deletedList.

I'm afraid that if calling Clear() on a collection is considered unobvious or complex, then .NET itself will probably continue to be very frustrating for you Sad [:(]

shahram replied on Friday, July 14, 2006

Thank you for your post, now I understand it better.

But still I have the question that when I use Clear() in a collection like this this.Clear();

it seems the childs just removes from the collection but then when I check in database they are not deleted.

Regards

ajj3085 replied on Friday, July 14, 2006

You must call Save on the root object; either the collection (if that's not a child collection) or the containing BusinessBase object.

Take a look at the sample that comes with Csla, specifically the portions on deleting projects or resources.

Jacco replied on Saturday, May 30, 2009

I can kinda see where he is coming from.  if you have a foreign key in your database, you then would have to delete the children before the parent, otherwise you get a violation. But to do this by trying to force the children to delete themselves is silly.

As Rocky says, why not let the database deal with that?  Write a stored procedure, and call it from the parent.  Then you can use the yourChildCollection.Clear() and you are done, one db connection

tetranz replied on Friday, July 14, 2006

As the exception suggests, you can't modify a collection while using a enumerator to loop around it which is what foreach does. The enumerator would get horribly confused if it let you do that.

I looks like you want to delete all child items. If that's correct then this.Clear() will probably do what you want.

In a more general case, you just need to call Remove(child) while not looping around the same collection. I think the usual way is to first build a list of "items for deletion". That can be done while looping around the list because all you are doing is building another list. Then loop around that list calling Remove() on the first list.

Ross

ajj3085 replied on Friday, July 14, 2006

You cannot use foreach when you are modifying the contents of the collection.

Change your code to something like this:

while( this.Count > 0 ) {
     this.RemoveAt( 0 );
}

That will properly clear all the children; as an alternate:

this.Clear();

HTH
Andy

Copyright (c) Marimer LLC