Business Rule making a database call

Business Rule making a database call

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


Vlam posted on Thursday, January 26, 2012

Per-Object Rules

I need a business rule in my object where I must check against the database for duplicates, but this is determined by two properties so I need to have the object to get both values from the object when my SP is executed.
In my object I have created the class for my rule
public class ShareTypeRule : Csla.Rules.BusinessRule
        {
           
            protected override void Execute(RuleContext context)
            {
                ShareType target = (ShareType)context.Target;
                bool stypeExist = true;

  
                stypeExist = target.getSedolExist(target.Sedol, target.Company_Id);


                if (stypeExist)
                {
                    AffectedProperties.Add(SedolProperty);
                    context.AddErrorResult(SedolProperty, "Share Type already exist for selected company");
                }

            }
        }

In my server side I created a function (getSedolExist)(This function makes the database call) on my object that returns the Boolean value.
I also added a trigger to my user control on the LostFocus event it calls a method in my viewmodel,   which then calls the Checkrules() method.
Problem is that when I build it needs the function getSedolExist in my client side code and when the Checkrules()

RockfordLhotka replied on Thursday, January 26, 2012

You need to use a command object in your rule, not a direct server method call.

Within your business layer the ONLY code that can interact with server-side methods, assemblies, or features is the code in DataPortal_XYZ methods.

ABSOLUTELY NO OTHER CODE CAN USE SERVER-SIDE FEATURES.

The ProjectTracker app implements an Exists command as an example of what you need to do. And I specifically discuss this in the Using CSLA 4 ebook series.

JonnyBee replied on Thursday, January 26, 2012

Hi,

You can also look at the Samples\Net\cs\RuleTutorial sample - and specifically the LookupRole and AsyncLookupRule.

You must use a CommandObject (or ReadOnlyObject) to do the database lookup.

 

Vlam replied on Monday, January 30, 2012

thx for the info.

I have added the code to use a commandbase object in my rule.

public class ShareTypeRule : Csla.Rules.BusinessRule
        {           
            protected override void Execute(RuleContext context)
            {
                ShareType target = (ShareType)context.Target;

                if (!string.IsNullOrEmpty(target.Sedol))
                {
                    var cmd = new ShareTypeExistCommand(target.Sedol, target.Company_Id);
                    DataPortal.BeginExecute<ShareTypeExistCommand>(cmd, (o, e) =>
                    {
                        if (e.Object != null)
                        {
                            if (e.Error != null)
                                throw e.Error;
                            else
                                if (e.Object.ShareTypeExists == true)
                                {
                                    AffectedProperties.Add(SedolProperty);
                                    context.AddErrorResult(SedolProperty, "Share Type already exist for selected company");
                                    target.PropertyHasChanged(SedolProperty);
                                }
                        }
                    });
                }
            }
        }

The way I have called the Checkrules was to add a trigger action to my lost focus event on the textbox of my usercontrol and added the following code to the method called by the trigger action in my viewModel

if (Model != null)
     Model.CheckRules();

This in turn calls the CheckRules() method created in my client side code.

public void CheckRules()
        {
            BusinessRules.CheckRules();
            OnPropertyChanged("Sedol");
        }

The problem now lies with the asynch call to the DB to check if the code entered already exists. The OnPropertyChanged on my client side code gets excecuted before the call to the database is completed and therefore the errorResult does not get reported back to the used.

JonnyBee replied on Monday, January 30, 2012

  1. You must NEVER change or utpdate AffectedProperties in the Execute method. AffectedProperties must be set in the constructor of your rule. One instance of your rule is registered for ALL instances of the business object /and property so you should view this instance as a Singelton.
  2. You do NOT need to call PropertyHasChanged - THIS MAY TRIGGER A RECURSIVE CALL AND NEW  RUN OF RULES. The business class/rule engine will call OnPropertyChanged for properties in AffectedProperties list when rule is completed or async rule calls context.Complete().

Property rules is automatically triggered when a property is set in the UI. You should not need to call CheckRules in the view model for each edit of fields.

I highly recommend the Using Csla 4 ebooks from Rocky. !!!

 

Vlam replied on Tuesday, January 31, 2012

Thx...I see chapter 2 creating Business objects using CSLA 4 explains the rule system in detail and I managed to get it working.

Copyright (c) Marimer LLC