XML is firmly entrenched in ADO.NET – indeed, the remoting format for passing data between objects is now XML With the .NET runtime, it is possible to describe a DataTabl e class within an XML schema definition file (XSD), What’s more, you can define an entire DataSet class, with a number of DataTable classes, and a set of relationships between these tables, and you can include various other details to fully describe the data.
When you have defined an XSD file, there is a tool in the runtime that will convert this schema to the corresponding data access class(es), such as the type-safe product DataTable class shown earlier, Let’s start with a simple XSD file (Products. xsd) that describes the same information as the Products sample discussed earlier and then extend it to include some extra functionality:
These options are covered in detail in Chapter 28, “Manipulating XML”; for now, this file basically defines a schema with the id attribute set to Products, A complex type called Product is defined, which contains a number of elements, one for each of the fields within the Products table.
These items map to data classes as follows. The Products schema maps to a class derived from DataSet, The Product complex type maps to a class derived from DataTable, Each sub-element maps to a class derived from DataColumn, The collection of all columns maps to a class derived from DataRow.
Thankfully, there is a tool within the .NET Framework that produces the code for these classes with the help of the input XSD file, Because its sole job is to perform various functions on XSD files, the tool itself is called XSD.EXE.
Assuming that you saved the preceding file as Product .xsd, you would convert the file into code by issuing the following command in a command prompt:
This creates the file Product. cs
Various switches can be used with XSD to alter the output generated, Some of the more commonly used switches are shown in the following table.
The following is an abridged version of the output from XSD for the Products schema, The output has been altered slightly to fit into a format appropriate for this book. To see the complete output, run XSD .EXEon the Products schema (or one of your own making) and take a look at the .cs file generated, The example includes the entire source code plus the Product. xsd file (note that this output is part of the downloadable code file available at www.csharpaid.com):
All private and protected members have been removed to concentrate on the public interface.TIll’ ProductDataTable and ProductRow definitions show the positions of two nested classes,wh.ch will be implemented next. You review the code for these classes after a brief explanation of the dataSet derived class.
The Products () constructor callsa private method, InitClass (),which constructs an instance of the DataTable-derived classProductDataTable, and adds the table to the Tables collectionof the DataSet class.The Products data table can be accessed by the following code:
DataSet ds = new Products();
DataTable products = ds.Tables[“Products”];
Or, more simply by using the property Product, available on the deriyed DataSet object:
DataTable products = ds.Product;
Because the Product property is strongly typed, you could naturally use ProductDataTable rather than the DataTable reference shown in the previous code.
The ProductDataTable> class includes far more code (note this is an abridged version of the code):
The ProductDataTable class, derived from DataTable and implementing the IEnurnerable interface, defines a private DataColumn instance for each of the columns within the table, These are initialized again from the constructor by calling the private Ini tClass () member. Each column is given an internal accessor, which is used by the DataRow class (which is described shortly):
public int Count
get return this.Rows.Count;
internal DataColumn ProductIDColumn
get ( return this.columnProductID;
II Other row accessors removed for clarity — there is one for each column
Adding rows to the table is taken care of by the two overloaded (and significantly different) AddProductRow () methods. The first takes an already constructed DataRow and returns a void, The second takes a set of values, one for each of the columns in the DataTable, constructs a new row, sets the values within this new row, adds the row to the DataTable object, and returns the row to the caller, Such widely different functions shouldn’t really have the same name!
Just like the InitClass () member in the DataSet-derived class, which added the table into the DataSet class, the InitClass () member in ProductDataTable adds columns to the DataTable class, Each column’s properties are set as appropriate, and the column is then appended to the columns collection:
NewRowFromBuilder () is called internally from the DataTable class’s NewRow () method. Here, it creates a new strongly typed row, The DataRowBuilder instance is created by the data tablerowbuilder, and its members are accessible only within the System . Data assembly:
protected override DataRow NewRowFromBuilder(DataRowBuilder builder)
retur.n new ProductRow(builder); ‘
The last class to discuss is the Product Row class, derived from DataRow, This class is used to provide type-safe access to all fields in the data table, It wraps the storage for a particular row, are provides members to read (and write) each of the fields in the table.
In addition, for each null able field, there are functions to set the field to null, and to check if the field is null, The following example shows the functions for the SupplierlD column:
The following code uses the classes ouptut from the XSD tool to retrieve data from the Products table and display that data to the console:
In addition, for each nullable field, there are functions to set the field to null, and to check if the field is null, The following example shows the functions for the SupplierlD column:
The following code uses the classes ouprut from the XSD tool to retrieve data from the Products table and display that data to the console:
The output 0f the XSD file contains a class derived from DataSet, Prcducts, which is created and then filled by the use of the data adapter, The foreach statement uses the strongly typed ProductRow and also the Product property which returns the Product data table.
To compile this example issue the following commands.
xsd product xsd /d
The first generates the products cs file from the Products, XSD schema, and then the csc command uses the /recurse : ∗. cs parameter to go through all files with the extension .cs and add these to the resulting assembly.