Thursday, February 28, 2008
« CslaDataProvider: The final step | Main | CSLA .NET 3.5 code savings: GetIdValue »

One of my primary goals with CSLA .NET 3.5 was to reduce the amount of code necessary for common business object tasks - like declaring a property or implementing a parent-child relationship. I've mentioned what I'm doing on the forum and elsewhere, but I thought a summary blog post would be nice. I'm motivated, because I spent some time earlier today upgrading some business object code based on CSLA 3.0.3 to 3.5 and it was just fun to watch the class shrink :)

Basic Properties

Prior to 3.5 my properties were comparatively large:

public string Name
{
  [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
  get
  {
    CanReadProperty(true);
    return _name;
  }
  [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
  set
  {
    CanWriteProperty(true);
    if (value == null) value = string.Empty;
    if (_name != value)
    {
      _name = value;
      PropertyHasChanged();
    }
  }
}

Now the same property looks like this:

private static PropertyInfo<string> NameProperty =
  RegisterProperty<string>(typeof(CertificationEdit), new PropertyInfo<string>("Name"));
public string Name
{
  get { return GetProperty<string>(NameProperty); }
  set { SetProperty<string>(NameProperty, value); }
}

I think that is so cool!! Though there's a performance hit to this much reduction, because you'll notice there's no backing field. In this case CSLA is actually managing the property value in the background and that incurs a little overhead. You can compromise if you'd like:

private static PropertyInfo<string> NameProperty =
  RegisterProperty<string>(typeof(CertificationEdit), new PropertyInfo<string>("Name"));
private string _name = NameProperty.DefaultValue;
public string Name
{
  get { return GetProperty<string>(NameProperty, _name); }
  set { SetProperty<string>(NameProperty, ref _name, value); }
}

Nearly the same code, but now with a private backing field so CSLA doesn't have to manage the value. Slightly faster, with slightly more code.

Either way, all the authorization, validation and data binding support works just like it did with the old syntax, so all the core features of CSLA .NET just keep working in your favor - with less code to write and maintain.

Child Object Properties

This new syntax works for child objects as well. A child used to look like this:

private ChildType _child;
public ChildType Child
{
  [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
  get
  {
    CanReadProperty(true);
    return _child;
  }
}

The new syntax requires that CSLA manage the property value for child objects:

private static PropertyInfo<ChildType> ChildProperty =
  RegisterProperty<ChildType>(typeof(CertificationEdit), new PropertyInfo<string>("Child"));
public ChildType Child
{
  get { return GetProperty<ChildType>(ChildProperty); }
}

The really cool part isn't the minor code savings in the property - it is the code savings elsewhere. Prior to 3.5 a parent object had to override IsDirty and IsValid, and had to hook and re-hook child data binding events. None of that code is required now! Because CSLA is managing the child object value, it can entirely handle IsDirty, IsValid and all data binding events automatically. This saves a lot of code in every parent object.

Even better, this eliminates code that a lot of people forgot to write, or forgot to update when adding a new child. In short, this eliminates a primary source of bugs/pain when dealing with parent-child object relationships.

There are other areas in 3.5 where I've reduced the code required, and I'll blog about others (like reducing data access code, eliminating many criteria classes and more) in future posts.


Thursday, February 28, 2008 10:48:06 PM (Central Standard Time, UTC-06:00)
From one person who forgot many a time to update the IsDirty/IsValid overrides when adding children, I say thank you for my decrease of future (unnecessary)bugs in advance.
David Maynard
Friday, February 29, 2008 8:06:35 AM (Central Standard Time, UTC-06:00)
Since you're already using factories for creating all of your business objects I bet you could easily get away with a little code injection. When you create the object for the first time you could create a dynamic parent object perhaps and add all of those cross cutting concerns for them automatically.

Well actually I wonder if that would work over remoting? hmmmm.
Tuesday, March 04, 2008 4:31:22 AM (Central Standard Time, UTC-06:00)
(I already submitted this comment but it didn't appear.. hmm...)

A lot of the time I find I need to modify the private backing field of a different property to the one currently being se, before PropertyHasChanged() is called. Something like this:

set{
if (_field1 != value)
{
_field1 = value;
_field2 = _field1 / 2;
PropertyHasChanged();
}
}

Does this new mechanism allow for this? I am presuming SetProperty<T> performs calls PropertyHasChanged.

I
Tuesday, March 04, 2008 9:20:21 AM (Central Standard Time, UTC-06:00)
Yes, SetProperty() calls both CanWriteProperty() and PropertyHasChanged().

However, the existing syntax continues to work just fine - you don't have to use the new model. Well, other than that you <i>must</i> switch to passing in the property name to CanReadProperty/CanWriteProperty/PropertyHasChanged.

Alternately, you can create a rule method to do what you are describing, thus keeping the property code standard (better for code-gen or snippets) and keeping the business rule (in this case calculating a value) as a rule.

private static bool SetField2<T>(T target, RuleArgs e) where T: BusinessClass
{
target._field2 = _target._field1 / 2;
return true;
}
Tuesday, March 04, 2008 4:46:32 PM (Central Standard Time, UTC-06:00)
(I posted a forum item here about this here: http://forums.lhotka.net/forums/thread/21812.aspx)

I was hoping to use something like the new model rather than use the existing (and still supported one). I considered putting this into the rules but for some reason it didn't smell right. I mean, they're called ValidationRules, I thought for the validation of property values, only.
Saturday, March 08, 2008 9:39:35 PM (Central Standard Time, UTC-06:00)
You may of answered this somewhere else, but:

We typically never return 'null' to the presentation layer (the code below gets rid of a lot of if(Value == null || Value.Trim() == string.Empty) checks, because we know it will never be null and the value will never have excess spaces...we also don't want the object to go dirty just because of case change in most case because we work with an AS400 which (for our purposes) only wants real changes, not case changes, because anytime we write a change new records are created and we get a lot flak for creating a new record that is the exact same value as the previous (because they can't see the case change).

get
{
//returns string.Empty if null
return StringUtilities.GetDefaultValue(_prop);
}
set
{
if(TrimIfSet(value).ToUpper() != _prop.ToUpper())
{
//Never allow white space in
_prop = TrimIfSet(value);
PropertyHasChanged();
}
}

Will I still be able to do this with the new syntax?
Brian Johnston
Sunday, March 09, 2008 5:28:24 AM (Central Standard Time, UTC-06:00)
Brian, the SetProperty method de-nulls string values on the way in, because null values break data binding. It doesn't do Trim or anything like that however, and it does use a case-sensitive check for equality when determining if the value has changed.

In your case you probably can't use the new SetProperty helper and would need to continue to use your current code structure (though you'll have to explicitly pass the property name to PropertyHasChanged now, because the overload you show in your code is obsolete).
Sunday, March 09, 2008 5:33:17 AM (Central Standard Time, UTC-06:00)
Damian, the name "ValidationRules" is really no longer all that accurate. Thanks to the support for generics in rule methods it is quite realistic (and advisable) to use rule methods to implement most business logic using the technique I posted.

Unfortunately, changing "ValidationRules" to "BusinessRules" or something like that would be a mess - a breaking change for every single CSLA-derived class in the world. Ouch! So even though the rules concept is broader than validation, I don't feel comfortable changing the name and breaking everyone's code...
Monday, April 28, 2008 6:40:13 AM (Central Standard Time, UTC-06:00)
in:

private static PropertyInfo<string> NameProperty =
RegisterProperty<string>(typeof(CertificationEdit), new PropertyInfo<string>("Name"));
public string Name
{
get { return GetProperty<string>(NameProperty); }
set { SetProperty<string>(NameProperty, value); }
}

What is "CertificationEdit"??

Frazer
Monday, April 28, 2008 6:59:50 AM (Central Standard Time, UTC-06:00)
The type "CertificationEdit" is the class within which the property is being declared. This works the same as a DependencyProperty in WPF or WF.
Comments are closed.