Collection loads during Fetch operation set IsDirty flag to true

Collection loads during Fetch operation set IsDirty flag to true

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


dkehring posted on Thursday, July 31, 2008

I'm using CSLA.NET 3.5.1

When performing a fetch on a root object with children, the IsDirty flag is being set when the collection class is loaded via LoadProperty. This forces me to have to call MarkOld at the end of the DataPortal_Fetch method although MarkOld is being called in Server.SimpleDataPortal. First of all, when the collection is first accessed and the collection does not exist, it is created via SetProperty in the collection property:

private static PropertyInfo<ProjectResources> ResourcesProperty = RegisterProperty<ProjectResources>(typeof(Project), new PropertyInfo<ProjectResources>("Resources"));

public ProjectResources Resources

{

get

{

if (!(FieldManager.FieldExists(ResourcesProperty)))

{

SetProperty<ProjectResources>(ResourcesProperty, ProjectResources.NewProjectResources());

}

return GetProperty<ProjectResources>(ResourcesProperty);

}

}

The SetProperty call causes the IsDirty flag to be set to true. This is okay, if MarkOld is called _after_ all child objects are loaded. However, the data portal (SimpleDataPortal in this example), calls MarkOld _before_ the call to DataPortal_Fetch:

try

{

// create an instance of the business object.

obj = new LateBoundObject(objectType);

target = obj.Instance as IDataPortalTarget;

if (target != null)

{

target.DataPortal_OnDataPortalInvoke(eventArgs);

target.MarkOld();

}

else

{

obj.CallMethodIfImplemented("DataPortal_OnDataPortalInvoke", eventArgs);

obj.CallMethodIfImplemented("MarkOld");

}

// tell the business object to fetch its data

if (criteria is int)

obj.CallMethod("DataPortal_Fetch");

else

obj.CallMethod("DataPortal_Fetch", criteria);

I would expect the call to MarkOld be made _after_ DataPortal_Fetch. Am I missing something or is this a bug? I also noticed the same is true for DataPortal_Create.

Regards,

Dave

ajj3085 replied on Thursday, July 31, 2008

I think you want to use LoadProperty, not SetProperty in your getter.

JoeFallon1 replied on Thursday, July 31, 2008

Actually the call to Mark Old used to be after the DP _Fetch. But I hated that behavior because in the original CSLA newsgroup it was discussed on how to handle fetching a BO that is not in the Database. Half the group recommended an exception and the other half recommended branching to DP_Create and returning a New empty BO instead. I went that route and the call to MarkOld after DP_Fetch made a mess of it. So Rocky kindly moved it to before the Fetch so that if you branched to Create it would not break things. Now I do not have to comment it out of the framework anymore.

Anyway - that is the background.

But the solution is as Andy describes - use LoadProperty not SetProperty in DP_Fetch.

Joe

 

ajj3085 replied on Thursday, July 31, 2008

I think the change was made because some rules change based on whether or not the object IsNew, not so that it would facilitate branching to a create.  Since ValidationRules.CheckRules must be called manually if you want it done in a fetch, and MarkOld wouldn't be called until after the rules were run, rules didn't correctly break or pass because IsNew was wrong.

JoeFallon1 replied on Thursday, July 31, 2008

Andy's point is also correct. Rocky ran into that issue after I pointed out my problem and the weight of both caused him to make the change.

Joe

 

RockfordLhotka replied on Thursday, July 31, 2008

Yes, BLAME JOE!!! ;)

dkehring replied on Friday, August 01, 2008

To all,

Thanks for the responses. However, I am using LoadProperty in my DataPortal_Fetch method. Unless I'm missing something in the responses or didn't explain things well I think everyone else is missing something. When I call LoadProperty on the collection class:

LoadProperty<Operatories>(OperatoriesProperty, Operatories.GetOperatories(dto));

... the call to Operatories enters the getter for Operatories. The Operatories property is lazy-intialized and so it creates a new Operatories collection and calls SetProperty, thus causing the IsDirty flag to be set:

   get
   {
      if (!(FieldManager.FieldExists(OperatoriesProperty)))
      {
         SetProperty<Operatories>(OperatoriesProperty, Operatories.NewOperatories());
      }
     return GetProperty<Operatories>(OperatoriesProperty);
   }

This syntax is per the ProjectTracker project. I know how to solve this. Call LoadProperty here instead of SetProperty. But, since this is part of the sample code, I thought this might be an issue. Plus, I wonder about what the implications will be by changing this from SetProperty to LoadProperty.

Anyone? ..... Bueller? ..... Bueller?

 

ajj3085 replied on Friday, August 01, 2008

Yes... the suggestion was to use LoadProperty in the property getter, and that won't cause your root BO to become dirty.

So it should read this:
   get
   {
      if (!(FieldManager.FieldExists(OperatoriesProperty)))
      {
         LoadProperty<Operatories>(OperatoriesProperty, Operatories.NewOperatories());
      }
     return GetProperty<Operatories>(OperatoriesProperty);
   }


Also, if you're calling LoadProperty in your DP_F, then you're NOT lazy loading the Operatories property... you're loading it at fetch time, and so you don't need the if block in your getter at all.

RockfordLhotka replied on Friday, August 01, 2008

The ProjectTracker code is wrong – there’s an item in my to-do list to fix it, but I haven’t had time.

 

I probably should find time – this is (I think) the third thread where I’ve had to confess to this mistake :)

 

Rocky

 

From: dkehring [mailto:cslanet@lhotka.net]
Sent: Friday, August 01, 2008 12:03 PM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] Collection loads during Fetch operation set IsDirty flag to true

 

To all,

Thanks for the responses. However, I am using LoadProperty in my DataPortal_Fetch method. Unless I'm missing something in the responses or didn't explain things well I think everyone else is missing something. When I call LoadProperty on the collection class:

LoadProperty<Operatories>(OperatoriesProperty, Operatories.GetOperatories(dto));

... the call to Operatories enters the getter for Operatories. The Operatories property is lazy-intialized and so it creates a new Operatories collection and calls SetProperty, thus causing the IsDirty flag to be set:

   get
   {
      if (!(FieldManager.FieldExists(OperatoriesProperty)))
      {
         SetProperty<Operatories>(OperatoriesProperty, Operatories.NewOperatories());
      }
     return GetProperty<Operatories>(OperatoriesProperty);
   }

This syntax is per the ProjectTracker project. I know how to solve this. Call LoadProperty here instead of SetProperty. But, since this is part of the sample code, I thought this might be an issue. Plus, I wonder about what the implications will be by changing this from SetProperty to LoadProperty.

Anyone? ..... Bueller? ..... Bueller?

 



stefan replied on Saturday, August 02, 2008

Hi,

apart from the ProjectTracker code being wrong,
what you, in addition, have wrong in your code, is that
you named your property 'Operatories' the same as your class,
thus triggering the getter each time you want to call the factory method
Operatories.NewOperatories...
So you are registering your managed property on the first call,
but what you are always getting back is a new reference
to a newly created object, which the fieldmanager is unaware of!

Edit:
Thinking over it again: Your code should result in an infinite loop,
calling LoadProperty over and over again, and would never get to
the factory call.


Stefan


ajj3085 replied on Monday, August 04, 2008

No, the compiler is smart enough to figure out when the type is being referenced vs. the property.

Copyright (c) Marimer LLC