How to embrace the .NET paradigm shift

Although the integration between ADO.NET and XML is unquestionably tight, only the DataSet, in the whole ADO.NET hierarchy of classes, can automatically load its contents from XML and then save back. Adding this same XML serialization to other classes, including DataTable and DataView, would have made the overall design of ADO.NET classes much more complex. By contrast, the code necessary to institute serialization for a DataTable or a DataView class isn't particularly difficult to write. Let's see how to do it.

Only the DataSet object can save to XML. Therefore, you have to use a temporary object to save a DataTable or a DataView to XML.

A DataSet object is a repository for data-related information. It can contain multiple tables, relations between tables, and constraints. In no case, however, does it contain information about a table view. If you need an XML document that includes rows from a single DataTable object, you must ensure that the table belongs to a DataSet that has no other contents. If the table already belongs to a non-empty DataSet, you first have to create a second, temporary DataSet object and clone the table into it. For example, let's say that you have a table called MyTable stored in a DataSet called myDataset.

   // Duplicate the table.
   DataTable dt = myDataset.Tables\["MyTable"\];
   DataTable dtCopy = dt.Copy();
   
   // Add the duplicate to a temporary DataSet.
   DataSet tmp = new DataSet();
   tmp.Tables.Add(dtCopy);
   
   // Save the DataSet with the single table to XML.
   StreamWriter sw = new StreamWriter(file);
   tmp.WriteXml(sw);
   sw.Close();

The DataTable's Copy method provides a full copy of the table, including column metadata and rows. In the .NET documentation, such an operation is often called a deep copy. Keep in mind that calling the Copy method is much different from duplicating the reference to a variable.

   DataTable dt = dtCopy;

The line above simply creates a new reference to the memory address on the right side of the equal sign. Both variables point to the same physical table. The Copy method, however, creates a new, yet identical, table. This step is necessary because you can't have the same DataTable object participate in two different DataSet objects. If you want to save the duplication step, you can detach the DataTable from the original DataSet and link it to a temporary one. After saving this new, temporary DataSet to XML, you detach the table and link it back to the original DataSet.

   // Detach the table.
   DataTable dt = myDataset.Tables\["MyTable"\];
   MyDataset.Remove(dt);
   
   // Add the table to a temporary DataSet.
   DataSet tmp = new DataSet();
   tmp.Tables.Add(dt);
   
   // Save the DataSet with the single table to XML.
   StreamWriter sw = new StreamWriter(file);
   tmp.WriteXml(sw);
   sw.Close();
   
   // Attach the DataTable to the original DataSet.
   myDataset.Tables.Add(dt);

A DataView object represents a row filter that is set atop a table. A DataView doesn't duplicate any row but instead creates an internal linked list of the table rows belonging to the filter. A DataView can't be embedded into a DataSet, so to save all a view's rows into an XML document, you must first create a subtable, then add this subtable to an empty DataSet, and finally save the contents to XML.

   DataView dv = new DataView(myTable);
   dv.RowFilter = strFilterMask;
   
   // Create an empty sub-table with the same
   // structure as the original.
   DataTable dt = myTable.Clone();
   
   // Loop through the items in the view and
   // import corresponding rows into a new table.
   foreach(DataRowView drv in dv)
       dt.ImportRow(drv.Row);
           
       DataSet ds = new DataSet();
       ds.Tables.Add(dt);

To create the child table that contains all the rows matching the filter condition and no others, you use the Clone method. Clone works in much the same way as Copy, with a significant difference. The newly created table has the same structure (columns, index, constraints) as the original, but is empty.

You loop through the rows referenced in the DataView object and import each row in the new table. Next, the table is added to a temporary DataSet and saved to XML. A row in a view is accessed through a DataRowView object, which is a sort of proxy for the actual row. The Row property on a DataRowView object returns the underlying table row object. The method ImportRow on the DataTable class makes a full copy of the given DataRow object and adds it to the table.

The DataSet is the key object in the ADO.NET object model. Working as a data container, it can include other ADO.NET objects. So although only the DataSet object can save to XML, the richness of the ADO.NET object model makes it relatively easy to write code that can save to XML any set of rows you want.