Solution You must persist the DataSet to XML, transform it to ADO Recordset schema, and load it into an ADO Recordset using COM interop.. The sample uses one XML file: Orders.xslt The
Trang 1[ 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
Trang 2GetDataTypeInfo( )
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="http://www.w3.org/1999/XSL/Transform"
xmlns:rs="urn:schemas-microsoft-com:rowset"
xmlns:z="#RowsetSchema"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:wxh="http://element14.com/wxhnamespace"
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" />
Trang 3<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 =
Trang 4ConfigurationSettings.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");
Trang 5nm.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);
Trang 6// 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);
Trang 7}
// Add a 'fixedlength' attribute, if appropriate
if (sqlDbType != SqlDbType.VarChar &&
sqlDbType != SqlDbType.NVarChar)
{
xa = xmlDoc.CreateAttribute("rs", "fixedlength",
"urn:schemas-microsoft-com:rowset");
xa.Value = "true";
dataele.SetAttributeNode(xa);
}
// Add a 'maybe' null attribute, if appropriate
if(!(bool)sr["AllowDBNull"])
{
xa = xmlDoc.CreateAttribute("rs", "maybenull",
"urn:schemas-microsoft-com:rowset");
xa.Value = sr["AllowDBNull"].ToString().ToLower( ); dataele.SetAttributeNode(xa);
}
// Add the 'datatype' element to the 'AttributeType'
xe.AppendChild(dataele);
// Add the 'AttributeType' element to the 'ElementType' // attribute
curNode.AppendChild(xe);
}
// Add the 'extends' element with attribute 'type" of 'rs:rowbase'
xe = xmlDoc.CreateElement("s", "extends",
"uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882");
xa = xmlDoc.CreateAttribute("", "type", "");
xa.Value = "rs:rowbase";
xe.SetAttributeNode(xa);
curNode.AppendChild(xe);
// Close the reader and connection
dr.Close( );
conn.Close( );
// Load the Orders data into a table in a DataSet
DataSet ds = new DataSet( );
SqlDataAdapter da = new SqlDataAdapter(sqlText,
Trang 8ConfigurationSettings.AppSettings["Sql_ConnectString"]);
da.Fill(ds, "Orders");
// Write the column data as attributes
foreach(DataColumn dc in ds.Tables["Orders"].Columns)
dc.ColumnMapping = MappingType.Attribute;
// Write the DataSet to an XML document
XmlDataDocument ordersXml = new XmlDataDocument(ds);
// Load the XML transformation
XslTransform xslt = new XslTransform( );
xslt.Load(ConfigurationSettings.AppSettings["Project_Directory"] + @"Chapter 05\Orders.xslt");
// Transform the XML document
XmlReader xr = xslt.Transform(ordersXml, null, (XmlResolver)null);
// Load the transformed document into an XML document
XmlDocument resultXmlDoc = new XmlDocument( );
resultXmlDoc.Load(xr);
xr.Close( );
StringBuilder sb = new StringBuilder(xmlDoc.OuterXml);
// Insert the data before the closing </xml> tag
sb.Insert(sb.Length - 6, resultXmlDoc.InnerXml.Remove(8,
resultXmlDoc.InnerXml.IndexOf(">") - 8));
// Make the <z:row> elements self closing
// (ADO import doesn't work otherwise)
sb.Replace("></z:row>","/>");
// Write the order data to a file as ADO XML format
StreamWriter sw = new StreamWriter(ADOXMLFILE);
sw.Write(sb.ToString( ));
sw.Close( );
// Create and open an ADO connection
ADODB.Connection adoConn = new ADODB.Connection( );
adoConn.Open("Provider = SQLOLEDB;Data Source=(local);" + "Initial Catalog=northwind", "sa", "", 0);
// Create the ADO recordset
ADODB.Recordset rs = new ADODB.Recordset( );
try
Trang 9{
// Load the XML into the ADO recordset
rs.Open(ADOXMLFILE,
adoConn,
ADODB.CursorTypeEnum.adOpenStatic,
ADODB.LockTypeEnum.adLockBatchOptimistic,
(int)ADODB.CommandTypeEnum.adCmdFile);
}
catch (System.Exception ex)
{
MessageBox.Show(ex.Message);
adoConn.Close( );
Cursor.Current = Cursors.Default;
return;
}
try
{
// Load the ADO recordset into a DataTable
OleDbDataAdapter oleDa = new OleDbDataAdapter( );
DataTable dt = new DataTable("Orders");
oleDa.Fill(dt, rs);
// Bind the default view of the table to the grid
dataGrid.DataSource = dt.DefaultView;
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
adoConn.Close( );
Cursor.Current = Cursors.Default;
}
dataGrid.CaptionText = "ADO Recordset Serialized as an XML document"; }
private void GetDataTypeInfo(SqlDbType sqlDbType, out String type,
out String dbtype)
Trang 10{
type = "";
dbtype = "";
// Convert the SqlDbType to type attributes in the dt and rs namespaces switch(sqlDbType)
{
case SqlDbType.BigInt:
type = "i8";
break;
case SqlDbType.Binary:
type = "bin.hex";
break;
case SqlDbType.Bit:
type = "Boolean";
break;
case SqlDbType.Char:
type = "string";
dbtype = "str";
break;
case SqlDbType.DateTime:
type = "dateTime";
dbtype = "variantdate";
break;
case SqlDbType.Decimal:
type = "number";
dbtype = "decimal";
break;
case SqlDbType.Float:
type = "float";
break;
case SqlDbType.Image:
type = "bin.hex";
break;
case SqlDbType.Int:
type = "int";
break;
case SqlDbType.Money:
type = "i8";
dbtype = "currency";
break;
case SqlDbType.NChar:
type = "string";