Child_DeleteSelf not being called

Child_DeleteSelf not being called

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


RandyH posted on Wednesday, October 29, 2008

I have code that looks similar to the following:

Public Class Parent
    Inherits BusinessBase(Of Parent)

    Private Shared MyChildListProperty As PropertyInfo(Of ChildList) = RegisterProperty(Of ChildList)(GetType(Child), New PropertyInfo(Of ChildList)("MyChildList", "The Child List"))
    Public ReadOnly Property MyChildList() As ChildList
        Get
            Return GetProperty(Of ChildList)(MyChildListProperty)
        End Get
    End Property
....
    Private Overloads Sub DataPortal_Delete(ByVal criteria As Object)
        '-- delete from db
        FieldManager.UpdateChildren(criteria)
    End Sub
....
End Class

Public Class ChildList
    Inherits BusinessListBase(Of ChildList, Child)
....
End Class

Public Class Child
    Inherits BusinessBase(Of Child)
....
    Private Sub Child_DeleteSelf(ByVal criteria As Object)
        'delete from db
    End Sub
....
End Class

When I call parent.Delete (parent is an instance) the parent object is being deleted from the db. But the children are not marked as dirty or isdeleted and so the Child_DeleteSelf is not being called. I seem to be missing something that marks the children for delete. Any help would be greatly appreciated.

JoeFallon1 replied on Wednesday, October 29, 2008

The basic concept you are missing is that you have to manage the entire delete yourself from within the Parent class.

You are incorrectly relying on CSLA to delete the child objects for you in this case.

In database terms you are looking to do a Cascade Delete.

What the ChildList does in CSLA is give you a way to delete individual rows from a child table when a user "edits" them in the UI and marks them for deletion.

If the Parent is deleted and you want all the child rows to be removed too then you have to handle it yourself.

Something like this:

Protected Overrides Sub DataPortal_DeleteSelf()
  DataPortal_Delete(
New CriteriaCode(GetType(Item), "DataPortal_DeleteSelf", mItemno))
End Sub

Protected Overrides Sub DataPortal_Delete(ByVal criteria As Object)
 
Dim strSQL As String
  Dim crit As CriteriaCode = DirectCast(criteria, CriteriaCode)
  strSQL = ItemDAO.Delete(crit.Code)

  Dim tr As IDbTransaction = Nothing
 
Try
   
tr = Me.BeginTransaction()
    
'Delete child objects before deleting the parent. 
    
DeleteChildren(tr, criteria)
   
'delete the parent
   
DAL.ExecuteNonQuery(tr, CommandType.Text, strSQL)
    PostDeleteData(tr, user)
   
Me.EndTransaction(tr)
 
Catch ex As Exception
   
Me.RollbackTransaction(tr)
   
Throw
 
End Try
End Sub

Protected Overridable Sub DeleteChildren(ByVal tr As IDbTransaction, ByVal criteria As Object)
 
Dim crit As CriteriaCode = DirectCast(criteria, CriteriaCode)
  DAL.ExecuteNonQuery(tr, CommandType.Text, ItemchildDAO.DeleteByItemno(crit.Code))
End Sub

Joe

RandyH replied on Wednesday, October 29, 2008

I now have a solution that seems to work.

In the parent class I now have this code
    Public Overrides Sub Delete()
        Me.ChildList.Clear()
        MyBase.Delete()
    End Sub

The clear marks the children for delete. Then the FieldManager.UpdateChildren call in the parent.DataPortal_Delete will then make the calls to the Child_DeleteSelf in each of the children.
Any problems with this solution?

tetranz replied on Wednesday, October 29, 2008

I think the more efficient thing to do is simply to get your stored procedure or whatever your DAL uses to delete the child records directly when it deletes the parent.

My parent_delete sproc usually does something like this:

DELETE FROM ChildTable
WHERE ParentId = @Id

DELETE FROM ParentTable
WHERE Id = @Id

eulerthegrape replied on Wednesday, October 29, 2008

I use this solution too and it works perfectly until you create a foreign key relationship between parent and child table and don't perform the deletion in the order described by tetranz...

ajj3085 replied on Wednesday, October 29, 2008

True, but that's fairly easy to find and fix when it happens.

JoeFallon1 replied on Wednesday, October 29, 2008

The drawback to your solution is that if there are 500 child rows in the collection then you will send 500 queries to the DB to remove them one at a time.

My solution and the SP offered by tetranz only send 2 queries in total.

Joe

 

ajj3085 replied on Thursday, October 30, 2008

Well, I wasn't advocating one solution over another... just pointing out the "problem" of order was a pretty trivial one because it's easy to find and easy to fix.

Of course it's not the number of queries that matter, its how many queries you send at once over the network.  If you're using L2S it will submit your changes in a single batch when you call SubmitChanges.  Many queries, but just one network hop.  Performance should be fine.

JoeFallon1 replied on Thursday, October 30, 2008

FYI the "your solution" in my comment was to RandyH - the op who originally posted and the re-posted his solution. I was not referring to Andy's comments at all.

Joe

 

ajj3085 replied on Thursday, October 30, 2008

Ahh... I thought you were replying to me from the post numbers.

eulerthegrape replied on Thursday, October 30, 2008

I was merely relating my first time "experience."  Once you've seen this "problem," yes it is a trivial fix but it was a head scratcher for me the first time.  If it saves some one some heartburn I think it's a valid "gotcha" to point out.

Copyright (c) Marimer LLC