Pregunta

is it possible to create a value range constraint on a DataTable in C#?

I'm dynamically adding a column to a DataTable:

this.PrimaryCorrelationMatrix.Columns.Add(sName, typeof(int));

but I'd like all values within this Column to be integers from [0, 10]. Can I implement such a constraint directly on the DataTable?

The next best option I can think of is to create some object with possible values [0, 10], and instead of typeof(int), using typeof(specialObj).

¿Fue útil?

Solución

One way to do this is to inspect the e.ProposedValue in the ColumnChanging event of the DataTable.

To have the constraint on a particular column, you can use the ExtendedProperties collection of the DataColumn to act as your flag to check those constraints:

DataTable dt = new DataTable();
DataColumn dc = new DataColumn("Range", typeof(int));
dc.ExtendedProperties.Add("Min", 0);
dc.ExtendedProperties.Add("Max", 10);
dt.Columns.Add(dc);
dt.ColumnChanging += dt_ColumnChanging;

In the ColumnChanging event, you would check if those properties exist, then use them:

void dt_ColumnChanging(object sender, DataColumnChangeEventArgs e) {
  if (e.Column.ExtendedProperties.ContainsKey("Min") &&
      e.Column.ExtendedProperties.ContainsKey("Max")) {
    int min = (int)e.Column.ExtendedProperties["Min"];
    int max = (int)e.Column.ExtendedProperties["Max"];
    if ((int)e.ProposedValue < min) e.ProposedValue = min;
    if ((int)e.ProposedValue > max) e.ProposedValue = max;
  }
}

Otros consejos

I can recommend you to forget about data tables and use classes. You can use data annotation to validate your model.

Use this attribute to validate a range of values for an specific property/

This code is extracted from the specified article(example of class making the validation of a range):

public class Product
{

  [Range(5, 50)]
  public int ReorderLevel { get; set; }

  [Range(typeof(Decimal),"5", "5000")]
  public decimal ListPrice { get; set; }

}

Your are going to find a lot of benefits of using classes.

This is an old post but I am using a solution to sync the Check_Constraints NOT filled by the OleDbDataAdapter.FillSchema on Access Databases worth to mention. Just used a OleDbConnection to retrieve GetOleDbSchemaTable and foreach() the rows extracting the validation text expression and created an anonymous delegate at the appropriate Table & Column attached to the proper Table.ColumnChanging event. The string validation provided by the Access schema will then be evaluated dynamically by the handy Eval() function described here. There is my code:

DataTable schemaTable = connection.GetOleDbSchemaTable(OleDbSchemaGuid.Check_Constraints, null);
// Attach delegate Eval() of each Check_Constraints on proper Table/Column
foreach (DataRow myField in schemaTable.Rows)
{
    string constraint_name = "";
    string check_clause = "";
    foreach (DataColumn myProperty in schemaTable.Columns)
    {
        if (myProperty.ColumnName == "CONSTRAINT_NAME")
            constraint_name = myField[myProperty.ColumnName].ToString();
        if (myProperty.ColumnName == "CHECK_CLAUSE")
            check_clause = myField[myProperty.ColumnName].ToString();
    }
    var rule = constraint_name.Replace("[", "").Replace("]", "").Split('.');
    if (rule.Length == 3 && dataset.Tables.Contains(rule[0]) && dataset.Tables[rule[0]].Columns.Contains(rule[1]) && String.IsNullOrEmpty(check_clause) == false)
    {
        dataset.Tables[rule[0]].ColumnChanging += delegate (object sender, DataColumnChangeEventArgs e)
        {
            if (e.Column.ColumnName == rule[1] && Convert.ToBoolean(ToolBox.Eval(e.ProposedValue + check_clause)) == false)
            {
                throw new Exception("Tabela: " + rule[0] + ", coluna: " + rule[0] + ", cheque: " + check_clause);
            }
        };
        Debug.WriteLine(rule[0] + "." + rule[1] + ": " + check_clause);
    }
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top