Introduction
Currently, the DataTable
has minimal support for custom validation in data columns when creating extended data columns. This article shows how to add regular expression validation capabilities to the data columns by extending the ADO.NET DataColumn
. The DataColumn
can be validated whenever it undergoes a change, against a validator.
Motivation
The ADO.NET DataColumn
supports unique values by the implementation of a unique constraint, but how do we add custom validation which may be governed by business rules (such as positive integers or some regular expression validation)? One option is to use a custom constraint derived from the abstract Constraint
class, but this is an arduous task.
It hence follows that we need some extensions to the DataColumn
. The extended data column does exactly this and allows the user to supply his own validation logic using a validator class, which returns whether the validation occurred successfully or not.
The backbone of the solution is the DataColumnEx
class, which takes in a DataTable
, name and a validator as parameters to the constructor.
IValidator Interface
All validators which participate in the validation of the data in the datacolumnEx
need to implement the IValidator
interface, which has a single method IsValid
.
namespace DataColumnEx
{
public interface IValidator
{
bool IsValid(object value);
}
}
The validator takes in an object by performing rules specified and returns a boolean indicating if the validation is successful. As is obvious, the validation can range from something as simple as restricting values to positive integers to something more complex that encapsulates a business rule.
The encapsulation of any business logic in a separate class decouples the business logic governing the validation from the extended data column.
DataColumnEx class
The DataColumnEx
takes in a class of type IValidator
in its Validator
property. The DataColumnEx
subscribes to the ColumnChanged
event of the table to which it belongs (as specified in the constructor) and invokes the validator there. The DataColumnEx
class also has a property RejectChangesOnError
indicating if changes made to the row should not be effective.
using System;
using System.Data;
namespace DataColumnEx
{
public class DataColumnEx : DataColumn
{
private IValidator m_validator;
private DataTable m_table;
private bool m_rejectChangesOnError;
private ResourceMgr m_resMgr =
new ResourceMgr("DataColumnEx.ErrorStrings");
public DataColumnEx(DataTable table, string name, IValidator validator)
{
ColumnName = name;
m_validator = validator;
m_table = table;
DataType = typeof(string);
if (m_table != null)
{
m_table.ColumnChanged +=
new DataColumnChangeEventHandler(OnColumnChanged);
}
}
public DataColumnEx(DataTable table, string name,
IValidator validator, Type columnType)
{
ColumnName = name;
m_validator = validator;
m_table = table;
DataType = columnType;
if (m_table != null)
{
m_table.ColumnChanged +=
new DataColumnChangeEventHandler(OnColumnChanged);
}
}
public IValidator Validator
{
get { return m_validator; }
set { m_validator = value; }
}
public bool RejectChangesOnError
{
get { return m_rejectChangesOnError; }
set { m_rejectChangesOnError = value; }
}
private void OnColumnChanged(object sender, DataColumnChangeEventArgs e)
{
if (e.Column == this)
{
object obj = e.ProposedValue;
if (!m_validator.IsValid(obj))
{
if (m_rejectChangesOnError)
e.Row.RejectChanges();
throw new Exception(m_resMgr.GetString("S_ERR_INVALID_DATA"));
}
}
}
}
}
Conclusion
I have presented some very elementary scenarios in which the data column can be validated to restrict input. This idea may be extended to more complex scenarios to suit the requirements of the business necessity at hand.