Business Validation Rules Question

Business Validation Rules Question

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


cdkisa posted on Wednesday, August 12, 2009

I want to add some business rules that require a database check.

I want to the rule to check the database only for the following conditions: IsNew = true or property "Name" has changed.

Is there a way to check which properties have changed through BB or is this something I need to implement myself using the PropertyChanged event?

If I have to implement myself, then which array type would be best suited for this? (i.e. array of string: string[] or list of string: List)

Thanks,
Pat


tetranz replied on Wednesday, August 12, 2009

cdkisa:
I want to add some business rules that require a database check. I want to the rule to check the database only for the following conditions: IsNew = true or property "Name" has changed. Is there a way to check which properties have changed through BB or is this something I need to implement myself using the PropertyChanged event? If I have to implement myself, then which array type would be best suited for this? (i.e. array of string: string[] or list of string: List) Thanks, Pat


If you attach the rule to the correct property using ValidationRules.AddRule() then it will run whenever that property changes. It may run at other times too because you typically call ValidationRules.CheckRules() after fetching or creating the object. The way I've handled the occasional case where I needed the rule to know if it was being called because the property was changing and not another reason, is to use a flag in the property setter.

        private bool _nameIsChanging;
        private static PropertyInfo<string> NameProperty = RegisterProperty<string>(c => c.Name);
        public string Name
        {
            get { return GetProperty(NameProperty); }
            set
            {
                _nameIsChanging = true;
                SetProperty(NameProperty, value);
                _nameIsChanging = false;
            }
        }

I can read _nameIsChanging in the static rule method as if it is a property. I previously used the PropertyChanged event for this sort of thing but after following a few posts by Rocky's last month I now prefer to do it in a rule. I do this even if it's not a real rule, i.e, it always returns true, I just want something to happen if the property changes.

cdkisa replied on Wednesday, August 12, 2009

Thanks for replying.

So what you are saying is that putting a list of string in a base class that all other classes inherit from is a no-no? Could you explain why?

I want to do this (as an instance property):

MyBase > BusinessBase
---------------------
Protected _changedProperties As New List(Of String)

Protected Overrides Sub OnPropertyChanged(ByVal propertyName As String)
MyBase.OnPropertyChanged(propertyName)
_changedProperties.Add(propertyName)
End Sub


MyClass > MyBase
--------------------
Private Shared Function CheckNameIsUnique(ByVal target As MyObject, ByVal e As Csla.Validation.RuleArgs) As Boolean

If target._changedProperties.Contains("Name") Then

If MyObject.NameExists(target.Name) Then

e.Description = "The name entered already exists. Names must be unique."
e.Severity = Csla.Validation.RuleSeverity.Error
Return False

End If

End If

Return True

End Function

It seems that this is more OO than introducing new properties and variables. But, I'm no expert.

Thanks,
Pat

tetranz replied on Wednesday, August 12, 2009

I guess something like that would work but it looks more complicated and error prone to me. I guess you're effectively trying to implement IsDirty at the property level which I know others have talked about here.

You probably just gave the bare bones there but your _changedProperties.Add really needs to do an "add if not already exists" otherwise you'll get duplicates. Well ... I guess dups in the List don't really affect the result of target._changedProperties.Contains("Name") but ... I would try to keep it clean. You'll probably need to clear the list after saving.

But more to the point ... Your rule will need to be attached to a property with ValidationRules.AddRule. Presumably this will be the Name property so that means it will run when the property changes. Now you're dependent on what order things happen in. PropertyChanged and then the rule or the other way? I guess you can test and find out or look at the CSLA source but it's best if you don't need to know or care.

I would put the dup test in the rule and let CSLA do it's thing. To me, that flag I suggested around the set is clean with nothing much to go wrong. It's true and then false so there's no real side effects, initialization to worry about etc. I suspect that you don't really need to know if the property has changed. Your db query will probably be, "is there a row with the same name but different id.". It doesn't really matter if that runs on fetch as well as property changed. Running it on fetch would alert the user to a problem with the data. Maybe someone edited a name outside of your app. Well ... maybe you have a unique index on Name so that's not possible. You should have a unique index because, this rule doesn't guarantee uniqueness if it's a multi-user app because someone else could save that name between the time the rule is checked and you saving.

When I do this sort of thing, I usually setup a simple cache so that I'm not hitting the db unnecessarily with the same query. The cache could be just a variable or two to remember the result of "is this name unique".

cdkisa replied on Wednesday, August 12, 2009

Is there any way to implement validation just before saving without overriding the Save method?

JoeFallon1 replied on Thursday, August 13, 2009

In my web UI I usually write code like:

If myBO.IsValid Then

  myBO=myBO.Save

End If

Then you can override IsValid if you want and call CheckRules before calling MyBase.IsValid. Or you can just call specific rules in the override.

Joe

 

Copyright (c) Marimer LLC