Can you make a database call in a Validation method?

Can you make a database call in a Validation method?

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


ormico posted on Monday, April 23, 2007

I've tried to look this up already but I can't find any reference to something similiar.

I have a BusinesBase<> object that contains a date. There are ranges that the date can and cannot fall within depending on data already in the database.

I would like to be able to write a custom validation rule that would log into the database, pass some data (an id and our date) and have it determin if out date is within an allowed range.

This seems straight forward enough, but my questions are

1. Do the validation rules run on the data portal? I don't want the data access call to happen in the UI

I think the answer is yes, so that is fine.

2. Can I keep my validation within the same transaction as my upate?

I'm using SQL Server transactions. If I instantiate a data access object inside my validation method and close it, then when dataportal_update() gets called I'll have to create another data access object and another connection and another transaction.

Shouldn't the validation happen in the same transaction?

-Zack

RockfordLhotka replied on Monday, April 23, 2007

You can make data portal calls in a rule method, but you shouldn't directly do data access, no. The rule methods can run on either client or server - you don't know which - and so you must use the data portal to ensure you actually interact with the app server properly.

That said, there's no reason at all why a rule method can't talk to the database (again, via the data portal). It is critical to remember that rule methods can run frequently however - and so performance can be an issue. This is why I added the rule priority concepts in version 2.1 - you can see how to use them in the CSLA .NET Version 2.1 Handbook.

The idea though, is to run any "cheap" rule methods first, and only run the "expensive" rule methods (like ones that hit the database) if the cheap methods pass. If a cheap method fails, then you can skip the expensive rule method, because the property is already known to be in error.

In terms of keeping the validation in the same transaction as the update - the answer is no. Validation occurs as properties are being set, which is entirely at a different point in the object lifecycle from when Save() is called.

However, you could choose to structure your objects differently - not following the structure used in the books or sample app. In this case you would not call PropertyHasChanged(), nor would you call ValidationRules.CheckRules() except at the top of the DataPortal_Insert(), DataPortal_Update() and DataPortal_DeleteSelf() methods.

Obviously you'd lose any sense of user interactivity - the result would be an object that only supports block mode interaction (like mainframe stuff) - but then the rule methods would be running only as part of a call to Save() and they would run within the same transactional context.

dg78 replied on Sunday, May 20, 2007

Hi,

 

I am in the same situation than Ormico : I want to access database in a Validation Rule.

 

Suppose a user enters an invoice. When he left the Customer control, it is necessary to find if the customer exists. Of course, I can initialize a hashtable or CustomerList and test if the customer exists inside this collection. But if there are many customers (several thousands), I think it will be better to check if he exists inside the database. Is it true ?

 

 I want to test a customer either by his number (unique id) or by his name or the beginning of his name (unique or several chooses). I don’t want to use a comboBox to choose the customer but a textbox following by a button (…) (in fact an user control) as Matt and Mario write in

http://forums.lhotka.net/forums/1/7380/ShowThread.aspx

 

So I think the best is to check a custom validation rule due to the binding between controls (here the textbox) and the property.

 

How do you do in a such situation which happens always ?

 

So, I understand that I need to use the DataPortal, as Rocky said.

How ? by calling a commandbase from the business class (invoice) and using a DataPortal_execute ? Where to put this code ?

 

Have you a little sample to show how to use that ?

 

Then, instead to put this code inside each BO, is it possible to make it generic ?

Where to put this generic code ?

 

Many questions for good advices as always in this forum.

 

Thanks in advance

 

Dominique

RockfordLhotka replied on Sunday, May 20, 2007

In the book I show how to build an Exists command (look at the Project class – and specifically at the nested Command class).

 

If you implement such a command, you can just call it in your rule method:

 

Private Shared Function MustNotExist(Of Customer)(…) As Boolean

 

  If Customer.Exists(target._id) Then

    e.Description = “Customer exists”

    Return False

 

  Else

    Return True

  End If

 

End Sub

 

I recommend using rule priorities to make this rule run after your cheaper rules (like field required, etc), and set it up so it only runs if those rules pass. The 2.1 Handbook explains how to do that.

 

Rocky


No virus found in this outgoing message.
Checked by AVG Free Edition.
Version: 7.5.467 / Virus Database: 269.7.5/812 - Release Date: 5/19/2007 1:52 PM

dg78 replied on Monday, May 21, 2007

Hi Rocky,

 

Thanks for your answer.

 

It is true, everything is explained (even well explained Big Smile [:D] ) in your book.

The most difficult thing is sometimes to find where are the explanations we need.

 

You wrote : “This might be something as simple as doing a quick database lookup”. It is just the case in my question.

 

I read also that it is possible to have a public class instead a private nested class inside a business object. I think it is the road to take for a generic database lookup class.

 

Does anybody do that ?

 

Cheers

 

Dominique

RockfordLhotka replied on Monday, May 21, 2007

dg78:

 

I read also that it is possible to have a public class instead a private nested class inside a business object. I think it is the road to take for a generic database lookup class.

 

Does anybody do that ?

 

This is certainly possible, but isn't something I recommend. When you do your object design, every object should have one responsibility that clearly fills a role within a use case. If you have a generic database lookup object that can do many lookups, it obviously fills many responsibilities and that's bad.

However, what you could maybe do is create a non-public lookup object. Your public object model would then have objects that fill specific responsibilities, but delegate the actual work to this non-public object. This is a form of normalization of behavior.

But even that only makes sense if you can create your centralized lookup object in a way where it has no conditionals, Select/switch statements or other code to make the object act differently depending on how, or from where, it was called.

Copyright (c) Marimer LLC