Conditional business rules or short-circuit for the case of validation success?

Conditional business rules or short-circuit for the case of validation success?

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


fryderyk posted on Tuesday, August 30, 2011


Suppose we have a business object declared as following pseudo code:

class ParentModel
{
    CslaChildProperty<ChildModel> ChildA;
    CslaChildProperty<ChildModel> ChildB;,
    ModeEnum    Mode;
}

the ParentModel is BusinessBase<T> and ChildModel is BusinessListBase<T>  derived CSLA object, and ChildModel has its own business rules defined. At some point during runtime, the ChildB.IsValid == false due to some broken business rules in ChildB. In fact, it's the property inside the child of some item in ChildB which has the broken rule and its invalid state propagated up to ChildB. (confused?)the relationship is shown below:

ChildBIdea.SomeObject.SomeObjectWithBrokenProperty

And the ChildA.IsValid == true. Now, according to the business requirement, at the current value of Mode, the validity of ParentModal is only relevant to the validity of ChildA, that is, the ParentModal.IsValid should be true. And we don't care and don't want the invalid state of ChildB to interfere with ParentA's validation process.


How can I achieve this ?

P.S.

It seems that if the ChildA/B is a plain BusinessBase<T>, the business rules defined inside will not be called automatically. however , if its a BusinessListBase<T>, then after the SomeObject described above is added into the list, the CheckRules() is immediately performed on the added object and the list object's IsValid becomes false.

  I have read about the priority system of the new business rule engine, seems that it can only achieve the short-circuiting of failure case but not the success case. If the success short-circuiting exists, then maybe we can write this :
at ParentModel's AddBusinessRule:
new Lambda(ChildAProperty,
    c=>{
        if (c.Target.Mode != ModeA)
            SuppressRules(ChildAProperty);
    }
    // ChildB's rule is similar.
    // ...

Edit: See my reply to JonnyBee, It'll be fantastic if we could do that.

kingmoon replied on Tuesday, August 30, 2011

Good Idea! But I wish a best answer....

JonnyBee replied on Tuesday, August 30, 2011

Hi,

How about simply overriding the ParentModel.IsValid property to test for Mode and return if the corresponding ChildA and/or ChildB IsValid?

A lot less messy -  ParentModel.Mode shouldn't need be a parameter to the business rules of the child types.

So something like this:

    public override bool IsValid {
        get 
        {
            if (Mode == ModeEnum.ModeA) return ChildA.IsValid && IsSelfValid;
            else if (Mode == ModeEnum.ModeB) return ChildB.IsValid && IsSelfValid;
            else return base.IsValid;  // the default implementation
        }
    }

fryderyk replied on Tuesday, August 30, 2011

Indifferent That's definitely an answer, which is what I missed.

As to the less messy route, yes,  we can split the Parent to two separate models and doing the switching part inside ViewModel. However, since the ParentModel is one primitive business concept, we thought it's not appropriate to split it up again.(Actually, the same scenario applies to 3 different places inside the ParentModelTongue Tied)

I thought it's a big step forward if this framework could support overriding the rule of ChildA property to this.Mode == ModeA && ChildA.IsValid. I think this feature doesn't break the OO design principle, it just adds some additional rules to ChildModel in ParentModel's context, which is different from simply disabling some rules of ChildModel itself.

I really hope you and your team can take it into consideration on the next csla release.

Many thanks.

 

JonnyBee replied on Wednesday, August 31, 2011

Hi,

I'm may not catch all you want to do but you shouldn't expect to attach rules to a child object in parent objects context. That would break encapsulation.
An objects business rules is attached to that object's TYPE - in order to preserve encapsulation.
Csla 4 only supports per-type rules and they must be attached to that object type and can not be changed (you may however switch RuleSet).

Csla supports overriding the rules by overriding the IsValid/IsSelfValid/Is... on the parent business object.

If you were to do this with rules you would also have to recheck the rules in all the child list objects when Mode is changed on the parent (and rules can be expensive to execute and/or do async database/webservice calls) or walk the tree (could be a number of levels), clear BrokenrulesCollection and call OnUnknownPropertyChanged on each editable child to update the UI (and ErrorProviders/PropertyStatuses).

My remark about messy is about having the validation of the child objects depend on a property value of a parent. I do not like to have the validation rules in a child depend on a certain parent type or even how the child object (given that ChildA and ChildB are the same type) would know what ModeA and ModeB would mean unless they also were aware of which list instance they belonged to.

Copyright (c) Marimer LLC