[ Team LiB ]
Recipe 8.8 Creating anXMLFileThatShowsChangesMadetoaDataSet
Problem
When you use the GetXML( ) method of the DataSet, you may see only the current
values in the DataSet. You want to get the original values and see which rows were
added, edited, or deleted.
Solution
Create anXML DiffGram, which is a document that details the modifications madetoa
DataSet.
The sample code contains two event handlers and a single method:
Form.Load
Sets up the sample by loading the Categories table from Northwind into aDataSet
and displays the DiffGram for the DataSet before modification.
Make Changes Button.Click
Deletes the first row, modifies the second row, inserts a row before the first row,
and adds a row to the end of the Categories DataTable
DisplayDiffGram( )
This method outputs the DiffGram for the DataSetto both afile and toa textbox
on the form.
The C# code is shown in Example 8-12
.
Example 8-12. File: XmlDiffgramForm.cs
// Namespaces, variables, and constants
using System;
using System.Configuration;
using System.Text;
using System.IO;
using System.Xml;
using System.Xml.Schema;
using System.Data;
using System.Data.SqlClient;
// Table name constants
private const String CATEGORIES_TABLE = "Categories";
// Field name constants
private const String CATEGORYNAME_FIELD = "CategoryName";
private const String XMLDIFFGRAMFILENAME =
ConfigurationSettings.AppSettings["Temp_Directory"] +
"CategoriesDiffgram.xml";
private DataSet ds;
// . . .
private void XmlDiffgramForm_Load(object sender, System.EventArgs e)
{
// Select fields from Categories table without the Picture BLOB.
String sqlText = "SELECT CategoryID, CategoryName, Description " +
"FROM Categories";
// Load the Categories table into the DataSet.
SqlDataAdapter da = new SqlDataAdapter(sqlText,
ConfigurationSettings.AppSettings["Sql_ConnectString"]);
ds = new DataSet( );
da.Fill(ds, "Categories");
DisplayDiffGram( );
}
private void makeChangesButton_Click(object sender, System.EventArgs e)
{
// Disable the make changes button.
makeChangesButton.Enabled = false;
DataTable dt = ds.Tables["Categories"];
// Delete the first row.
dt.Rows[0].Delete( );
// Modify the second row.
dt.Rows[1][CATEGORYNAME_FIELD] += "New ";
// Insert a row.
DataRow row = dt.NewRow( );
row.ItemArray = new object[] {0, "New Category0",
"New Category0 Description"};
dt.Rows.InsertAt(row, 0);
// Add a row.
dt.Rows.Add(new object[] {9, "New Category9",
"New Category9 Description"});
DisplayDiffGram( );
}
private void DisplayDiffGram( )
{
// Write the XML diffgram toa memory stream.
MemoryStream ms = new MemoryStream( );
ds.WriteXml(ms, XmlWriteMode.DiffGram);
// Write the memory stream toa file.
FileStream fs = new FileStream(XMLDIFFGRAMFILENAME, FileMode.Create,
FileAccess.Write);
ms.WriteTo(fs);
fs.Close( );
// Display the XML DiffGram.
byte[] result = ms.ToArray( );
ms.Close( );
resultTextBox.Text = Encoding.UTF8.GetString(result,0,result.Length);
}
Discussion
A DiffGram is anXML format used to specify both the original and current values for the
contents of a DataSet. It does not include any schema information. The DiffGram is also
the primary serialization format used by the .NET Framework to persist and serialize a
DataSet. The DiffGram format is XML-based, making it platform and application
independent. It is not, however, widely used or understood outside of Microsoft .NET
applications.
The DiffGram format is divided into three sections—current, original, and errors—as
shown in the following example:
<?xml version="1.0"?>
<diffgr:diffgram
xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"
xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1">
<DataInstanceName>
. . .
</DataInstanceName>
<diffgr:before>
. . .
</diffgr:before>
<diffgr:errors>
. . .
</diffgr:errors>
</diffgr:diffgram>
Here are descriptions of the three DiffGram sections:
<DataInstanceName>
The DataInstanceName is the name of the DataSet or DataTable. This block
contains the current version of the data containing all modifications. Modified
elements are identified with the diffgr:hasChanges="modified" annotation while
new elements are identified with the diffgr:hasChanges="inserted" annotation.
Deleted elements are not annotated, rather, they appear only in the <diffgr:before>
section.
<diffgr:before>
This section contains the original version of the elements that have been modified
or deleted. Elements in this section are matched to elements in the
<DataInstanceName> section using the diffgr:id annotation with matching values.
<diffgr:errors>
This section contains error information for an element in the
<DataInstanceName> section. Elements in this section are matched to elements in
the <DataInstanceName> section using the diffgr:id annotation with matching
values.
The example loads all Categories from Northwind into a DataTable called Categories in a
DataSet. The first row is deleted, the second is modified, a row is inserted before the first
row, and a row is added to the end of the DataTable. After these modifications, the
DiffGram for the DataSet is:
<diffgr:diffgram xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"
xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1">
<NewDataSet>
<Categories diffgr:id="Categories9" msdata:rowOrder="0"
diffgr:hasChanges="inserted">
<CategoryID>0</CategoryID>
<CategoryName>New Category0</CategoryName>
<Description>New Category0 Description</Description>
</Categories>
<Categories diffgr:id="Categories2" msdata:rowOrder="2"
diffgr:hasChanges="modified">
<CategoryID>2</CategoryID>
<CategoryName>CondimentsNew </CategoryName>
<Description>Sweet and savory sauces, relishes, spreads, and
seasonings</Description>
</Categories>
<Categories diffgr:id="Categories3" msdata:rowOrder="3">
<CategoryID>3</CategoryID>
<CategoryName>Confections</CategoryName>
<Description>Desserts, candies, and sweet breads</Description>
</Categories>
<! . . . >
<Categories diffgr:id="Categories8" msdata:rowOrder="8">
<CategoryID>8</CategoryID>
<CategoryName>Seafood</CategoryName>
<Description>Seaweed and fish</Description>
</Categories>
<Categories diffgr:id="Categories10" msdata:rowOrder="9"
diffgr:hasChanges="inserted">
<CategoryID>9</CategoryID>
<CategoryName>New Category9</CategoryName>
<Description>New Category9 Description</Description>
</Categories>
</NewDataSet>
<diffgr:before>
<Categories diffgr:id="Categories1" msdata:rowOrder="1">
<CategoryID>1</CategoryID>
<CategoryName>Beverages</CategoryName>
<Description>Soft drinks, coffees, teas, beers, and ales</Description>
</Categories>
<Categories diffgr:id="Categories2" msdata:rowOrder="2">
<CategoryID>2</CategoryID>
<CategoryName>Condiments</CategoryName>
<Description>Sweet and savory sauces, relishes, spreads,
and seasonings</Description>
</Categories>
</diffgr:before>
</diffgr:diffgram>
As expected, the DiffGram contains both the annotation indicating inserted and modified
records. The <diffgr:before> section contains the original record for the deleted records
with CategoryID=1 and the modified record with CategoryID=2.
As shown in the example, a DiffGram is written for the DataSet by specifying an
XmlWriteMode of DiffGram when calling the WriteXml( ) method of the DataSet. The
GetXml( ) method cannot be used to generate a DiffGram. ADataSet can be loaded from
an XML DiffGram by specifying an XmlWriteMode of DiffGram when calling the
ReadXml( ) method.
[ Team LiB ]
. Team LiB ]
Recipe 8.8 Creating an XML File That Shows Changes Made to a DataSet
Problem
When you use the GetXML( ) method of the DataSet, you may. sample by loading the Categories table from Northwind into a DataSet
and displays the DiffGram for the DataSet before modification.
Make Changes Button.Click