[ Team LiB ]
Recipe 5.10 Converting a DataSet to an ADO Recordset
Problem
You need to convert a DataSet to an ADO Recordset so that you can use it in a legacy
application.
Solution
You must persist the DataSet to XML, transform it to ADO Recordset schema, and load
it into an ADO Recordset using COM interop.
You'll need a reference to the Primary Interop Assembly (PIA) for ADO provided in the
file ADODB.DLL. Select adodb from the .NET tab in Visual Studio .NET's Add
Reference Dialog.
The sample uses one XML file:
Orders.xslt
The XSLT stylesheet used to transform the XML document output by the DataSet
into an ADO Recordset XML document.
The sample code contains one event handler and one method:
Go Button.Click
Converts the DataSet to an ADO Recordset using the following steps:
1. A shell XML document for the ADO Recordset is created.
2. A DataReader accesses the schema information for the data to convert
using the GetSchemaTable( ) method. This information is mapped to and
added to the ADO Recordset XML document.
3. The DataSet is loaded with data for a single DataTable. The XML
document for the DataSet is transformed and written into the ADO
Recordset XML document.
4. An ADO Recordset object is created and loaded with the ADO Recordset
XML document. This completes the conversion.
5. The ADO Recordset is loaded into a DataTable using the
OleDbDataAdapter. The default view for the table is bound to the data grid
on the form to display the results of the conversion.
GetDataTypeInfo( )
This method maps SQL Server specific types to data type attributes for the ds and
rs namespaces used to serialize an ADO Rowset.
The XSLT file is shown in Example 5-10
.
Example 5-10. File: Orders.xslt
<?xml version="1.0" ?>
<xsl:stylesheet xmlns:xsl="
xmlns:rs="urn:schemas-microsoft-com:rowset"
xmlns:z="#RowsetSchema"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:wxh="
version="1.0">
<msxsl:script language="CSharp" implements-prefix="wxh">
<![CDATA[
private String GetShortTime(String longDateTime)
{
return longDateTime.Substring(0,19);
}
]]>
</msxsl:script>
<xsl:output method="xml" indent="yes" />
<xsl:template match="NewDataSet">
<rs:data>
<xsl:apply-templates select="Orders" />
</rs:data>
</xsl:template>
<xsl:template match="Orders">
<z:row>
<xsl:apply-templates select="@OrderID" />
<xsl:apply-templates select="@CustomerID" />
<xsl:apply-templates select="@EmployeeID" />
<xsl:apply-templates select="@OrderDate" />
<xsl:apply-templates select="@RequiredDate" />
<xsl:apply-templates select="@ShippedDate" />
<xsl:apply-templates select="@ShipVia" />
<xsl:apply-templates select="@Freight" />
<xsl:apply-templates select="@ShipName" />
<xsl:apply-templates select="@ShipAddress" />
<xsl:apply-templates select="@ShipCity" />
<xsl:apply-templates select="@ShipRegion" />
<xsl:apply-templates select="@ShipPostalCode" />
<xsl:apply-templates select="@ShipCountry" />
</z:row>
</xsl:template>
<xsl:template match="@OrderDate">
<xsl:attribute name="OrderDate">
<xsl:value-of select="wxh:GetShortTime(.)" />
</xsl:attribute>
</xsl:template>
<xsl:template match="@RequiredDate">
<xsl:attribute name="RequiredDate">
<xsl:value-of select="wxh:GetShortTime(.)" />
</xsl:attribute>
</xsl:template>
<xsl:template match="@ShippedDate">
<xsl:attribute name="ShippedDate">
<xsl:value-of select="wxh:GetShortTime(.)" />
</xsl:attribute>
</xsl:template>
<xsl:template match="@*">
<xsl:copy-of select="." />
</xsl:template>
</xsl:stylesheet>
The C# code is shown in Example 5-11
.
Example 5-11. File: ConvertDataSetToAdoRecordsetForm.cs
// Namespaces, variables, and constants
using System;
using System.Configuration;
using System.Windows.Forms;
using System.IO;
using System.Text;
using System.Xml;
using System.Xml.Xsl;
using System.Data;
using System.Data.SqlClient;
using System.Data.OleDb;
private const String ADOXMLFILE =
ConfigurationSettings.AppSettings["Temp_Directory"] + "ADO_Orders.xml";
// . . .
private void goButton_Click(object sender, System.EventArgs e)
{
Cursor.Current = Cursors.WaitCursor;
String sqlText = "SELECT * FROM Orders";
// Create the connection.
SqlConnection conn = new SqlConnection(
ConfigurationSettings.AppSettings["Sql_ConnectString"]);
// Create the command to load all orders records.
SqlCommand cmd = new SqlCommand(sqlText, conn);
conn.Open( );
// Create a DataReader from the command.
SqlDataReader dr = cmd.ExecuteReader(
CommandBehavior.SchemaOnly | CommandBehavior.KeyInfo);
// Create a table of the schema for the DataReader.
DataTable schemaTable = dr.GetSchemaTable( );
// Create an XML document.
XmlDocument xmlDoc = new XmlDocument( );
// Add ADO namespace and schema definition tags to the XML document.
String adoXml =
"<xml xmlns:s = 'uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882' " +
"xmlns:dt = 'uuid:C2F41010-65B3-11d1-A29F-00AA00C14882' " +
"xmlns:rs = 'urn:schemas-microsoft-com:rowset' " +
"xmlns:z = '#RowsetSchema'>" +
"<s:Schema id = 'RowsetSchema'>" +
"<s:ElementType name = 'row' content = 'eltOnly'>" +
"</s:ElementType>" +
"</s:Schema>" +
"</xml>";
xmlDoc.LoadXml(adoXml);
// Create a namespace manager for the XML document.
XmlNamespaceManager nm = new XmlNamespaceManager(xmlDoc.NameTable);
// Add ADO prefixes.
nm.AddNamespace("s", "uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882");
nm.AddNamespace("dt", "uuid:C2F41010-65B3-11d1-A29F-00AA00C14882");
nm.AddNamespace("rs", "urn:schemas-microsoft-com:rowset");
nm.AddNamespace("z", "#RowsetSchema");
// Select the s:ElementType node.
XmlNode curNode = xmlDoc.SelectSingleNode("//s:ElementType", nm);
XmlElement xe = null;
XmlAttribute xa = null;
// Iterate through the schema records for the DataReader.
foreach(DataRow sr in schemaTable.Rows)
{
// Create an 'AttributeType' element for the schema record.
xe = xmlDoc.CreateElement("s", "AttributeType",
"uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882");
// Get the data type.
SqlDbType sqlDbType = (SqlDbType)sr["ProviderType"];
// Create the 'name' attribute.
xa = xmlDoc.CreateAttribute("", "name", "");
xa.Value = sr["ColumnName"].ToString( );
xe.SetAttributeNode(xa);
// Create the 'number' attribute.
xa = xmlDoc.CreateAttribute("rs", "number",
"urn:schemas-microsoft-com:rowset");
xa.Value = ((int)sr["ColumnOrdinal"] + 1).ToString( );
xe.SetAttributeNode(xa);
// Add attribute if null values are allowed in the column.
if((bool)sr["AllowDBNull"])
{
xa = xmlDoc.CreateAttribute("rs", "nullable",
"urn:schemas-microsoft-com:rowset");
xa.Value = sr["AllowDBNull"].ToString().ToLower( );
xe.SetAttributeNode(xa);
}
// Add 'writeunknown' attribute.
xa = xmlDoc.CreateAttribute("rs", "writeunknown",
"urn:schemas-microsoft-com:rowset");
xa.Value = "true";
xe.SetAttributeNode(xa);
// Create a 'datatype' element for the column within the
// 'AttributeType'.
XmlElement dataele = xmlDoc.CreateElement("s", "datatype",
"uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882");
String typeName, dbTypeName;
GetDataTypeInfo(sqlDbType, out typeName, out dbTypeName);
// Add a 'type' attribute specifying the data type.
xa = xmlDoc.CreateAttribute("dt", "type",
"uuid:C2F41010-65B3-11d1-A29F-00AA00C14882");
xa.Value = typeName;
dataele.SetAttributeNode(xa);
// Add a 'dbtype' attribute, if necessary.
if (dbTypeName != "")
{
xa = xmlDoc.CreateAttribute("rs", "dbtype",
"urn:schemas-microsoft-com:rowset");
xa.Value = dbTypeName;
dataele.SetAttributeNode(xa);
}
// Add the 'maxlength' attribute.
xa = xmlDoc.CreateAttribute("dt", "maxLength",
"uuid:C2F41010-65B3-11d1-A29F-00AA00C14882");
xa.Value = sr["ColumnSize"].ToString( );
dataele.SetAttributeNode(xa);
// Add 'scale' and 'precision' attributes, if appropriate.
if(sr["DataType"].ToString( ) != "System.String")
{
if(Convert.ToByte(sr["NumericScale"]) != 255)
{
xa = xmlDoc.CreateAttribute("rs", "scale",
"urn:schemas-microsoft-com:rowset");
xa.Value = sr["NumericScale"].ToString( );
dataele.SetAttributeNode(xa);
}
xa = xmlDoc.CreateAttribute("rs", "precision",
"urn:schemas-microsoft-com:rowset");
xa.Value = sr["NumericPrecision"].ToString( );
dataele.SetAttributeNode(xa);