Using the
SQLDataAdapter and the SQLXMLAdapter in a VB.Net Application –
Part 2
By Bill
Wunder
In the Part
one of this article we compared the difference between a joined
table T-SQL query result set and a “shaped” XML query result
set. Then we began the process of creating a VB.Net application
to exploit that “shaped” XML query result set. We looked at
creating a SQLDataAdapter including defining a DataSet class,
instantiating, and even populating an instance of that DataSet.
We even considered why XML data can be problematic when using a
SQLDataAdapter. We examined the .xsd file VB.Net creates for a
DataSet and considered a few ways to modify the .xsd file using
the available Visual Studio Net tools. In this second part,
we’ll turn our attention to using SQLXML 3.0 to populate an .xsd
definition that includes complex data types with a single query,
examine how to load the SQLXML query into an existing VB.Net
DataSet, and see how easy it is to access the query results from
the in-memory and disconnected DataSet.
To start this
exploration we need to add a reference to SQLXML 3.0 to our
project so we can use the SQLXMLAdapter to populate the DataSet.
To add the reference, go to the Solution Explorer, right click
on References in the project and select “Add Reference…” to open
the Add Reference dialog. Browse down to the
Microsoft.Data.SQLXML component on the .Net tab, double click
the entry to select it and hit "OK". Be careful! The list is
pretty long, seems to get longer every day, and there are a few
entries that look an awful lot like SQLXML 3.0 but aren't the
same at all. If you don’t find it in the list it’s probably not
installed on the machine. To install SQLXML3.0 go to the
download page at
http://www.microsoft.com/sql, select the SQLXML 3.0 SP2 link
and select “Open”. Once you do find it and add it to the
project, the project will know all about SQLXML. For your part,
you may want to review the SQLXML 3.0 Documentation file that
was placed on your machine when SQLXML was installed. This will
be your key to getting the most from the tool set now and in the
future.
Next we need
a function that will access the database using SQLXML and
populate our DataSet. I’ll give you a simple function to
accomplish this but please note that if your DataSet class is
named anything other than DataClass1 – which should be the
default name created if you followed along in the previous
article – you’ll need to update the code below to use the
correct name in your project. Right Click on the Form and select
View Code and paste the following function in below the text
“Windows Form Designer Generated Code”:
Private
Function LoadData()
Dim
sSQLServer As
String
Dim
sConnectionString As
String
Dim sCommandString
As
String
Dim sFileName
As
String
Dim strmFile
As System.IO.FileStream
Dim cmd
As
Microsoft.Data.SqlXml.SqlXmlCommand
Dim adapter
As
Microsoft.Data.SqlXml.SqlXmlAdapter
' to keep it simple we'll hardcode
the SQL Server name
' and the database name in the
connection string
Try
sConnectionString = "provider=sqloledb" & _
";data provider=sqloledb" & _
";Server=BILLXP" & _
";database=XMLtest" & _
";Integrated Security=SSPI"
' or for a SQL authenticated
connection
' sConnectionString =
"provider=sqloledb" & _
' ";data
provider=sqloledb" & _
'
";Server=BILLXP" & _
'
";database=XMLtest" & _
' ";User ID=sa" &
_
'
";Password=strongpassword"
' now define the sql command
sCommandString = "Select r.Name " & _
", m.Name " & _
", m.IsOrganic " & _
", m.IsVegan " & _
"from dbo.TB_Restaurant r " & _
"inner join dbo.TB_MenuItem m " & _
"on r.id = m.RestaurantId " & _
"For XML AUTO"
' connect to the SQL Server
cmd
= New
Microsoft.Data.SqlXml.SqlXmlCommand(sConnectionString)
cmd.RootTag = "ArchiveConfiguration"
cmd.OutputEncoding = "utf-8"
cmd.CommandText = sCommandString
cmd.CommandType = Microsoft.Data.SqlXml.SqlXmlCommandType.Sql
adapter = New
Microsoft.Data.SqlXml.SqlXmlAdapter(cmd)
' populate the DataSet
DataSet1.Clear()
adapter.Fill(DataSet1)
' dump the data to the "Output"
window
For
Each dt As DataTable
In DataSet1.Tables
If dt.TableName = "r"
Then
For
Each dr As DataRow
In dt.Rows
Debug.WriteLine(dr("Name"))
Next dr
End
If
Next dt
For
Each dt As DataTable
In DataSet1.Tables
If dt.TableName = "m"
Then
For
Each dr As DataRow
In dt.Rows
Debug.WriteLine(dr("Name") & vbTab & _
dr("IsOrganic") & vbTab & _
dr("IsVegan"))
Next dr
End
If
Next dt
LoadData = True
Catch exSQL
As SqlClient.SqlException
System.Windows.Forms.MessageBox.Show("(LoadData) SQL Error: " &
_
exSQL.Number & " " & _
exSQL.Message, "XML
Test")
End
Try
End
Function
Remember, make
sure the name of your DataSet class replaces the name DataSet1
where it occurs in this routine if your DataSet class is not
named DataSet1. It’s also worth mentioning that as you get
familiar with using namespaces in VB.Net you can avoid fully
qualified namespaces such as I use in this example by using the
Imports statement to declare namespaces in your
code. See the Imports documentation in the
Visual Studio documentation for more on this topic.
In order to
get the function to run without obscuring our DataAdapter
focused discussion with something like data grids or adding
other Windows Forms processing to this example, the next thing
we want to do is to click the + box in front of the text
“Windows Form Designer Generated Code” to expand the
system generated code. Look it over to see everything Visual
Studio auto generated when you added the “Windows Application”
form to your project. At the beginning of this code you’ll find
the "New" subroutine. As a rule, about the only place you’ll
ever want to make a change to the auto generated code is to add
initialization code to this subroutine and then only after the
call to InitializeComponent. An example would be if your
application needs to list the SQL Servers available on the
network in a drop down box, you could load that list here. This
is also a good place to add a call to a class or other test code
when you want the windows application be act as a stub for
testing some functionality in preliminary development efforts.
Here, I’m going to use Sub New to execute the LoadData Function
and output the debug information it produces. To do this all we
need to do is add a call to the LoadData Function in the space
that allows you to add initialization code. While it’s not
exactly the same thing, this will cause the function to run when
the application starts in a similar fashion to the load event
familiar to VB6 users. You could also use the form’s load event
but I can save a couple lines of code by using the
initialization routine in this example.
Public
Sub
New()
MyBase.New()
'This call is required by the Windows
Form Designer.
InitializeComponent()
'Add any initialization after the
InitializeComponent() call
addà
LoadData()
End
Sub
At this point
you should be able to execute the VB.Net application by hitting
F5 and the empty form will load to your desktop. Then if you
look at Visual Studio .Net 2003 Output window you should see the
results of the query as read from the in-memory DataSet and
dumped using the debug.writeln statements.
And there you
have it, an example of the easiest way of designing and
populating a DataSet from a SQL Server using the DataAdapter
wizard and an example of a code based population of an existing
DataSet using SQLXML extensions. One thing you might be
interested to know is that this example will run against a SQL
Server 2000 and against Yukon beta1. That’s worth mentioning
because you now know that just by reading this article you are
on your way to being able to use some of those new features
coming in Yukon.
Bill