Adding Business Rules to the Data-Centric Object


Before you begin trapping rules, you need to import the Errors namespace. Add the following line in the header of the RegionDC code module:

 Imports NorthwindTraders.NorthwindShared.Errors 

Next, add the following variable declaration in the header of the RegionDC class:

 Private mobjBusErr As BusinessErrors 

Now, in the Save routine, add the following line of code below the Dim statements but above the sRegion with statement:

 mobjBusErr = New BusinessErrors() 

Now you are ready to begin handling the rule violations.

The only property you are checking for business rule violations on is the RegionDescription property because the RegionID property is read-only. To review, this is what your RegionDescription property currently looks like:

 Public Property RegionDescription() As String      Get           Return mstrRegionDescription      End Get      Set(ByVal Value As String)           mstrRegionDescription = Value      End Set End Property 

Because you are going to be trapping for the violations when the property is set, you are only concerned with the Set block. All of your business rule checks will occur in a Try..Catch block, so start by altering the Set block of code so that it looks like the following:

 Try      mstrRegionDescription = Value Catch exc As Exception      mobjBusErr.Add("Region Description", exc.Message) End Try 

The Catch block of your routines will be used to catch any business violations you throw. When the error is thrown, you set the property name and pass in the exception message and then continue on your way.

To perform your validations, let's add the following If..Then..Else statement right below the Try statement:

 If Value.Length = 0 Then      Throw New ZeroLengthException Else      If Value.Length > 50 Then           Throw New MaximumLengthException(50)      End If End If 

Now you have all the rules in place to validate, and you can trap the violations.

Note

Examining the code, you will notice it is only going to catch one violation per rule. In other words, when an exception is thrown, you do not go back and check any of the additional rules. This is easier to handle than trying to catch multiple errors per property. As you will see when you get to the user interface, it is easier for you and less confusing for the user if you only handle one error per property.

Retrieving Business Rules

Next you will add another method that is extremely useful in large business applications—the GetBusinessRules method. This method has one purpose: to return a set of all of the rules implemented by the class. There are two good reasons for doing this. The first is that it makes sense in many applications to be able to inform the user of all of the rules of an object when they are performing data entry. The second reason is to allow other applications that may use your objects to be able to retrieve a list of your objects rules. Although these rules should be published in application documentation, it is often advantageous to allow the object to be self-describing.

Note

This is not truly a self-describing object, although it looks like one right now. It is not self-describing because first you have to duplicate your business rules, and second, the object does not really examine itself. Chapter 10, "Using Reflection," shows you how to create a truly self-aware class in terms of business rules.

Add the following code to implement this method into the RegionDC class:

 Public Function GetBusinessRules() As BusinessErrors      Dim objBusRules As New BusinessErrors()      With objBusRules           .Add("Region Description", "The value cannot be null.")           .Add("Region Description", "The value cannot be more than 50 " _           & "characters in length.")      End With      Return objBusRules End Function 

This method creates a BusinessErrors object and adds all of the errors that can occur in your object to it. It then returns this collection of errors to the calling code. To allow this method to be accessible from the client code, you need to add another method to your IRegion interface. To do this, alter the IRegion interface in the Interfaces code module so that it reads as follows:

 Public Interface IRegion      Function LoadProxy() As DataSet      Function LoadRecord(ByVal intID As Integer) As Structures.structRegion      Function Save(ByVal sRegion As structRegion, _      ByRef intID As Integer) As BusinessErrors      Sub Delete(ByVal intID As Integer)      Function GetBusinessRules() As BusinessErrors End Interface 

You made two changes to this interface. The first change is to the Save routine, which is now a function that returns a BusinessErrors object. The second change is the addition of the GetBusinessRules function. Once you incorporate these changes, you will have a couple of syntax errors until you import the following namespace into the Interfaces code module:

 Imports NorthwindTraders.NorthwindShared.Errors 

Note

This change is why you returned the ID of the saved record as a ByRef value.

Return to the RegionDC class and alter the GetBusinessRules function so that it implements the interface function you just created. To do this, change the signature line of the method to read as follows:

 Public Function GetBusinessRules() As BusinessErrors _ Implements IRegion.GetBusinessRules 

Returning Errors during the Save

Before you can report errors to the user interface, you need to alter your Save routine (at this point you have an error caused by your altering of the IRegion Interface)—first so that it matches your interface signature and second so that it actually returns your collection of errors. Alter the Save method signature to read as follows:

 Public Function Save(ByVal sRegion As structRegion, _     ByRef intID As Integer) As BusinessErrors Implements IRegion.Save 

The way this code is currently structured, the following events will take place when you try to save your object:

  1. The BusinessErrors object is instantiated.

  2. The public RegionDescription property will have its value set.

  3. Any error will cause an error to be added to the BusinessError object.

The last thing you need to do is to respond to any business rules that were violated during the setting of the properties. To do this, add the following code to check to see if there were any errors (add this code after the With sRegion block in place of the code that is already there):

 If mobjBusErr.Count = 0 Then      cn.Open()      With cmd      .Connection = cn           .CommandType = CommandType.StoredProcedure           .CommandText = "usp_region_save"           .Parameters.Add("@id", mintRegionID)           .Parameters.Add("@region", mstrRegionDescription)           .Parameters.Add("@new_id", SqlDbType.Int).Direction = _           ParameterDirection.Output           .ExecuteNonQuery()           intID = Convert.ToInt32(.Parameters.Item("@id").Value)      End With      cmd = Nothing      cn.Close() End If Return mobjBusErr 

The only change here is the addition of the If..Then statement and the addition of the Return line. The If statement checks to see if any errors were thrown. If you did, then you skip the block of code that calls the database; otherwise you save the data to the database. Finally, you return the collection of errors. On the user interface side, you will check the count of errors to see if you need to do anything with the object that is returned to you. Now you are ready to move on to the user-centric objects.




Building Client/Server Applications with VB. NET(c) An Example-Driven Approach
Building Client/Server Applications Under VB .NET: An Example-Driven Approach
ISBN: 1590590708
EAN: 2147483647
Year: 2005
Pages: 148
Authors: Jeff Levinson

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net