Adding RestrictionstoDataTableandDataColumnObjects As you know, a DataSet object is used to store a copy of a subset of the database. For example, you can store a copy of the rows from database tables into a DataSet, with each table represented by a DataTable object. A DataTable stores columns in DataColumn objects. In addition to storing rows retrieved from a database table, you can also add restrictionsto a DataTableand its DataColumn objects. This allows you to model the same restrictions placed on the database tables and columns in your DataTableandDataColumn objects. For example, you can add the following constraints to a DataTable: • Unique • Primary key • Foreign key In addition, you can add the following restrictionsto a DataColumn: • Whether the column can accept a null value-which you store in the AllowDBNull property of the DataColumn. • Any auto-increment information-which you store in the AutoIncrement, AutoIncrementSeed, and AutoIncrementStep properties of the DataColumn. You set these properties when adding rows to a DataTable with a corresponding database table that contains an identity column. The ProductID column of the Products table is an example of an identity column. Note ADO.NET will not automatically generate values for identity columns in a new row. Only the database can do that. You must read the generated identity value for the column from the database. You'll see how to do that later in the sections "Retrieving New Identity Column Values " and "Using Stored Procedures to Add, Modify, and Remove Rows from the Database." Also, if your database table contains columns that are assigned a default value, you should read that value from the database. This is better than setting the DefaultValue property of a DataColumn because if the default value set in the database table definition changes, you can pick up the new value from the database rather than having to change your code. • The maximum length of a string or character column value-which you store in the MaxLength property of the DataColumn. • Whether the column is read-only-which you store in the ReadOnly property of the DataColumn. • Whether the column is unique-which you store in the Unique property of the DataColumn. By adding these restrictions up front, you prevent bad data from being added to your DataSet to begin with. This helps reduce the errors when attempting to push changes in your DataSet to the database. If a user of your program attempts to add data that violates a restriction, they'll cause an exception to be thrown. You can then catch the exception in your program and display a message with the details. The user can then change the data they were trying to add and fix the problem. You also need to define a primary key before you can find, filter, and sort DataRow objects in a DataTable. You'll learn how to do that later in the section "Finding, Filtering, and Sorting Rows in a DataTable." Tip Adding constraints causes a performance degradation when you call the Fill() method of a DataAdapter. This is because the retrieved rows are checked against your constraints before they are added to your DataSet. You should therefore set the EnforceConstraints property of your DataSet to false before calling the Fill() method. You then set EnforceConstraints back to the default of true after the call to Fill(). You can use one of following ways to add restrictions toDataTableandDataColumn objects: • Add the restrictions yourself by setting the properties of your DataTableandDataColumn objects. This results in the fastest executing code. • Call the FillSchema() method of your DataAdapter to copy the schema information from the database to your DataSet. This populates the properties of the DataTableobjectsand their DataColumnobjects automatically. Although simple to call, the FillSchema() method takes a relatively long time to read the schema information from the database and you should avoid using it. You'll learn the details of both these techniques in the following sections. Adding the Restrictions Yourself You can add restrictionsto your DataTableandDataColumnobjects yourself using the properties of the DataTableandDataColumn objects. For example, assume you have a DataSet object named myDataSet that contains three DataTableobjects named Products, Orders, and Order Details that have been populated using the following code: SqlCommand mySqlCommand = mySqlConnection.CreateCommand(); mySqlCommand.CommandText = "SELECT ProductID, ProductName " + "FROM Products;" + "SELECT OrderID " + "FROM Orders;" + "SELECT OrderID, ProductID, UnitPrice " + "FROM [Order Details];"; SqlDataAdapter mySqlDataAdapter = new SqlDataAdapter(); mySqlDataAdapter.SelectCommand = mySqlCommand; DataSet myDataSet = new DataSet(); mySqlConnection.Open(); mySqlDataAdapter.Fill(myDataSet); mySqlConnection.Close(); myDataSet.Tables["Table"].TableName = "Products"; myDataSet.Tables["Table1"].TableName = "Orders"; myDataSet.Tables["Table2"].TableName = "Order Details"; The primary key for the Products table is the ProductID column; the primary key for the Orders table is the OrderID column; and the primary key for the Order Details table is made up of both the OrderID and ProductID columns. Note You must include all the columns of a database table's primary key in your query if you want to define a primary key on those columns in your DataTable. In the following sections, you'll see how to • Add constraints to the Products, Orders, and Order Details DataTable objects. • Restrict the values placed in the DataColumnobjects of the Products DataTable. Adding Constraints toDataTableObjects In this section, you'll see how to add constraints toDataTable objects. Specifically, you'll see how to add primary key constraints to the Products, Orders, and Order Details DataTable objects. A primary key constraint is actually implemented as a unique constraint. You'll also see how to add foreign key constraints from the Order Details to the Products and Orders DataTable objects. Constraints are stored in a ConstraintCollection object that stores Constraint objects. You access the ConstraintCollection using the DataTable object's Constraints property. To add a new Constraint object to ConstraintCollection, you call the Add() method through the Constraints property. The Add() method allows you to add unique constraints and foreign key constraints to a DataTable. Since a primary key constraint is implemented as a unique constraint, you can also use the Add() method to add a primary constraint to a DataTable. You'll see how to use the Add() method shortly. You can also add a primary key constraint to a DataTable object by setting its PrimaryKey property, which you set to an array of DataColumnobjects that make up the primary key. An array is required because the primary key of a database table can be made up of multiple columns. As you'll see in the examples, this is simpler than using the Add() method to add a primary key constraint. CALLING THE Fill() METHOD OF A DataAdapter MORE THAN ONCE The Fill() method retrieves all of the rows from the database table, as specified in your DataAdapter object's SelectCommand property. If you add a primary key to your DataTable, then calling the Fill() method more than once will put the retrieved rows in your DataTableand throw away any existing rows with matching primary key column values already in your DataTable. If you don't add a primary key to your DataTable, then calling the Fill() method more than once will simply add all the retrieved rows to your DataTable again, duplicating the rows already there. This is another reason for adding a primary key constraint to your DataTable because you don't want duplicate rows. Adding a Primary Key to the Products DataTable Let's take a look at adding a primary key to the Products DataTable. First, the following example creates a DataTable object named productsDataTable and sets it to the Products DataTable retrieved from myDataSet: DataTable productsDataTable = myDataSet.Tables["Products"]; Now, the primary key for the Products database table is the ProductID column; therefore, you need to set the PrimaryKey property of productsDataTable to an array containing the ProductID DataColumn object. The following example shows how you do this. It creates an array of DataColumnobjects named productsPrimaryKey and initializes it to the ProductID column of productsDataTable, then sets the PrimaryKey property of productsDataTable to the array: DataColumn[] productsPrimaryKey = new DataColumn[] { productsDataTable.Columns["ProductID"] }; productsDataTable.PrimaryKey = productsPrimaryKey; When you set the PrimaryKey property of a DataTable, the AllowDBNull and Unique properties of the DataColumn object are automatically changed as follows: • The AllowDBNull property is changed to false and indicates that the DataColumn cannot accept a null value. • The Unique property is changed to true and indicates that the DataColumn value in each DataRow must be unique. In the previous example, therefore, the AllowDBNull and Unique properties of the ProductID DataColumn are automatically changed to false and true, respectively. Adding a Primary Key to the Orders DataTable The following example sets the PrimaryKey property of the Orders DataTableto the OrderID DataColumn: myDataSet.Tables["Orders"].PrimaryKey = new DataColumn[] { myDataSet.Tables["Orders"].Columns["OrderID"] }; Notice I've used just one statement in this example to make it more concise than the previous example. You can also use the Add() method to add a unique, primary key, or foreign key constraint to a DataTable. The Add() method is overloaded as follows: void Add(Constraint myConstraint) // adds any constraint void Add(string constraintName, DataColumn myDataColumn, bool isPrimaryKey) // adds a primary key or unique constraint void Add(string constraintName, DataColumn parentColumn, DataColumn childColumn) // adds a foreign key constraint void Add(string constraintName, DataColumn[] myDataColumn, bool isPrimaryKey) // adds a primary key or unique constraint void Add(string cosntraintName, DataColumn[] parentColumns, DataColumn[] childColumns) // adds a foreign key constraint where . Adding the Restrictions Yourself You can add restrictions to your DataTable and DataColumn objects yourself using the properties of the DataTable and DataColumn. to the default of true after the call to Fill(). You can use one of following ways to add restrictions to DataTable and DataColumn objects: • Add the restrictions