Need original property value in DataPortal_xyz and Child_xyz methods

Need original property value in DataPortal_xyz and Child_xyz methods

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


j055 posted on Wednesday, October 07, 2009

Hi

I'm using 3.7.1.

Is there a way without too much work to get original values from managed properties?

I want to check equality of old and new values and then log to the database.

This isn't really for auditing purposes. There's a specify business use in the object that requires this.

A simple example or any better suggestions would be great.

Thanks
Andrew

RockfordLhotka replied on Wednesday, October 07, 2009

Jason Bock recently blogged about how to do this. It requires creating your own subclass for PropertyInfo<T> and FieldData<T>, which allows you to manage field values as you choose.

rsbaker0 replied on Wednesday, October 07, 2009

Here is my implementation of this (simpler and more space efficient than implementing your own IFieldData class IMHO):

http://forums.lhotka.net/forums/post/24445.aspx

Basically, you override OnPropertyChanging() and, if you haven't previously cached the original value, you save the current property value -- before the pending property change is applied -- in a dictionary as the original value.

We use this for at least 3 purposes: field-level concurrency in database updates, auditing, and the ability to determine if a property is "really" dirty in business rules (e.g. it handles the case when the user changes something and then changes it back to the original value).

The nice thing about it is that there is no impact at all unless a property is changed -- the cache is lazy instantiated -- and then the space requirement is roughly proportional to the number of changed properties. You don't have to double the size of your object (unless, of course, you change every property :)

j055 replied on Thursday, October 08, 2009

I'm struggling to make much sense of any of this. I suppose what I'm trying to achieve is a method like ReadOriginalProperty or GetOriginalProperty for the business developer to use without needing to know what's going on underneath.

Jason Bock seems to be doing much more than sub classing PropertyInfo and FieldData and I'm not sure if that's really necessary for my needs. As long as the business developer (which is me) can
get the original value with a simple method call by using a sub classed businessbase they can make a decision about what to do with it.

I know I could easily create fields for original values in the business class but that seems a little crude to say the least, however it may be the quickest to implement unless you can convince me otherwise :) !!

rsbaker0 replied on Thursday, October 08, 2009

j055:
I'm struggling to make much sense of any of this. I suppose what I'm trying to achieve is a method like ReadOriginalProperty or GetOriginalProperty for the business developer to use without needing to know what's going on underneath.


That's exactly what the minimal plumbing in my solution is for. You implement an intermediate base class derived from BusinessBase<> to house the original value cache, and then derive objects that require original property caching from that class. If you use CSLA managed properties, then the plumbing works for free. (Otherwise, you have to call OnPropertyChanging in your setters, but that's a code generation issue)

In my case, I implement two methods along the lines of what you are asking for:

IsDirtyProperty(propertyname) - just returns true if the property is actually different from the original value

IsDirtyProperty(propertyname, out originalValue) - returns true if the property has changed and also gives you the original value as an output parametr.

j055 replied on Thursday, October 08, 2009

Had another look at your code and starting to understand a bit better. For my use I override OnPropertyChanging:

protected override void OnPropertyChanging(string propertyName)
{
base.OnPropertyChanging(propertyName);

if (!IsNew && !String.IsNullOrEmpty(propertyName))
{
object oldValue = GetPropertyValue(this, propertyName);
CacheValue(propertyName, oldValue);
}
}

and created a ReadOriginalProperty method which gets the cached value:

protected object ReadOriginalProperty(IPropertyInfo propertyInfo)
{
if (((propertyInfo.RelationshipType & RelationshipTypes.LazyLoad) != 0) &&
!FieldManager.FieldExists(propertyInfo))
throw new InvalidOperationException("Property get not allowed");

IFieldData info = FieldManager.GetFieldData(propertyInfo);
if (info != null)
{
if (_valueCache != null && _valueCache.Contains(info.Name))
{
object cachedValue = _valueCache[info.Name];
if (!Equals(cachedValue, info.Value))
return cachedValue;
return info.Value;
}
}
return null;
}

Seems to work with initial testing. At least I can see how things are supposed to fit together a bit better now.

Thanks for your help
Andrew

Copyright (c) Marimer LLC