Implementing business rules using customized DataSet objects

Introduction

Information systems contain and enforce rules about the business they support. A rule is constraint which describes the way how objects are to behave. Field-level validations are checks that pertain to the property values of the underlying business entities. For example, a field must be 50 characters or less in length or some fields are required while other fields are optional as well as some fields must be greater than a specific value.

Sometimes these rules are expressed at the relational model and the underlying database schema. To limit fields sizes you can use the data types and the desired length for example varchar(50), use the CHECK statement on table columns when you create the tables to check valid values, express whether a field is required or optional by declaring table columns to allow NULLS as well as use referential integrity rules to establish valid relationships and its cardinality between entities.

Unfortunately there are a lot of rules which are not readily represented using the relational models, or at least not in a manner amenable to direct translation into a relational database for example when the business rules depend on values of attributes in different entity instances or cardinality constraints such as there can be no more than four order items in a sales order. As well as sometimes we don't have rights to change the relational schema (due to restrictions of the database administrator), thus the business rules must be enforced in the
Business Logic Layer of our application.

Implementing business rules using DataSet objects

Let's supposed we're going to implement some business rules associated to the product entities represented by the table Production.Product such as the ListPrice field value must be a required numeric value which is greater than or equal to zero as well as we don't have rights to change the schema of the AdventureWorks database shipped with SQL Server 2005.
The implementation strategy is create a Business Logic Layer implemented in Visual Studio .NET by a Class Library project (see Figure 1).

Figure-1.gif

Figure 1

Now add to the project a DataSet item and name it ProductionBO.xsd (see Figure 2).

Figure-2.gif

Figure 2

Now let's add the Products DataTable to the ProductionBO.xsd DataSet using the TableAdapter Configuration Wizard(see Figure 3).

Figure-3.gif

Figure 3

In order to enforce that the ListPrice column in the DataTable Product is required, the select the ListPrice column from the DataTable Product and then go to the Properties window. Set the AllowDBNull property to False (see Figure 4).

Figure-4.gif

Figure 4

Unfortunately, we can't specify that the ListPrice field is greater than or equal to zero, through the Properties window. In order to implement this rule, we need to create an event handler for the underlying DataTable's ColumnChanging event. You must add partial class that extends the generated DataTable Product, in this way, we don't have to rewrite our business logic every time the DataTable Product is re-generated by Visual Studio .NET (see Figure 5).

Figure-5.gif

Figure 5

Next create an event handler for the ColumnChanging event that ensures the proper value of the ListPrice field otherwise the ArgumentException exception is thrown (see Listing 1).

using System;
using System.Collections.Generic;
using System.Text;

namespace ProductionBusinessLogicLayerLib
{
    public partial class ProductionBO : System.Data.DataSet
    {
        public partial class ProductDataTable : System.Data.DataTable, System.Collections.IEnumerable
        {
            public override void BeginInit()
            {
                this.ColumnChanging += new System.Data.DataColumnChangeEventHandler(ProductDataTable_ColumnChanging);
            }
 
            void ProductDataTable_ColumnChanging(object sender, System.Data.DataColumnChangeEventArgs e)
            {
                if (e.Column.Equals(this.ListPriceColumn))
                {
                    if (!Convert.IsDBNull(e.ProposedValue) && (decimal)e.ProposedValue < 0)
                    {
                        throw new ArgumentException("ListPrice field must be greater than or equal to zero","ListPrice");
                    }
                }
            }
        }
    }
}

Listing 1

Conclusion

In this article, I covered one implementation strategy to implement business rules using DataSet objects. I hope you can adapt this example to your own business scenario.