Child_DeleteSelf() not called from parent

Child_DeleteSelf() not called from parent

Old forum URL:

sguolla posted on Tuesday, August 20, 2013

I have a parent object that inherits from BusinessBase and a child object that inherits from BusinessBase.  The child is an object contained within the parent.  The child object is a regular business object.  It is NOT a list.  All my child data portal methods (e.g. Child_Create(), Child_Insert(), Child_Fetch(), Child_Update()) get called as expected with the exception of Child_DeleteSelf().  My child methods get called correctly when I invoke FieldManager.UpdateChildren(this);  I have the correct signature in the methods.

I've seen similar posts on-line from other people and there doesn't seem to be an answer.  I don't understand why the parent cannot invoke a delete on a child in the same way it invokes for insert, fetch, update, etc.  This seems like a natural thing to do and it's all part of one transaction.

If a parent cannot invoke this, I have no idea why Child_DeleteSelf() even exists.

I've been using CSLA for several years now.  I guess I've never encountered this situation.

If anyone has any insight or experience with this, I'd be very grateful.

JonnyBee replied on Tuesday, August 20, 2013

There 2 important requirements for CSLA DataPortal to call into Child_DeleteSelf

  1. Object must has IsDeleted == true (ie: you must have called MarkDeleted on the child)
  2. Object must have IsNew == false (ie: if IsNew is true the object does not exist in the database and no reason to call Child_DeleteSelf)

so please make sure that the child object has both IsDeleted == true and IsNew == false and the Child_DeleteSelf method will be called. 

sguolla replied on Tuesday, August 20, 2013

Thanks for getting back to me Jonny Bee.  You're the man!  So, IsNew is false which is good and I see that IsDeleted is false.  For MarkDeleted() to work, it has to be called from within the child object.  The parent object does not have access to it.

So my solution is to create a public method in the child object which has one line of code: MarkDeleted() and have the parent call this public method.  Then, when I place FieldManager.UpdateChildren() in DataPortal_DeleteSelf(), the method Child_DeleteSelf() is called.

That's great, but I don't like having to add this extra step.  I don't have to do it for INSERT and UPDATE so why do I have to do it for DELETE.  This seems like flawed design.  It's as if the default behavior of CSLA is to NOT automatically delete children when a parent is deleted.  Wouldn't the opposite be the desired behavior all the time?  Especially considering at the database level the children have foreign keys that are primary keys of the parent.

Am I missing something?

JonnyBee replied on Tuesday, August 20, 2013

No, if the parent is deleted the parent should be responsible for deleting all its children as well.

You would only be correct if the assumption is that ALL child objects must be loaded.

In a relational database (and business object use case) you would happily load only a few of the related table(s) or even use Lazy-loading to only load data when required and still want to delete the parent record.

So you would be better off to use cascading delete in the database or call a stored procedure that handles the delete - rather than assuming that the object structure must load and mark all the child data as deleted.

sguolla replied on Tuesday, August 20, 2013

I see where you're coming from.  One of the design goals for our project is to have really straightforward stored procedures and have ALL logic in C# code and in CSLA.  As such, we don't want complicated cascading deletes at the database level.  In the same way a child inserts or updates data for his/her own database table, we want that same child to perform its own deletion.

In short, we want the object structure to manage everything.  Your original suggestion is a fine workaround.  It really struck me as odd for the case of deletion.

I also didn't consider the lazy-load situation.

Thanks again.

Copyright (c) Marimer LLC