<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>SQL Developer - Connecting Databases : ADO</title><link>http://blogs.msdn.com/selvar/archive/tags/ADO/default.aspx</link><description>Tags: ADO</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>Using ADO in VB and Access</title><link>http://blogs.msdn.com/selvar/archive/2007/11/11/using-ado-in-vb-and-access.aspx</link><pubDate>Sun, 11 Nov 2007 14:50:25 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:6097863</guid><dc:creator>selvar</dc:creator><slash:comments>2</slash:comments><comments>http://blogs.msdn.com/selvar/comments/6097863.aspx</comments><wfw:commentRss>http://blogs.msdn.com/selvar/commentrss.aspx?PostID=6097863</wfw:commentRss><description>&lt;h4&gt;&lt;a name="_Toc422016790"&gt;ActiveX Data Objects (ADO) Overview&lt;/a&gt;&lt;/h4&gt;  &lt;h5&gt;&lt;a name="_Toc422016791"&gt;ActiveX Data Objects (ADO) Design Philosophy&lt;/a&gt;&lt;/h5&gt;  &lt;p&gt;ActiveX Data Objects (ADO) was originally designed as a simple and relatively lightweight COM based database API for use with Active Server Pages (ASP) on Internet Information Server (IIS). ADO was designed from the ground up to be thread-safe, highly memory efficient, and easily remotable (which is highly desired when using any API with IIS). Also, ADO is the first high level API from Microsoft that supports the new OLE DB core API (OLE DB is Microsoft&amp;#8217;s new COM based database core API which is destined to eventually replace the ODBC API). The Microsoft Data Access Group felt that it was a better idea to create a total new API rather than try to extend the existing DAO and RDO API&amp;#8217;s to support OLE DB and the various other &amp;#8220;IIS Friendly&amp;#8221; characteristics. DAO and RDO were written when all of the database clients were single threaded monolithic applications &amp;#8211; hence they were not written from the ground up to be thread safe. Microsoft will continue to support DAO and RDO but no new functionality is planned. The long term plan is to get our customers to migrate to ADO and to focus our efforts on making ADO the high level API of choice for all database clients.&lt;/p&gt;  &lt;h5&gt;&lt;a name="_Toc422016792"&gt;The ADO Object Model Overview&lt;/a&gt;&lt;/h5&gt;  &lt;p&gt;The ADO object model is very simple (3 major objects and 4 minor objects) and fairly simple and intuitive compared to Microsoft&amp;#8217;s previous database object models:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/selvar/WindowsLiveWriter/UsingADOinVBandAccess_F3FF/clip_image002_2.jpg"&gt;&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="150" alt="clip_image002" src="http://blogs.msdn.com/blogfiles/selvar/WindowsLiveWriter/UsingADOinVBandAccess_F3FF/clip_image002_thumb.jpg" width="211" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;b&gt;Connection&lt;/b&gt; - Maintains connection information with the data provider. Includes methods for conducting database transactions (BeginTrans, CommitTrans, RollbackTrans). Includes an Execute method for executing SQL Data Manipulation Language (DML) and Data Definition Language (DDL) statements that do not require parameters. Includes an OpenSchema method for querying a database system for schema (sometimes called meta) information such as lists of system tables, indexes on tables, etc&amp;#8230;&lt;/p&gt;  &lt;p&gt;&lt;b&gt;Command&lt;/b&gt; - Maintains information about a command, such as a query string, parameter definitions, etc. You can execute a command string on a Connection object or a query string as part of opening a Recordset object, without defining a Command object. The Command object is useful where you want to define query parameters, or execute a stored procedure that returns output parameters. Basically, the Command object is useful for preparing a SQL statement and providing parameters to the statement if needed.&lt;/p&gt;  &lt;p&gt;&lt;b&gt;Recordset&lt;/b&gt; - A set of records returned from a query and a cursor into those records. You can open a Recordset (i.e., execute a query) without explicitly opening a Connection object. However, if you do first create a Connection object, you can open multiple Recordset objects on the same connection. The ADO Recordset is very similar to DAO&amp;#8217;s Recordset and RDO&amp;#8217;s rdoResultset object. The ADO Recordset has the additional advantage of allowing complete disconnection from the back-end database system (this is called a &amp;#8220;disconnected&amp;#8221; Recordset) as well as built-in cross-process and cross-machine remotability.&lt;/p&gt;  &lt;p&gt;&lt;b&gt;Field&lt;/b&gt; - Contains information about a single column of data within a Recordset. The Recordset object features a Fields collection to contain all of its Field objects. With the Field object you can gather information about a column in a table, such as the data-type of the column, nullability, and the amount of data it can hold (maximum characters for example). The ADO Field object is similar to both DAO&amp;#8217;s and RDO&amp;#8217;s Field/rdoField objects.&lt;/p&gt;  &lt;p&gt;&lt;b&gt;Parameter&lt;/b&gt; - A single parameter for a parameterized Command. The Command object features a Parameters collection to contain all of its Parameter objects. ADO&amp;#8217;s Parameter&amp;#8217;s collection also has a handy &amp;#8220;auto-populate&amp;#8221; feature which makes it much easier to use with SQL Server stored procedures and for parameterized SQL statements if the driver is sophisticated enough to provide parameter meta-information (SQL Server and Oracle Drivers are good in this respect -- the Microsoft Access ODBC Driver is not as good).&lt;/p&gt;  &lt;p&gt;&lt;b&gt;Error&lt;/b&gt; - Contains extended error information about an error condition raised by the provider. Since a single statement can generate two or more errors, the Errors collection can contain more than one Error object at a time, all of which result from the same incident. Similar to Error/rdoError in DAO/RDO.&lt;/p&gt;  &lt;p&gt;&lt;b&gt;Property&lt;/b&gt; - A provider-defined characteristic of an ADO object. Every ADO object contains a properties collection which can be iterated programmatically.&lt;/p&gt;  &lt;h4&gt;&lt;a name="_Toc422016797"&gt;Connecting To Databases With ADO&lt;/a&gt;&lt;/h4&gt;  &lt;h5&gt;&lt;a name="_Toc422016798"&gt;Connecting using Connection.Open&lt;/a&gt;&lt;/h5&gt;  &lt;p&gt;To connect to a database in ADO, you can use one of two general methods. The first method is to use the Connection.Open method. The resulting opened connection object can be used directly or passed to other ADO objects.&lt;/p&gt;  &lt;p&gt;Note that ADO provides access to both OLE DB providers and ODBC drivers. ADO does this by using a special OLE DB provider that translates ADO&amp;#8217;s OLE DB calls to correspondingly equivalent ODBC calls. This translator provider is code named &amp;#8220;Kangera&amp;#8221;and it&amp;#8217;s provider name is &amp;#8220;MSDASQL&amp;#8221;. The MSDASQL provider is the default provider for ADO. In other words, if you do not explicitly specify a provider, then the MSDASQL provider is used automatically. This makes using ADO with ODBC drivers very straightforward. If the customer understands ODBC connection strings, then connecting to an ODBC driver using ADO will be very simple. Just pass the ODBC connection string as the first parameter to the Connection.Open method:&lt;/p&gt;  &lt;p&gt;Sub ADO_ODBC_CONNECTION_TEST()&lt;/p&gt;  &lt;p&gt;Dim conn As New ADODB.Connection&lt;/p&gt;  &lt;p&gt;conn.Open &amp;quot;DSN=LocalServer;DATABASE=pubs;UID=sa;PWD=;&amp;quot;&lt;/p&gt;  &lt;p&gt;If conn.State = adStateOpen Then&lt;/p&gt;  &lt;p&gt;Debug.Print &amp;quot;Connection successfully opened.&amp;quot;&lt;/p&gt;  &lt;p&gt;Else&lt;/p&gt;  &lt;p&gt;Debug.Print &amp;quot;Connection failed.&amp;quot;&lt;/p&gt;  &lt;p&gt;End If&lt;/p&gt;  &lt;p&gt;End Sub&lt;/p&gt;  &lt;p&gt;If the customer wants to use an OLE DB provider, then the specific provider name must be set to over-ride the MSDASQL default provider. This can be set individually (by using the Provider property of the Connection object) or by adding a PROVIDER= statement to the OLE DB connection string as below:&lt;/p&gt;  &lt;p&gt;Sub ADO_OLEDB_CONNECTION_TEST()&lt;/p&gt;  &lt;p&gt;Dim conn As New ADODB.Connection&lt;/p&gt;  &lt;p&gt;conn.Provider = &amp;quot;SQLOLEDB&amp;quot;&lt;/p&gt;  &lt;p&gt;conn.Open &amp;quot;SERVER=UKDUDE;DATABASE=Pubs;UID=sa;PWD=;&amp;quot;&lt;/p&gt;  &lt;p&gt;If conn.State = adStateOpen Then&lt;/p&gt;  &lt;p&gt;Debug.Print &amp;quot;Connection successfully opened.&amp;quot;&lt;/p&gt;  &lt;p&gt;Else&lt;/p&gt;  &lt;p&gt;Debug.Print &amp;quot;Connection failed.&amp;quot;&lt;/p&gt;  &lt;p&gt;End If&lt;/p&gt;  &lt;p&gt;End Sub&lt;/p&gt;  &lt;p&gt;Once the Connection object is open, you can then pass the connection to an ADO Command or Recordset object by setting the next object&amp;#8217;s ActiveConnection property to the connection object:&lt;/p&gt;  &lt;p&gt;Dim conn As New ADODB.Connection&lt;/p&gt;  &lt;p&gt;Dim rs As ADODB.Recordset&lt;/p&gt;  &lt;p&gt;&amp;#8216; Open connection ...&lt;/p&gt;  &lt;p&gt;Set rs.ActiveConnection = conn&lt;/p&gt;  &lt;p&gt;Please note the use of the &amp;#8220;Set&amp;#8221; keyword here which is required when assigning object type variables in VBA.&lt;/p&gt;  &lt;h5&gt;&lt;a name="_Toc422016799"&gt;Connecting via connection string passed to a Command or Recordset Object&lt;/a&gt;&lt;/h5&gt;  &lt;p&gt;ADO also has a short-hand method of opening a database connection that bypasses the connection object altogether. Both the recordset and the command object allow you to pass in a connection string instead of a connection object to their respective ActiveConnection properties. Just set the Command/Recordset&amp;#8217;s ActiveConnection property to the desired connection string, and the object is ready to use.&lt;/p&gt;  &lt;p&gt;Sub ADO_COMMAND_CONNECTION_TEST()&lt;/p&gt;  &lt;p&gt;Dim cmd As New ADODB.Command&lt;/p&gt;  &lt;p&gt;Dim rs As ADODB.recordset&lt;/p&gt;  &lt;p&gt;Dim strConn As String&lt;/p&gt;  &lt;p&gt;cmd.ActiveConnection = &amp;quot; DRIVER={SQL Server};&amp;quot; &amp;amp; _&lt;/p&gt;  &lt;p&gt;&amp;quot;Server=UKDUDE;DATABASE=pubs;UID=sa;PWD=;&amp;quot;&lt;/p&gt;  &lt;p&gt;cmd.CommandText = &amp;quot;byroyalty&amp;quot;&lt;/p&gt;  &lt;p&gt;cmd.CommandType = adCmdStoredProc&lt;/p&gt;  &lt;p&gt;cmd.Parameters.Refresh&lt;/p&gt;  &lt;p&gt;cmd.Parameters(1).Value = 25&lt;/p&gt;  &lt;p&gt;Set rs = cmd.Execute&lt;/p&gt;  &lt;p&gt;' Recordset now has authors with 25% royalty.....&lt;/p&gt;  &lt;p&gt;End Sub&lt;/p&gt;  &lt;p&gt;Note that here I did not use the &amp;#8220;Set&amp;#8221; keyword as in the previous example. I am assigning a string to a property which is not the same as assigning a VBA object.&lt;/p&gt;  &lt;p&gt;Note that this second method is actually a more desired approach than explicitly using a connection object in code. In general, most ODBC drivers do not support more than one active statement per connection. This means that sharing a single Connection object over more than one Command/Recordset object can cause errors due to multiple active statements running. If the customer uses the connection string approach, then each Command/Recordset object will have it&amp;#8217;s own individual connection object internally and &amp;#8220;multiple active statements per connection&amp;#8221; errors will be avoided.&lt;/p&gt;  &lt;p&gt;&lt;b&gt;     &lt;br /&gt;&lt;/b&gt;&lt;/p&gt;  &lt;h5&gt;&lt;a name="_Toc422016800"&gt;Sample ODBC and OLE DB Connection Strings&lt;/a&gt;&lt;/h5&gt;  &lt;p&gt;Many customers are confused by ODBC and OLE DB connection strings. One of the most helpful articles I found to explain various connection strings is the &amp;#8220;Setting Connection String Parameters in DAO&amp;#8221; whitepaper.&lt;/p&gt;  &lt;p&gt;&lt;a title="http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/dnaraccessdev/html/ODC_MicrosoftOfficeDeveloperForumConnectionStringParametersinMicrosoftAccess.asp" href="http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/dnaraccessdev/html/ODC_MicrosoftOfficeDeveloperForumConnectionStringParametersinMicrosoftAccess.asp"&gt;http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/dnaraccessdev/html/ODC_MicrosoftOfficeDeveloperForumConnectionStringParametersinMicrosoftAccess.asp&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Here are some simple examples to connect to various ODBC drivers and OLE DB Providers.&lt;/p&gt;  &lt;p&gt;Microsoft Access:&lt;/p&gt;  &lt;p&gt;ODBC = &amp;#8220;DRIVER={Microsoft Access Driver (*.mdb)};DBQ=C:\NW.MDB&amp;#8221;&lt;/p&gt;  &lt;p&gt;OLE DB = &amp;#8220;PROVIDER=Microsoft.JET.OLEDB.3.51;DATA SOURCE= C:\NW.MDB&amp;#8221;&lt;/p&gt;  &lt;p&gt;Microsoft SQL Server:&lt;/p&gt;  &lt;p&gt;ODBC = &amp;#8220;DRIVER={SQL Server};SERVER=MyServer;DATABASE=pubs;UID=xxx;PWD=yyy;&amp;quot;&lt;/p&gt;  &lt;p&gt;OLE DB = PROVIDER=SQLOLEDB;SERVER=MyServer;DATABASE=pubs;UID=xxx;PWD=yyy;&amp;quot;&lt;/p&gt;  &lt;p&gt;Microsoft Oracle &lt;/p&gt;  &lt;p&gt;ODBC = &amp;#8220;DRIVER={SQL Server};SERVER=MyServer;DATABASE=pubs;UID=xxx;PWD=yyy;&amp;quot;&lt;/p&gt;  &lt;p&gt;OLEDB = &amp;#8220;PROVIDER=MSDAORA;SERVER=MyServer;DATABASE=pubs;UID=xxx;PWD=yyy;&amp;quot;&lt;/p&gt;  &lt;p&gt;Microsoft Excel&lt;/p&gt;  &lt;p&gt;ODBC= &amp;quot;Driver={Microsoft Excel Driver (*.xls)};DBQ=C:\Book1.xls&amp;quot;&lt;/p&gt;  &lt;p&gt;Microsoft FoxPro&lt;/p&gt;  &lt;p&gt;ODBC=&amp;#8221;DRIVER={Microsoft FoxPro Driver (*.dbf)};DBQ=C:\FoxFiles;&amp;#8221;&lt;/p&gt;  &lt;p&gt;&lt;b&gt;     &lt;br /&gt;&lt;/b&gt;&lt;/p&gt;  &lt;h4&gt;&lt;a name="_Toc422016801"&gt;Using the ADO Command Object&lt;/a&gt;&lt;/h4&gt;  &lt;h5&gt;&lt;a name="_Toc422016802"&gt;General Command Object Issues&lt;/a&gt;&lt;/h5&gt;  &lt;p&gt;The ADO Command object is used when one needs to provide parameter information to a stored procedure, a SQL DML statement, or a SQL select statement. Parameters are indicated by embedding a single question mark in the location when the parameter is desired. Parameters can only replace literal values in a SQL statement, they cannot be used to indicate a variable field names for example.&lt;/p&gt;  &lt;p&gt;Here are some example SQL statements that use parameters:&lt;/p&gt;  &lt;p&gt;select * from authors where au_id=&amp;#8217;243-11-2334&amp;#8217;&lt;/p&gt;  &lt;p&gt;select * from authors where au_id=?&lt;/p&gt;  &lt;p&gt;insert into MyTable (field1,field2) values (1,&amp;#8217;hello&amp;#8217;)&lt;/p&gt;  &lt;p&gt;insert into MyTable (field1,field2) values (?,?)&lt;/p&gt;  &lt;p&gt;{call MyStoredProcedure(&amp;#8216;la&amp;#8217;,&amp;#8217;dee&amp;#8217;,&amp;#8217;dah&amp;#8217;)}&lt;/p&gt;  &lt;p&gt;{call MyStoredProcedure(?,?,?)&lt;/p&gt;  &lt;p&gt;Parameter markers are simply replaced from left to right as encountered. The first parameter encountered is parameter 0 (parameter&amp;#8217;s collection is zero based).&lt;/p&gt;  &lt;p&gt;ADO provides an &amp;#8220;auto-populate&amp;#8221; feature for parameters which is quite handy. If the driver supports it, you can call ADO&amp;#8217;s Parameters.Refresh method and this will automatically build the parameters collection for you (rather than manually adding each parameter one at a time programmatically).&lt;/p&gt;  &lt;p&gt;Sub ADO_PARAM_TEST()&lt;/p&gt;  &lt;p&gt;Dim conn As New ADODB.Connection&lt;/p&gt;  &lt;p&gt;Dim cmd As New ADODB.Command&lt;/p&gt;  &lt;p&gt;Dim rs As New ADODB.recordset&lt;/p&gt;  &lt;p&gt;cmd.ActiveConnection = &amp;quot;Driver={SQL Server};&amp;quot; &amp;amp; _&lt;/p&gt;  &lt;p&gt;&amp;quot;Server=UKDUDE;DATABASE=pubs;UID=sa;PWD=;&amp;quot;&lt;/p&gt;  &lt;p&gt;cmd.CommandText = &amp;quot;select * from authors where au_id=?&amp;quot;&lt;/p&gt;  &lt;p&gt;cmd.CommandType = adCmdText&lt;/p&gt;  &lt;p&gt;cmd.Parameters.Refresh &amp;#8216; Auto-populate here&amp;#8230;&lt;/p&gt;  &lt;p&gt;cmd.Parameters(0).Value = &amp;quot;213-46-8915&amp;quot;&lt;/p&gt;  &lt;p&gt;Set rs = cmd.Execute&lt;/p&gt;  &lt;p&gt;' Read record here...&lt;/p&gt;  &lt;p&gt;End Sub&lt;/p&gt;  &lt;p&gt;For more information on manually populating the parameters collection, see the online examples in the ADO documentation. Unfortunately, the Microsoft Access ODBC and OLE DB drivers do not currently support automatic parameter population. This has been submitted as a feature request for future versions of the driver.&lt;/p&gt;  &lt;h5&gt;&lt;/h5&gt; &lt;b&gt;   &lt;br /&gt;&lt;/b&gt;  &lt;h5&gt;&lt;a name="_Toc422016803"&gt;Using Stored Procedures With Command Objects&lt;/a&gt;&lt;/h5&gt;  &lt;p&gt;When calling a stored procedures using the Command object, set the Command&amp;#8217;s CommandText to just the name of the stored procedure, then set the CommandType property to the adCmdStoredProc constant to let ADO now that the SQL statement in the CommandText property is a stored procedure.&lt;/p&gt;  &lt;p&gt;Sub ADO_STORED_PROC_TEST()&lt;/p&gt;  &lt;p&gt;Dim conn As New ADODB.Connection&lt;/p&gt;  &lt;p&gt;Dim cmd As New ADODB.Command&lt;/p&gt;  &lt;p&gt;Dim rs As New ADODB.recordset&lt;/p&gt;  &lt;p&gt;cmd.ActiveConnection = &amp;quot;Driver={SQL Server};&amp;quot; &amp;amp; _&lt;/p&gt;  &lt;p&gt;&amp;quot;Server=UKDUDE;DATABASE=pubs;UID=sa;PWD=;&amp;quot;&lt;/p&gt;  &lt;p&gt;cmd.CommandText = &amp;quot;byroyalty&amp;quot;&lt;/p&gt;  &lt;p&gt;cmd.CommandType = adCmdStoredProc&lt;/p&gt;  &lt;p&gt;cmd.Parameters.Refresh&lt;/p&gt;  &lt;p&gt;' Skip parameter 0 which is the return value!&lt;/p&gt;  &lt;p&gt;cmd.Parameters(1).Value = 25&lt;/p&gt;  &lt;p&gt;rs.Open cmd, , adOpenStatic, adLockOptimistic, -1&lt;/p&gt;  &lt;p&gt;End Sub&lt;/p&gt;  &lt;p&gt;You can determine which parameters are bound by running the code example in the following KB article against your particular stored procedure:&lt;/p&gt;  &lt;p&gt;HOWTO: Determine How ADO Will Bind Parameters&lt;/p&gt;  &lt;p&gt;&lt;a title="http://support.microsoft.com/kb/q181199/" href="http://support.microsoft.com/kb/q181199/"&gt;http://support.microsoft.com/kb/q181199/&lt;/a&gt;&lt;/p&gt;  &lt;h4&gt;&lt;a name="_Toc422016804"&gt;Using The ADO Recordset Object&lt;/a&gt;&lt;/h4&gt;  &lt;h5&gt;&lt;a name="_Toc422016805"&gt;General Recordset Issues&lt;/a&gt;&lt;/h5&gt;  &lt;p&gt;The ADO Recordset object is very similar to the Recordset objects in Microsoft&amp;#8217;s previous database API&amp;#8217;s. The Recordset has the concept of a &amp;#8220;current record&amp;#8221; or &amp;#8220;record pointer&amp;#8221; which points to the currently selected record. The programmer can move the current record pointer forwards and backwards by using the MoveNext and MovePrevious methods. In most cases the developer simply loops through a set of records until the Recordset EOF flag is set to True:&lt;/p&gt;  &lt;p&gt;Dim rs As New ADODB.Recordset&lt;/p&gt;  &lt;p&gt;rs.ActiveConnection = &amp;quot;Driver={SQL Server};&amp;quot; &amp;amp; _&lt;/p&gt;  &lt;p&gt;&amp;quot;Server=UKDUDE;DATABASE=pubs;UID=sa;PWD=;&amp;quot;&lt;/p&gt;  &lt;p&gt;rs.Open &amp;#8220;select * from authors&amp;#8221;&lt;/p&gt;  &lt;p&gt;While Not rs.EOF&lt;/p&gt;  &lt;p&gt;&amp;#8216; Process record here&amp;#8230;&lt;/p&gt;  &lt;p&gt;Rs.MoveNext&lt;/p&gt;  &lt;p&gt;Wend&lt;/p&gt;  &lt;p&gt;The developer can also use the Fields collection to dynamically gather more information about the various columns in the recordset. The Fields collection of the Recordset object allows the &amp;#8220;For Each&amp;#8221; VBA collection syntax which makes coding quite efficient:&lt;/p&gt;  &lt;p&gt;Dim rs As New ADODB.Recordset&lt;/p&gt;  &lt;p&gt;Dim f As ADODB.Field&lt;/p&gt;  &lt;p&gt;&amp;#8216; Open recordset...&lt;/p&gt;  &lt;p&gt;While Not rs.EOF&lt;/p&gt;  &lt;p&gt;For Each f In rs.Fields&lt;/p&gt;  &lt;p&gt;&amp;#8216; Display various field properties.&lt;/p&gt;  &lt;p&gt;Debug.Print f.Name &amp;amp; &amp;#8220;=&amp;#8221; &amp;amp; f.Value&lt;/p&gt;  &lt;p&gt;Next f&lt;/p&gt;  &lt;p&gt;Rs.MoveNext&lt;/p&gt;  &lt;p&gt;Wend&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=6097863" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/selvar/archive/tags/ADO/default.aspx">ADO</category></item><item><title>ADO Cursors</title><link>http://blogs.msdn.com/selvar/archive/2007/11/11/ado-cursors.aspx</link><pubDate>Sun, 11 Nov 2007 13:29:31 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:6095812</guid><dc:creator>selvar</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/selvar/comments/6095812.aspx</comments><wfw:commentRss>http://blogs.msdn.com/selvar/commentrss.aspx?PostID=6095812</wfw:commentRss><description>&lt;p&gt;The CursorLocation and the Cursortype properties of the ADO Recordset object determine what we are allowed to do with our underlying cursor of data.&lt;/p&gt;  &lt;p&gt;These properties help to determine things like whether we can move through the data one time or many times, whether or not we can get a count of the records up-front and even whether or not we can bind our data to a grid. &lt;/p&gt;  &lt;p&gt;The location and the cursor type also affect how well the application will perform and how well you will be able to scale this application. Scalability is a term used to describe how well an application can take on new users without losing performance. For example if I have an application and I add 2000 more users and the application still is as fast as it was with 20 users, this is a very scalable application. &lt;/p&gt;  &lt;p&gt;One very basic example of how the CursorLocation and CursorType can affect the functionality of an application is through the Move methods.&lt;/p&gt;  &lt;p&gt;Have you have ever created an ADO recordset with just the bare minimum of code then tried to use a Move methods to move through the records? You may have found that MoveNext works fine, but if you try to call the MovePrevious method, you get an error.&lt;/p&gt;  &lt;p&gt;Or perhaps you have tried to use the RecordCount property to determine how many records are in the recordset and received a &amp;#8211;1.&lt;/p&gt;  &lt;p&gt;Both of these are the cursor location and cursor type properties in action.&lt;/p&gt;  &lt;p&gt;Let&amp;#8217;s take a look at creating an ADO recordset with some very simple ADO code and see how the CursorLocation and CursorType properties come into play. &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Dim cn As ADODB.Connection     &lt;br /&gt;Dim rs As ADODB.Recordset&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Set cn = New ADODB.Connection     &lt;br /&gt;Set rs = New ADODB.Recordset&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;cn.Open &amp;quot;Provider=SQLOLEDB;Data Source=server;&amp;quot; &amp;amp; _     &lt;br /&gt;&amp;quot;User Id=user1;Password=MyPassword;&amp;quot; &amp;amp; _       &lt;br /&gt;&amp;quot;initial catalog=pubs;&amp;quot;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;rs.Open &amp;quot;select au_fname from authors&amp;quot;, cn&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;In this code we have done the bare minimum to create a recordset. We declared our ADO connection and recordset objects, instantiated them by setting them = to a new connection or recordset object and then opened our connection and recordset.&lt;/p&gt;  &lt;p&gt;Notice that we did not set any properties for the recordset object in this code except those that are absolutely necessary.&lt;/p&gt;  &lt;p&gt;If we attempt to MovePrevious in this recordset we will receive &amp;#8220;Error 3219 The operation is not allowed in this context.&amp;#8221; This is one of the most common issues that new users of ADO see.&lt;/p&gt;  &lt;p&gt;By default, when I create a recordset and I do not explicitely set the cursortype property, we get a cursortype of adOpenForwardOnly.&lt;/p&gt;  &lt;p&gt;This means that I can only move through my records one at a time in a forward only manner. Therefore MovePrevious gives an error. &lt;/p&gt;  &lt;p&gt;So what we see is if we do not explicitly set the cursor type property we get a default value of adOpenForwardOnly and can only make one pass through the records in a forward direction.&lt;/p&gt;  &lt;p&gt;Default values are there to help in ADO so you do not have to set every value, but if you are uncertain what the default values are, you can run into errors.&lt;/p&gt;  &lt;p&gt;Let&amp;#8217;s take a look at the default values on the CursorType and CursorLocation a bit more closely.&lt;/p&gt;  &lt;h5&gt;&lt;u&gt;Default CURSOR values&lt;/u&gt;&lt;/h5&gt;  &lt;p&gt;CursorLocation = adUseServer&lt;/p&gt;  &lt;p&gt;CursorType = adOpenForwardOnly&lt;/p&gt;  &lt;p&gt;LockType = adOpenReadOnly&lt;/p&gt;  &lt;p&gt;When we create a recordset and do not specifically state the cursorlocation, cursortype or the locktype we then receive the default values for these properties.&lt;/p&gt;  &lt;p&gt;The defaults are adUseServer for the cursorlocation. adOpenForwardOnly for the default cursortype which allows us to move through our records in a forward-only manner. &lt;/p&gt;  &lt;p&gt;And although we are not going to discuss this specifically in this webcast, it is worth noting that the locktype on the ADO recordset object is set to adOpenReadOnly by default. So if I tried to update our basic recordset, we would get an error. For more information on the LockType property please see MSDN.&lt;/p&gt;  &lt;p&gt;So by default we get back a recordset that is server-side, Forward-only and Read-only. A Recordset with these properties is a very special recordset that is commonly known as a FireHose Recordset or Firehose Cursor. &lt;/p&gt;  &lt;h5&gt;&lt;u&gt;CursorType Property Values&lt;/u&gt;&lt;/h5&gt;  &lt;p&gt;- Can be set on or before the Open method.&lt;/p&gt;  &lt;p&gt;rs.Open &amp;quot;select au_fname from authors&amp;quot;, cn, adOpenStatic&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;(Or)&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Rs.CursorType = adOpenStatic   &lt;br /&gt;Rs.ActiveConnection = cn    &lt;br /&gt;rs.Open &amp;quot;select au_fname from authors&amp;quot;&lt;/p&gt;  &lt;p&gt;To create another cursor type, we set the CursorType property on the ADO recordset object.&lt;/p&gt;  &lt;p&gt;In the code we see two ways to set this property. &lt;/p&gt;  &lt;p&gt;In the first line we set the third argument to the cursortype we want, in this example we are requesting adOpenStatic.&lt;/p&gt;  &lt;p&gt;The second method shown may be a bit more readable but both function in the same manner. And in this code I am also setting this to adOpenStatic.&lt;/p&gt;  &lt;p&gt;In addition to adOpenStatic shown we also have adOpenForwardOnly our default, adOpenDynamic and adOpenKeyset.&lt;/p&gt;  &lt;p&gt;Each of these provide different functionality. Let&amp;#8217;s first consider adOpenStatic.&lt;/p&gt;  &lt;h4&gt;Cursor Types&lt;/h4&gt;  &lt;h5&gt;&lt;u&gt;Firehose Cursor&lt;/u&gt;&lt;/h5&gt;  &lt;p&gt;- Forward-only, read-only cursor&lt;/p&gt;  &lt;p&gt;- Optimized for SQL Server&amp;#8482;&lt;/p&gt;  &lt;p&gt;- Records are passed over the connection in a stream&lt;/p&gt;  &lt;p&gt;- Move methods give an error message&lt;/p&gt;  &lt;p&gt;- RecordCount property is incorrect&lt;/p&gt;  &lt;p&gt;The Firehose cursor is a forward-only read-only cursor. The name Firehose was given to this since the records are passed over the connection one at a time in a stream of data very much like water going through a FireHose.&lt;/p&gt;  &lt;p&gt;This is the type of cursor that SQL Server is optimized to work with and this type of recordset in general is the fastest performing recordest.&lt;/p&gt;  &lt;p&gt;But with this performance does comes a limitation of functionality. As we noted MovePrevious, MoveFirst and MoveLast will return errors. The recordcount property will return a &amp;#8211;1. This makes sense because the recordset object has no idea how many records are left in the stream on the connection until it hits the end.&lt;/p&gt;  &lt;p&gt;Actually calling this a cursor is really a misnomer because a cursor is never really created in this scenario. We simply get a very quick stream of records from the data base.&lt;/p&gt;  &lt;p&gt;With so many limitations on the methods and properties available, it seems unlikely that a developer would choose to use this cursor, but many do for the reason of performanc. Since the records are streamed across the connection, this makes this a very fast performing cursor. &lt;/p&gt;  &lt;p&gt;Firehose cursors are also very scalable cursors.&lt;/p&gt;  &lt;p&gt;So if you are looking for a quick way to provide data to the user AND they will only need to make one pass through the information, this is your best option.&lt;/p&gt;  &lt;p&gt;If you need to provide more functionality to your user then you will need to specifically request a different cursor type and check to ensure that your data provider will allow this.&lt;/p&gt;  &lt;h5&gt;&lt;u&gt;Static Cursor&lt;/u&gt;&lt;/h5&gt;  &lt;p&gt;- Static copy of the data&lt;/p&gt;  &lt;p&gt;- Cursor is populated with all columns in the results&lt;/p&gt;  &lt;p&gt;- Can be updated&lt;/p&gt;  &lt;p&gt;- Cannot see changes other users make&lt;/p&gt;  &lt;p&gt;- Move methods and RecordCount work&lt;/p&gt;  &lt;p&gt;adOpenStatic when used as the cursor type creates a static copy of the data from the database.&lt;/p&gt;  &lt;p&gt;Many developers think that because this is a static copy of the data that this cursor type is not very useful. But in fact, this particular cursortype is typically the best choice for most applications.&lt;/p&gt;  &lt;p&gt;One of the reasons that this type of cursor is often overlooked is that there is a misconception that you cannot update this. A static cursor when created fetches all rows and all columns from the database and places a copy of this data in a cursor. Since it is a copy many think this cannot be updated, this is not true. A static recordset created using ADO can be updated using the Update and UpdateBatch methods.&lt;/p&gt;  &lt;p&gt;Since it is a copy of the data any changes, additions or deletions that are made to the records since the time the recordset was opened cannot be seen. On the flip side of that also since it is a copy of the data the MoveNext, MovePrevious, MoveFirst and MoveLast all work as expected as does the Recordcount property.&lt;/p&gt;  &lt;p&gt;The static cursor typically provides good performance and this is also the only cursor type that you will get back if you ask for a client-side recordset. We will get to client side recordsets in just a moment. &lt;/p&gt;  &lt;p&gt;If we need to be able to see the changes that other users have made to the records since the recordset was created, we will need to use some other cursor type, one possibility is the Keyset.&lt;/p&gt;  &lt;h5&gt;&lt;u&gt;Keyset Cursor&lt;/u&gt;&lt;/h5&gt;  &lt;p&gt;- Only the keys of the records are returned&lt;/p&gt;  &lt;p&gt;- Shows updates on the data that others have made&lt;/p&gt;  &lt;p&gt;- Does not show other&amp;#8217;s additions and deletions to the data&lt;/p&gt;  &lt;p&gt;- Move methods and RecordCount work&lt;/p&gt;  &lt;p&gt;The Keyset cursortype is by setting the cursortype property to adOpenKeyset.&lt;/p&gt;  &lt;p&gt;When this type of Recordset is retrieved the cursor contains only the key values of the records that meet our criteria will be returned. &lt;/p&gt;  &lt;p&gt;This allows the recordset to show any changes that have been made to the records since the recordset was requested but records that have been added to or deleted from the database will not be shown. &lt;/p&gt;  &lt;p&gt;So when I have a keyset recordset and I begin moving through my records, I move to a record, look at the keyvalue and then find that record with an current changes in the data store. I can move forward and back through the list of keys and also get a recordcount of the number of keys that have been returned.&lt;/p&gt;  &lt;p&gt;So this particular type of cursor provides more functionality than the last two, but I cannot see any additionl or deletions. If I need to see these also I will have to choose a Dynamic Cursor.&lt;/p&gt;  &lt;h5&gt;&lt;u&gt;Dynamic Cursor&lt;/u&gt;&lt;/h5&gt;  &lt;p&gt;- Keys for the rows are retrieved&lt;/p&gt;  &lt;p&gt;- Changes that other users make can be seen&lt;/p&gt;  &lt;p&gt;- Keyset is re-evaluated with each client request&lt;/p&gt;  &lt;p&gt;- Additions and deletions can be seen&lt;/p&gt;  &lt;p&gt;The Dynamic cursor is most like the Keyset cursor in that this returns only a list of the keyvalues that meet the criteria of the query so I can see other user&amp;#8217;s changed. But the big difference here is that the Dynamic cursor will reevaluate the database for any newly added or deleted records with each client request.&lt;/p&gt;  &lt;p&gt;This constant reevaluation of the membership of the cursor impacts the performance of this type of cursor and causes this one to typically have a high overhead and be slow. &lt;/p&gt;  &lt;p&gt;All of these options are pretty clear and this sounds pretty easy, you decide what you need to do with your records and balance this with the performance that you need from the recordset and pick the correct cursor type. But there are limitations to the cursors that you can create and when.&lt;/p&gt;  &lt;h4&gt;&lt;u&gt;Limitations on CursorType&lt;/u&gt;&lt;/h4&gt;  &lt;p&gt;- Dependent upon the provider used&lt;/p&gt;  &lt;p&gt;- Check the CursorType property to confirm&lt;/p&gt;  &lt;p&gt;Rs.open &amp;quot;Select * from authors&amp;quot;, cn   &lt;br /&gt;Debug.Print rs.CursorType&lt;/p&gt;  &lt;p&gt;0 adOpenForwardOnly&lt;/p&gt;  &lt;p&gt;1 adOpenKeyset&lt;/p&gt;  &lt;p&gt;2 adOpenDynamic&lt;/p&gt;  &lt;p&gt;3 adOpenStatic&lt;/p&gt;  &lt;p&gt;- Dependent upon the CursorLocation&lt;/p&gt;  &lt;p&gt;When you set the cursortype in your application, this is simply a request that you are making. And it may not indicate the actual cursor type that you receive. The cursor type that you actually get in your application is dependent upon the data provider and the database that you are using and also the cursor location.&lt;/p&gt;  &lt;p&gt;So let&amp;#8217;s say I create a recordset and I request a keyset cursor but I place this request to XYZ database. ADO will ask the data provider for XYZ database if a keyset cursor is available. XYZ database may come back and say No keyset is not available, but I can give you a static instead. ADO will then create the recordset using the static cursor and continue through the program.&lt;/p&gt;  &lt;p&gt;Some developers have asked why ADO does not give an error in this situation. ADO assumes that you have checked the data provider and the database and you are picking something that you can get back. &lt;/p&gt;  &lt;p&gt;You can check what is returned this by printing the cursortype property after you open the recordset. If we take a look at the code on this slide we see under the second bullet point that I have opened my recordset and then I do a debug.print statement and write out the cursortype property. You will receive an integer value in the the immediate window but you can check in your object browser or on the listing above for the type of cursor you are given. O = forward only, 1 = keyset and so on.&lt;/p&gt;  &lt;p&gt;In addition to the data provider and the data base limiting the cursor type, the cursor type is also limited by the cursor location.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;em&gt;Anytime I specify a cursor location of &lt;u&gt;adUseClient&lt;/u&gt; I get a static cursor no matter what I have specified in the cursor type property.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;h4&gt;&lt;u&gt;CursorLocation Property&lt;/u&gt;&lt;/h4&gt;  &lt;p&gt;- Determines where the records are stored&lt;/p&gt;  &lt;p&gt;- Determines where the processing of the records takes place&lt;/p&gt;  &lt;p&gt;- Two different locations&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;Client&lt;/p&gt; &lt;/blockquote&gt;  &lt;blockquote&gt;   &lt;p&gt;Server&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;- Default is adUseServer&lt;/p&gt;  &lt;p&gt;The cursorlocation property of the ADO Recordset object determines where the records are stored and where the processing of these records will take place.&lt;/p&gt;  &lt;p&gt;There are two options available for the cursor location, adUseClient and adUseServer. Each of the options has certain functionality the back end database.&lt;/p&gt;  &lt;p&gt;If you take a look in the code sample on this slide, we again have two ways to explicitly set the cursor location. The first is using 4th argument on the Open method of the recordset object and the second is to pull out the cursorlocation property and set this. In this code we are setting this to adUseClient. &lt;/p&gt;  &lt;p&gt;Just like the cursortype property the cursorlocation has a default value so this does not have to be set in order for your code to work. The default value for the CursorLocation is adUseServer or server-side cursors.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;rs.Open &amp;quot;select au_fname from authors&amp;quot;, cn, , adUseClient&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;em&gt;(OR)&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Rs.CursorLocation = adUseClient     &lt;br /&gt;Rs.ActiveConnection = cn      &lt;br /&gt;rs.Open &amp;quot;select au_fname from authors&amp;quot;&lt;/strong&gt;&lt;/p&gt;  &lt;h4&gt;&lt;u&gt;Server-Side Recordsets&lt;/u&gt;&lt;/h4&gt;  &lt;p&gt;- Dependent upon the OLE DB Provider and the data store&lt;/p&gt;  &lt;p&gt;- Not available with all data sources&lt;/p&gt;  &lt;p&gt;- Some providers will simulate this functionality&lt;/p&gt;  &lt;p&gt;- SQL Server allows true server-side cursors&lt;/p&gt;  &lt;p&gt;Server-side cursors or recordsets are the default and that sometimes cause confusion. When you begin researching ADO guidelines and even when we discuss some of this guideline here you will notice that we say client-side is better. But server-side is the default. &lt;/p&gt;  &lt;p&gt;A server-side recordset is a recordset where the results of the query are stored and processed on the server. So in an application where I have a client machine that uses ADO to request a cursor of records using a cursor location of adUseServer. The application makes a call to the database and requests the records, the records are then retrieved and stored in the cursor on the server machine. This uses the resources of the server machine to store and process the records. You can imagine that this can cause performance issues for your server.&lt;/p&gt;  &lt;p&gt;Since with a server-side cursor you are expecting a database to have certain functionality, the ability to create a server-side cursor is dependent upon the database you choose. SQL Server allows true server-side cursors, but Access does not. You will want to consult the documentation of your particular database to determine how server-side recordsets are handled. Some database will disallow the use of server-side cursors and some will simulate this functionality.&lt;/p&gt;  &lt;p&gt;Many developers immediately begin to create their application using server-side cursors because these cursors are very fast and this is the only way that you can create a recordset with a cursor type of Keyset, or Dynamic. So the developer determines that is is necessary to see other user&amp;#8217;s changes to records so he makes the decision to use a keyset cursor. He then creates this server-side but has not considered the number of users of the application.&lt;/p&gt;  &lt;p&gt;Remember that server-side cursors rely on the resources of the server to run. So let&amp;#8217;s say we have 500 users of our application all creating server-side recordsets at the same time, as you can imagine this could cause a performance problem on the server.&lt;/p&gt;  &lt;p&gt;So perhaps the developer should have considered a different design using Client-side recordset instead.&lt;/p&gt;  &lt;h4&gt;&lt;u&gt;Client-Side Recordsets&lt;/u&gt;&lt;/h4&gt;  &lt;p&gt;- Records are fetched from the data store and processed on the client machine&lt;/p&gt;  &lt;p&gt;- Very scalable&lt;/p&gt;  &lt;p&gt;- Can only get a static CursorType&lt;/p&gt;  &lt;p&gt;- Can be updated&lt;/p&gt;  &lt;p&gt;When we request a client-side recordset the requested records are streamed back to the client machine and if we check the cursortype property we will always see that we are getting a static cursor.&lt;/p&gt;  &lt;p&gt;When we create a client side ADO recordset, ADO passes our query to the appropriate OLEDB Provider and a copy of the data is returned to the client. ADO then takes these results and stores them on the client machine in ADO&amp;#8217;s very own client cursor engine therefore we must have a static cursor that is maintained on the client. And as we have already discussed our static recordset is scrollable and updatable.&lt;/p&gt;  &lt;p&gt;Since the processing of the records is taking place on the client, in our last example where we had 500 users, we now have this overhead spread out on 500 client machines rather than taking place centrally on the server. Client-side recordsets are a much more scalable solution than serverside.&lt;/p&gt;  &lt;p&gt;Although we will not go through this specifically, it is good to know that when using client side recordsets although they are scalable they also bring concurrency issues to the table in our design plan. Concurrency issues can occur when two user make changes to the same record and then try to update these changes back to the database. The database has to be told how to handle this situation.&lt;/p&gt;  &lt;p&gt;Putting concurrency issues aside, client-side cursors are a good choice for most applications and they allow the database to do what it was designed to do, store information and process queries to return information.&lt;/p&gt;  &lt;p&gt;It is difficult when designing an application to determine how all this works together and what the best options are for you. And the worst part is that no one can tell you specifically what you should do. But in general there are questions we can ask and guidelines we can use to try and get the best possible design.&lt;/p&gt;  &lt;h4&gt;&lt;u&gt;More References&lt;/u&gt;&lt;/h4&gt;  &lt;p&gt;194973 PRB: ADO: Recordcount May Return -1   &lt;br /&gt;&lt;a href="http://support.microsoft.com/?id=194973"&gt;http://support.microsoft.com/?id=194973&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;253248 PRB: Setting the Sort Property of an ADO Recordset Object Causes Error 3251   &lt;br /&gt;&lt;a href="http://support.microsoft.com/?id=253248"&gt;http://support.microsoft.com/?id=253248&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;194610 How To Demonstration of ADO Bookmarks and Move Methods   &lt;br /&gt;&lt;a href="http://support.microsoft.com/?id=194610"&gt;http://support.microsoft.com/?id=194610&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;306385 PRB: CursorType Returns adOpenStatic When You Request adOpenDynamic from   &lt;br /&gt;&lt;a href="http://support.microsoft.com/?id=306385"&gt;http://support.microsoft.com/?id=306385&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;278408 PRB: Cannot Bind OLEDB DataGrid Control to Recordset That Does Not   &lt;br /&gt;&lt;a href="http://support.microsoft.com/?id=278408"&gt;http://support.microsoft.com/?id=278408&lt;/a&gt;&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=6095812" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/selvar/archive/tags/ADO/default.aspx">ADO</category></item><item><title>ADO Model</title><link>http://blogs.msdn.com/selvar/archive/2007/11/11/ado-model.aspx</link><pubDate>Sun, 11 Nov 2007 12:59:28 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:6094984</guid><dc:creator>selvar</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/selvar/comments/6094984.aspx</comments><wfw:commentRss>http://blogs.msdn.com/selvar/commentrss.aspx?PostID=6094984</wfw:commentRss><description>&lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/selvar/WindowsLiveWriter/ADOModel_D95A/image_2.png"&gt;&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="295" alt="image" src="http://blogs.msdn.com/blogfiles/selvar/WindowsLiveWriter/ADOModel_D95A/image_thumb.png" width="406" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=6094984" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/selvar/archive/tags/ADO/default.aspx">ADO</category></item></channel></rss>