How should I handle validation failure for uniqueness in an ObjectFactory (CSLA 4)?

How should I handle validation failure for uniqueness in an ObjectFactory (CSLA 4)?

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


Dane posted on Sunday, October 23, 2011

I have a BusinessObject called Dog.  Dog has the property Name. I create a new Dog, give it a Name and save.  The class DogFactory (which inherits from ObjectFactory) handles the push of information to my data source.  At the time of save I need to validate that there are no other dogs in my data source with the new Dog.Name and if there are I'd like to add a validation error directly to the NameProperty but I'm seeing no clear way to do this.

Thanks for any suggestions you might have.

JonnyBee replied on Sunday, October 23, 2011

If your code reaches the Save method in object factory then you should throw an exception.

You should create a business rule to check uniqueness BEFORE the Save.

IE:

  1. Create a business rule to check for uniqueness - preferrably an async rule that executes when the user edits the Name field and uses a CommandObject to check uniqueness in the DB..
  2. if you wish to run all rules "manually" call <bo>.BusinessRules.CheckRules() after the object is unbound from UI. 
  3. Save is only allowed when <bo> has no broken rules of severity=Error.

StefanCop replied on Sunday, October 23, 2011

As Jonny said, you have to decide, whether you want the error before the save operation or within it. 

In the first case (before) a BusinessRule as Jonny explained is the right choice.

If you consider duplicate values as a rare case, you might treat it like an exception. For example you declare a check clause right in the database, catch that exception and re-throw a more verbose one; or you check right before the insert/update and throw an exception.
On the client tier you get the exception while Save()-ing in a DataPortalException's BusinessException and have to handle it.

In our project, we needed to run such rules just before the Save, but not for every change of a property (every keystroke in our case). The solution isn't pretty, but works:
- we have added a Flag Property to every editable BO (actuelly an explicit interface implementation),
- have overriden the Save() like this: ... Save() { IsSaving = true; try { BusinessRules.CheckRules(); return base.Save(); } finally { IsSaving = false; } }
- every such rule has in its Execute an "if (!obj.IsSaving) return true;" condition.

You may want to have a look at this post, where I discussed the problem with Jonny: Business Rule .

HTH

ajj3085 replied on Sunday, October 23, 2011

Actually you'll probably need both, before and after.  When the user enters a value, check for uniqueness then via a rule.  Just before your insert operation in DataPortal_Insert, you'll have to run the rule again.  Otherwise you end up with a system that says you entered something unique, but someone else saves the same thing before you do.

JonnyBee replied on Monday, October 24, 2011

I'd prefer to have the "transactional uniqueness" handled by the database rather than a rule in code.

So my preferences would be:

 

tiago replied on Monday, October 24, 2011

Hi Dane,

CslaGenFrok has a library of rules that includes a NoDuplicates rule. This is a generic rule as you don't have to specify the parent type (aka the collection type).  The rule is a regular Csla rule and checks that on the parent collection, there is no other item with the same name/description.

Note that you might want some degree of duplication like the brands and models issue:

As the rule checks only the parent collection (the brand) and not all models, it handles this use case nicely.

You can find the Rule sample 1.0.2 DLL and documentation in the form of CHM at http://cslagenfork.codeplex.com/releases/view/73538 

Source code is available.

Copyright (c) Marimer LLC