Business Rules / Calculated Fields Dependency

Business Rules / Calculated Fields Dependency

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


AbbasMalik posted on Monday, September 30, 2013

Hi experts,

I have BaseQty and Factor fields in the database. On user front end, I display Quantity field which is calculated as BaseQty * Factor. I know I can write a business rule CalcQuantity which will be fired on BaseQty and Factor field.

But the problem is Quantity field is also updatable by the user on the front end. User can enter a value in the Quantity field and in this case BaseQty is to be calculated as Quantity/Factor. If I write a CalcBaseQty rule, it will create a kind of cyclic dependency with CalcQuantity rule. BaseQty and Quantity are interdependent.

How to implement this scenario?

 

Curelom replied on Monday, September 30, 2013

One approach you could do is have a nullable field in your datastore for the user entered value.  Your property would then display the calculation if the nullable field is null or 0 or whatever value you choose.  The property would display the user entered value if it was populated.  The "setting" of the property would populate the nullable back field.  So the majority of the logic would be within the property instead of a rule.

Curelom replied on Monday, September 30, 2013

One other thing, you may want to add another property such as IsBaseQtyPopulated to determine if the value is calced or user populated. You could use that property for any visual feeback you want to give to the user.

JonnyBee replied on Monday, September 30, 2013

Hi,

So in terms of business rules you need rules that only run when the user modifies a field.

You can achieve this by setting these properties in your rules constructor:

      IsAsync = false;
      CanRunAsAffectedProperty = false;   // only run when this property is changed 
      CanRunInCheckRules = false;          // when true will also run in CheckRules
      CanRunOnServer = false;             // when true will also run on logical serverside (Data Access)

When all 3 CanXYZ properties is false - the rule will only run when the user (or code) calls the property setter and change the value.

 

 

AbbasMalik replied on Tuesday, October 01, 2013

Hi JonnyBee

Thanks for the information on business rules. I am using csla.net 4.5.30.

I wrote a CalcBaseQty business rule with setting all 3 CanXYZ to false. But the rule was not firing. I had to set CanRunAsAffectedProperty to true   and rule started firing when user changed value through user interface.

But the problem is that CalcQty rule fires before CalcBaseQty. I need to fire CalcBaseQty rule first so that user entered value is translated back to BaseQty field.  I tried setting priority of CalcBaseQty to -1, but it made no difference.

Finally, removed the CalcBaseQty rule, and in the Qty setter, I directly update the BaseQty. It works as expected but I don't know if it is ok to do this.

Thanks

Abbas

JonnyBee replied on Tuesday, October 01, 2013

When all CanXYZ is false the rule will only fire when PrimaryProperty of the Rule is changed. 

IE: PrimaryProperty must be the property set by user. 

So:

AbbasMalik replied on Tuesday, October 01, 2013

JonnyBee

When all CanXYZ is false the rule will only fire when PrimaryProperty of the Rule is changed. 

IE: PrimaryProperty must be the property set by user. 

So:

 

 Ok. If I pass BaseQty as PrimaryProperty to CalcQty() then how will I update the Qty field from Execute method. Because I think

context.AddOutValue(qty / factor) 

 

 is used to update only PrimaryProperty. Is there a way to update a field other than primary property?

Thanks  

JonnyBee replied on Tuesday, October 01, 2013

There's overload to context.AddOutValue that accepts an IPropertyInfo as first parameter for the property to update. 

Note: The property to update must be added to AffectedProperties in the Rule constructor.

Example rule:

  public class CalcBaseQty : PropertyRule
  {
    private readonly PropertyInfo<decimal> _qtyProperty;
    private readonly PropertyInfo<decimal> _baseQtyProperty;
    private readonly PropertyInfo<int> _factorProperty;
 
    public CalcBaseQty(PropertyInfo<decimal> qtyProperty, PropertyInfo<decimal> baseQtyProperty, PropertyInfo<int> factorProperty)
      : base(qtyProperty)
    {
      _qtyProperty = qtyProperty;
      _baseQtyProperty = baseQtyProperty;
      _factorProperty = factorProperty;
 
      InputProperties = new List<IPropertyInfo>() { qtyProperty, factorProperty };
      AffectedProperties.Add(baseQtyProperty);
 
      CanRunOnServer = false;
      CanRunAsAffectedProperty = false;
      CanRunInCheckRules = false;
    }
 
    protected override void Execute(RuleContext context)
    {
      var qty = context.GetInputValue(_qtyProperty);
      var factor = context.GetInputValue(_factorProperty);
 
      context.AddOutValue(_baseQtyProperty, qty / factor);
    }
  }

JonnyBee replied on Tuesday, October 01, 2013

I will also highly recommend the Using CSLA 4 ebooks available in the CSLA Store.

Especially the :

 

AbbasMalik replied on Tuesday, October 01, 2013

Thanks Jonny for providing prompt response with complete example. I will also read the recommended books.

Regards

Abbas

Copyright (c) Marimer LLC