1

The business layer in our application uses CSLA.NET. I've got business classes named Invoice and InvoiceItem (derived from a subclass of CSLA BusinessBase) and InvoiceItemList (derived from a subclass of CSLA BusinessBindingListBase).

Invoice class has a property for Items, declared as:

    private static readonly PropertyInfo<InvoiceItemList> ItemsProperty =
RegisterProperty<InvoiceItemList>(o => o.Items, RelationshipTypes.Child);


public InvoiceItemList Items
{
    get
    {
        return GetProperty(ItemsProperty);
    }
    private set
    {
        SetProperty(ItemsProperty, value);
    }
}

I want to implement a CSLA Business Rule that ensures that Invoice is not saved without at least one item. So, I've created a MinCount rule, derived from CSLA PropertyRule and applied it to Items property.

BusinessRules.AddRule(new MinCount(ItemsProperty, 1));

The problem is, this rule is only fired when SetProperty is called on ItemsProperty, which is called only once (in DataPortal_Create). There are no items at the time of creation so the rule correctly marks the object as invalid. However the rule isn't fired when InvoiceItem objects are Added to/Removed from Items property. As a result the Invoice object remains invalid, and is not saved.

What is the correct way to implement rules (such as Min/Max Count rule) for properties that are derived from BusinessBindingListBase (or BusinessListBase)?

M. Rashid
  • 159
  • 6

2 Answers2

1

I ended up writing the following code to trigger my Min/Max rule.

protected override void OnChildChanged(ChildChangedEventArgs e)
{
    base.OnChildChanged(e);

    // We are only interested in some change in a List property
    if (e.ListChangedArgs == null || e.ChildObject == null) return;

    // We are only interested in addition or removal from list
    if (e.ListChangedArgs.ListChangedType != ListChangedType.ItemAdded
        && e.ListChangedArgs.ListChangedType != ListChangedType.ItemDeleted)
        return;

    // Find property by type
    var t = e.ChildObject.GetType();
    var prop = FieldManager.GetRegisteredProperties().FirstOrDefault(p => p.Type == t);

    // Raise property change, which in turn calls BusinessRules.CheckRules on specified property
    foreach (prop != null)
        PropertyHasChanged(prop);
}

The above code DOES NOT handle the scenario where there are more than one List properties of same type. The code could have used a Where (in place of FirstOrDefault), to iterate through all such properties. The drawback is that the change would then be fired unnecessarily for other properties.

M. Rashid
  • 159
  • 6
  • You can filter to only run that code on specific lists by doing `if (e.ChildObject is InvoiceItemList) { // do stuff }` – Andy Aug 31 '16 at 22:40
0

This is for those that are interested in this currently. I would suggest implementing a business rule in the parent object, pass the collection in and check the count.

kcabral
  • 35
  • 1
  • 8