ReadXmlWorkoutMachine
===================

This application permits you to explore the results of using ReadXml() in different situations and with different XmlReadModes.  You have four sets of choices to make:

1. Whether to use an untyped DataSet or a Strongly Typed one;
2. Whether to read from an XML file that includes schema information, has no schema information, or is a DiffGram;
3. Whether to use an overload of ReadXml() that specifies the read mode, or an overload that does not; and finally (if you choose to specify the read mode),
4. What XmlReadMode to use for the mode parameter of the ReadXml() call.

The application loads Product information that originated in the Northwind database's Products table. Four different datafiles are available:

1. Products_SchemaWritten.xml,
2. Products_SchemaIgnored.xml
3. Products_DiffGram.xml, and
4. Products_SchemaAltered.xml

The first three datafiles were created using the WriteXmlWorkoutMachine application, using the mode XmlWriteMode.WriteSchema, XmlWriteMode.IgnoreSchema, and XmlWriteMode.DiffGram, respectively. The first includes both schema information and data; the second data only.  The third file, Products_DiffGram.xml, contains no schema information, the same set of data as Products_SchemaIgnored.xml, and in addition, data regarding changes that were made to the DataSet between the time it was filled and written. Those changes included an update of the ProductName column one one record; deletion of a second record, and insertion of a third record.

The final file, Products_SchemaAltered.xml, was produced by making a copy of Products_SchemaWritten.xml, then changing the data types on all of the int16 ("short") columns to int32's ("int").  This datafile gives us a way of seeing "which schema wins" when we use a strongly typed DataSet, but also specify a read mode of ReadXmlSchema.

ReadXml() is an overloaded method with eight different versions.  Four of the overloads do not specify the read mode, and four do.  The two sets of four overloads allow four different types of input:  an XmlReader, a Stream, a TestReader, and a FileName.  In this application we always read our input from a file.

If you choose to specify the read mode, there are six choices, corresponding to the members of the XmlReadMode enumeration.  These choices are:

1. XmlReadMode.ReadSchema
2. XmlReadMode.IgnoreSchema
3. XmlReadMode.InferSchema
4. XmlReadMode.Auto
5. XmlReadMode.Fragment
6. XmlReadMode.DiffGram 

XmlReadMode.ReadSchema loads the schema information from the XML data file, then loads its data, interpreting it according to that schema.

XmlReadMode.IgnoreSchema bypasses the schema information in the XML data file (if present), simply attempting to load its data.  If ReadXml() is invoked from an untyped dataset, no data is loaded.

XmlReadMode.InferSchema bypasses the schema information in the XML data file (if present), but attempts to infer a schema from the data it finds.  Invoking ReadXml() from an untyped dataset with this mode should result in a successful load.  Note: when you select this option for the XmlReadMode, the button labelled Execute InferXmlSchema() is enabled, and can be clicked as an alternative to the Execute ReadXml() button.  The InferXmlSchema() methods does not actually use the XmlReadMode parameter, but I have restricted its invocation to the situation where that option is selected simply to emphasize the fact InferXmlSchema() returns the same XML (minus data) as ReadXml called with XmlReadMode.InferSchema.

XmlReadMode.Auto lets you leave the read mode decision to ADO.NET.  It makes its choice according to the following rules: 

1. If the data is a DiffGram, it sets XmlReadMode to DiffGram
2. If the dataset already has a schema, or the document contains an in-line schema, it sets XmlReadMode to ReadSchema.
3. If the dataset does not already have a schema and the document does not contain an in-line schema, it sets XmlReadMode to InferSchema.

XmlReadMode.Fragment reads XML documents such as those generated by executing FOR XML queries against an instance of SQL Server. When XmlReadMode is set to Fragment, the default namespace is read as the inline schema.

XmlReadMode.DiffGram reads a DiffGram produced by a WriteXml() call, and applies changes from the DiffGram to the DataSet. The DataSet must have the same schema as the DataSet on which WriteXml was called to produce the DiffGram, or the DiffGram operation will fail.


How to Use the ReadXmlWorkoutMachine
==============================
The WorkoutMachine permits you to experiment with different combinations of the four basic choices, and see both the data that gets loaded, in a DataGrid, as a user might see it (on the "Data" tab); and an XML representation of the information in the DataSet (on the "XML" tab)..  The loaded DataSet produces the latter by calling the WriteXml() method with the XmlWriteMode.WriteSchema parameter.  It writes the Xml representation of the DataSet to a memory stream, whence it is read by a StreamReader into a string, and the string then assigned to the Text property of the TextBox in which you see it displayed.

Case 1
-------
First try loading the data using all the default settings:  

1. Untyped DataSet
2. Datafile with Schema Info
3. Mode Specified, and
4. ReadSchema.  

Note on the XML tab that the DataSet includes schema information which is detailed near the top of its XML representation.  All of the key columns -- ProductID, SupplierID, and CategoryID -- are typed as integers; and ProductID is marked as an AutoIncrement column. ProductName and QuantityPerUnit are designated as string types; UnitPrice as a decimal; UnitsInStock, UnitsOnOrder, and ReorderLevel are typed as shorts; Discontinued as a Boolean; and Photo as a Base64Binary.

Case 2
-------
Now change the XmlReadMode to IgnoreSchema so that you have the following settings:

1. Untyped DataSet
2. Datafile with Schema Info
3. Mode Specified, and
4. IgnoreSchema.  

Click <Load Records from XML File> to re-load the data. Notice in the XML that neither schema nor product data appears; and non appears in the DataGrid, either.  

Case 3
-------
Now change the DataSet type to "Strongly Typed" so you have these settings:

1. Strongly Typed DataSet
2. Datafile with Schema Info
3. Mode Specified, and
4. IgnoreSchema.  

Re-load.  Voila, the data reappears in both views.  If ADO.NET can't read or infer schema information from the datafile, it needs to have it in the DataSet!

Case 4
-------
Now re-select the Untyped DataSet; choose the datafile that has no schema information; and do a modal read with a mode of InferSchema:

1. Untyped DataSet
2. Datafile with no Schema Info
3. Mode Specified, and
4. InferSchema.  

 ADO.NET loads the data and "makes up" a schema to accomodate it.  But note that the model of the schema it creates is a bit of a blunt instrument: all columns are typed as strings, and the Photo column is ignored.  It does not even appear in the datagrid.

Case 5
-------
Now try these settings:

1. Untyped DataSet
2. DiffGram datafile
3. Mode specified, and
4. Read mode of DiffGram

You should receive the following error message:  "Can't load diffGram. Table 'Products' is missing in the destination dataset. Try reading the DiffGram into a strongly typed DataSet."  The first part of that error message comes from the error thrown by .NET; the last sentence was added by me.  What's happening here is that the DiffGram doesn't include schema information, and since you specified the Untyped DataSet, ADO.NET is again at a loss to know what to do with the data.

Case 6
-------
Change the DataSet type to Strongly Typed and re-load.  

1. Strongly Typed DataSet
2. DiffGram datafile
3. Mode specified, and
4. Read mode of DiffGram

Note that the name of the first product displayed is "Chai Tea Latte Powder": that was changed from "Chai Tea Latte" in the original dataset.  (This was a record I added some time ago to the Northwind Products table.)  The very last row in the dataGrid shows a "Chai Tea Candy Bars" product, which was added just before the DiffGram datafile was produced.  The difference information, consisting of the old state of the first record and a copy of a record that was deleted, is not displayed in the DataGrid; but the information is there in the DataSet, accessible with a DataSet.GetChanges() call.  (A notation is also there about the record that was inserted.)

Case 7
-------
Try this combination:

1. Untyped DataSet
2. Datafile with no schema info 
3. Mode specified, and
4. Read Schema.

As you may by now expect, no records get loaded, because even though we told ReadXml() to read the schema, there was none to read.  Since the DataSet itself doesn't supply it, again ADO.NET is unable to load the data.

When Schemas Collide
================
Suppose we read data into a Strongly Typed DataSet, but still specify a read mode of ReadXmlSchema, in a situation where there is a difference between the schema in the DataSet and the one in the datafile.  Which schema wins? 

Recall that the datafile Products_SchemaAltered.xml is nearly, but not completely, identical to Products_SchemaWritten.xml (which has the same schema as dsProducts.xsd, the base for our strongly typed dataset). In Products_SchemaAltered.xml, I changed the short data types to ints.  Let's look at those:

Case 8
-------
1. Untyped DataSet
2. Datafile with altered schema
3. Mode specified, and
4. Read Schema.

Confirm that the UnitsInStock, UnitsOnOrder, and Reorder level column are typed as ints in the schema shown on the XML tab.

Now re-load the data into a Strongly Typed DataSet:

Case 9
-------
1. Strongly Typed DataSet
2. Datafile with altered schema
3. Mode specified, and
4. Read Schema.

This timethe XML view shows UnitsInStock, UnitsOnOrder, and Reorder level typed as shorts.  Clearly, the data typing specified in the DataSet itself has trumped that contained in the datafile, even though we specified XmlReadMode.ReadSchema as the read mode.

Modeless Reads
============
If you use an Untyped DataSet and select Modeless as your "Type of Read", ReadXml() behaves as follows:

1. It reads the schema from the datafile is there is one; and 
2. Infers the schema otherwise.

If you use an Strongly Typed DataSet and do a modeless read, the schema in the DataSet will trump any schema in the datafile.

