FieldManager.IsDirty Not Responding to MarkClean

FieldManager.IsDirty Not Responding to MarkClean

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


BigPines2 posted on Wednesday, September 09, 2009

After moving to CSLA 3.5.3, I am starting to use the FieldManager to let CSLA manage my child objects. However, one serious annoyance is that the FieldManager is always dirty. After calling MarkClean on the parent object the FieldManager is still dirty. Even calling MarkClean on the FieldManager itself will not work - it still says it is dirty. How can this be? Unfortunately, my UI implementation depends on knowing if an object is dirty or not so this is throwing everything off for me.

I could work around this by this by using IsSelfDirty of the parent object but I found that IsSavable is also affected by the problem and there is no IsSelfSavable.

Any ideas on how to resolve this are welcome.

Mike

RockfordLhotka replied on Wednesday, September 09, 2009

There's something going on in your code. We have unit tests and sample apps that work fine - calling MarkClean() on the object causes the expected behavior.

Is this occurring when you call Save()? Are you properly using the result of Save()?

_customer = _customer.Save();

In older code people would often just call Save() like a void method, not a function, and that is a common cause for confusion - in 3.5+ you really need to call Save() correctly - as a function.

BigPines2 replied on Wednesday, September 09, 2009

This is even happening before I ever call save. In fact, as soon as I fetch the object from the DB, if I call MarkClean the parent object reports not dirty but the FieldManager still reports dirty. It is always dirty no matter what. Even after saving the object, the new object that comes back from the save has a FieldManager that is dirty. BTW, I am saving the correct way as in your example above. I always set the object instance to the result of the object coming back from the save.

If I don't use the FieldManager, I don't have this problem on my objects. I am setting up the child object property like this:

Private Shared CredentialEventsProperty As PropertyInfo(Of EntityCredentialParent) = RegisterProperty(New PropertyInfo(Of EntityCredentialParent)("CredentialEvents"))

Public ReadOnly Property CredentialEvents() As EntityCredentialParent
     Get
          If Not FieldManager.FieldExists(CredentialEventsProperty) Then
               LoadProperty(Of EntityCredentialParent)(CredentialEventsProperty, EntityCredentialParent.NewObject(Me))
          End If

          Return GetProperty(CredentialEventsProperty)
     End Get
End Property


I then load the child from the database like this:

LoadProperty(Of EntityCredentialParent)(CredentialEventsProperty, EntityCredentialParent.GetObject(dr, cn, Me))

From the moment I load the object as outlined above, the FiledManager becomes dirty and cannot be cleaned by calling MarkClean. I have dug into this a bit and found that the child object is basically not getting "managed" correctly. When I call the parent object's MarkClean, my understanding is that should trigger the FieldManager to call MarkClean on the child objects right? This does not appear to be happening. I just found if I call MarkClean directly on the child object it works correctly but if I call MarkClean on the FieldManager or the Parent BO, it does not affect the child BO.

Any ideas? :(

Mike

RockfordLhotka replied on Wednesday, September 09, 2009

There’s some mismatch then, because the BusinessBase IsDirty implementation delegates to the field manager. So if the field manager is dirty, the object will report dirty too.

BigPines2 replied on Wednesday, September 09, 2009

Right. That is exactly what I am seeing. The FieldManager is dirty and the object is also therefore dirty. The FieldManager is dirty because the child it is managing is dirty but it should not be.

The problem is, the child cannot be marked clean through the normal process. When you mark an object as clean, it should trigger the FieldManager to mark all children as clean but the children are never getting marked clean. Likewise, if you call FieldManager.MarkClean directly, the children do not get marked clean. The ONLY way to get the children marked clean is to call MarkClean directly on the child. This makes the FieldManager return clean and therefore the object is clean.

I would just manually call Child.MarkClean but the method is protected. Ahhhhhhhh!!!

I'll keep digging. I guess I will just have to step through every line of code after MarkClean is called on the parent to figure out why it is not working.

Mike

RockfordLhotka replied on Wednesday, September 09, 2009

Ahh, that’s the misunderstanding then.

 

When you mark an object as clean, that’ll mark its fields as clean, but not its child objects.

 

To preserve encapsulation every object manages its own state. A parent object can’t arbitrarily say “child you are clean”, because that breaks encapsulation. MarkClean() has never cascaded down through to child objects.

BigPines2 replied on Wednesday, September 09, 2009

RockfordLhotka:
Ahh, that’s the misunderstanding then.

 When you mark an object as clean, that’ll mark its fields as clean, but not its child objects.


 To preserve encapsulation every object manages its own state. A parent object can’t arbitrarily say “child you are clean”, because that breaks encapsulation. MarkClean() has never cascaded down through to child objects.

Well that makes sense. I'll go look at why my child is dirty. I guess I just never had to care before.


Mike

BigPines2 replied on Wednesday, September 09, 2009

Yeah you were right Rocky. Sorry, I am getting a little rusty on the fundamentals. Embarrassed [:$]

Mike

ajj3085 replied on Wednesday, September 09, 2009

Are you using the DataPortal.Childxyz methods? If so, it should be handling the Markxyz calls for you... unless your code is doing something to make the object dirty again. Also, be sure you're using BypassPropertyChecks when loading your child object, because I think the MarkClean occurs BEFORE your Child_Fetch.

BigPines2 replied on Wednesday, September 09, 2009

OK, here is what I am seeing:

1) ParentObject.MarkClean called by my code
2) ParentObject.FieldManager.MarkClean gets successfully called which looks like this:

Friend Sub MarkClean()
     For Each item In _fieldData
          If item IsNot Nothing AndAlso item.IsDirty Then
               item.MarkClean()
          End If
     Next item
End Sub


3) item.MarkClean gets successfully called on the only child in my test. This call goes to FieldData.MarkClean which looks like this:

Public Sub MarkClean() Implements IFieldData.MarkClean

     _isDirty = False

End Sub


4) _isDirty is already False before this call but it gets set to False again.

That is it. That is all I can see happening. How is the Child getting cleaned here?

Mike

Copyright (c) Marimer LLC