<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.orcsweb.com/utility/FeedStylesheets/atom.xsl" media="screen"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en"><title type="html">Brent Gardner's Blog</title><subtitle type="html">It's all about the code.</subtitle><id>http://blogs.orcsweb.com/brent/atom.aspx</id><link rel="alternate" type="text/html" href="http://blogs.orcsweb.com/brent/default.aspx" /><link rel="self" type="application/atom+xml" href="http://blogs.orcsweb.com/brent/atom.aspx" /><generator uri="http://communityserver.org" version="2.1.61129.2">Community Server</generator><updated>2007-04-09T12:54:00Z</updated><entry><title>Copying a WebSite in IIS 5</title><link rel="alternate" type="text/html" href="http://blogs.orcsweb.com/brent/archive/2007/06/26/copying-a-website-in-iis-5.aspx" /><link rel="enclosure" type="application/x-zip-compressed" length="34480" href="http://blogs.orcsweb.com/brent/attachment/2000.ashx" /><id>http://blogs.orcsweb.com/brent/archive/2007/06/26/copying-a-website-in-iis-5.aspx</id><published>2007-06-26T21:25:00Z</published><updated>2007-06-26T21:25:00Z</updated><content type="html">&lt;p&gt;&lt;span style="font-size:10pt;font-family:'Arial','sans-serif';"&gt;IIS 6 was a heck of a product. I particularly like the ability to backup / import individual sites, and the xml based metabase. Unfortunately every once in a while I need to do the same thing in IIS 5. Like when I need to copy the metabase settings from an IIS 5 production server to a IIS 5 dev server to reproduce a bug. Doing this by hand is tedious at best, so I wrote a utility that uses ADSI to scan through the metabase of one server, and copy those entries onto another server. This may be a marginally useful thing with IIS 7 on the way, but I figured I would put it out there in case it would help anyone.&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size:10pt;font-family:'Arial','sans-serif';"&gt;Another nice feature, it *should* work to copy in between IIS 5 &amp;amp; 6, and probably 7. So this might be a nice way to migrate sites to a new version of IIS.&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size:10pt;font-family:'Arial','sans-serif';"&gt;Cheers,&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size:10pt;font-family:'Arial','sans-serif';"&gt;Brent&lt;/span&gt;&lt;/p&gt;&lt;img src="http://blogs.orcsweb.com/aggbug.aspx?PostID=2000" width="1" height="1"&gt;</content><author><name>Brent</name><uri>http://blogs.orcsweb.com/members/Brent.aspx</uri></author></entry><entry><title>Retrieve IUSR Password</title><link rel="alternate" type="text/html" href="http://blogs.orcsweb.com/brent/archive/2007/06/26/retrieve-iusr-password.aspx" /><id>http://blogs.orcsweb.com/brent/archive/2007/06/26/retrieve-iusr-password.aspx</id><published>2007-06-26T18:25:00Z</published><updated>2007-06-26T18:25:00Z</updated><content type="html">&lt;p&gt;&lt;span style="font-size:10pt;font-family:'Arial','sans-serif';"&gt;Anytime you setup a password for a service it gets stored with reversible encryption. The software needs to be able to retrieve the password to log in as that user. IIS is no exception. When you setup the IUSR password, it gets encrypted and stored on disk, but since&amp;nbsp;the encryption&amp;nbsp;is reversible, you can still get at it. MS seems to want to hide this from you: AdsUtil and MetaBaseExplorer have access to the password, but obfuscate it before display. Luckily I wrote my own utility which will let you see the password.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size:10pt;font-family:'Arial','sans-serif';"&gt;If you haven&amp;#39;t yet, just download &lt;a href="http://blogs.orcsweb.com/brent/archive/2007/06/26/adsi-explorer.aspx" title="AdsiExplorer" target="_blank"&gt;&lt;font color="#800080"&gt;AdsiExplorer&lt;/font&gt;&lt;/a&gt;, and browse to your website. The AnonymousUserPass property contains the IUSR password in plain text!&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size:10pt;font-family:'Arial','sans-serif';"&gt;Happy password retrieval,&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size:10pt;font-family:'Arial','sans-serif';"&gt;Brent&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size:10pt;font-family:'Arial','sans-serif';"&gt;&lt;/span&gt;&lt;/p&gt;&lt;img src="http://blogs.orcsweb.com/aggbug.aspx?PostID=1997" width="1" height="1"&gt;</content><author><name>Brent</name><uri>http://blogs.orcsweb.com/members/Brent.aspx</uri></author></entry><entry><title>ADSI Explorer</title><link rel="alternate" type="text/html" href="http://blogs.orcsweb.com/brent/archive/2007/06/26/adsi-explorer.aspx" /><link rel="enclosure" type="application/x-zip-compressed" length="72495" href="http://blogs.orcsweb.com/brent/attachment/1996.ashx" /><id>http://blogs.orcsweb.com/brent/archive/2007/06/26/adsi-explorer.aspx</id><published>2007-06-26T18:13:00Z</published><updated>2007-06-26T18:13:00Z</updated><content type="html">&lt;p class="MsoNormal" style="margin:0in 0in 10pt;"&gt;&lt;span style="font-size:10pt;line-height:115%;font-family:'Arial','sans-serif';"&gt;I&amp;#39;ve seen allot of ADSI related utilies out there. There is metaedit, adsiedit, adsutil.vbs. All of these are either limited (metaedit) or a pain in the butt (adsutil). So I wrote a nice little graphical explorer for ADSI that works much like wbemtest for WMI. It will let you browse Active Directory, IIS, LDAP or whatever. I have attached both the quickly hacked together source and the executable. I&amp;#39;ve found it incredibly useful myself, I hope others find it useful too.&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;img alt="AdsiExplorer" height="673" src="http://blogs.orcsweb.com/brent/attachment/1994.ashx" style="width:913px;height:673px;" title="AdsiExplorer" width="913" /&gt;&lt;/p&gt;&lt;p&gt;Cheers,&lt;/p&gt;&lt;p&gt;&amp;nbsp;Brent&lt;/p&gt;&lt;img src="http://blogs.orcsweb.com/aggbug.aspx?PostID=1996" width="1" height="1"&gt;</content><author><name>Brent</name><uri>http://blogs.orcsweb.com/members/Brent.aspx</uri></author></entry><entry><title>Creating a Hierarchical DataSource from a DataSet</title><link rel="alternate" type="text/html" href="http://blogs.orcsweb.com/brent/archive/2007/06/14/creating-a-hierarchical-datasource.aspx" /><link rel="enclosure" type="application/x-zip-compressed" length="76006" href="http://blogs.orcsweb.com/brent/attachment/1314.ashx" /><id>http://blogs.orcsweb.com/brent/archive/2007/06/14/creating-a-hierarchical-datasource.aspx</id><published>2007-06-15T05:22:00Z</published><updated>2007-06-15T05:22:00Z</updated><content type="html">&lt;p&gt;I&amp;#39;ve already covered creating custom tabular DataSources in previous posts, but sometimes they just aren&amp;#39;t enough. For example, the ASP.NET 2.0 Menu and TreeView controls are designed to bind to a new type of HierarchicalDataSource. &lt;a href="http://weblogs.asp.net/bleroy/archive/2004/09/10/228155.aspx" title="Le Roy"&gt;Bertrand Le Roy&lt;/a&gt;&amp;nbsp;has a fantastic blog post on this. As creative as his example was, I wanted to tweak it a little bit to fit my needs. For example, Mr. Le Roy uses multiple tabular DataSources, and binds them together with his Relation parameters. This seemed a little round-about to me. Why take a DataSet, break it up into tabular DataSources, then combine them again back into a DataSet, when you could just serve up the DataSet whole, and provide much less information to the Controls? Also, the above example did not have a SelectMethod, instead it simply showed the contents of an entire table.&lt;/p&gt;&lt;p&gt;The code to use this control is really straight forward, so rather than go into a detailed analysis, how about a screenshot?&lt;/p&gt;&lt;p&gt;&lt;img height="573" src="http://blogs.orcsweb.com/brent/attachment/1842.ashx" width="650" /&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;You can download the sample project below. It is the same one from my post on the &lt;a href="http://blogs.orcsweb.com/brent/archive/2007/06/14/pre-loading-vs-lazy-loading.aspx"&gt;FriendlyDal&lt;/a&gt;, and it will probably continue to be expanded I blog about more fun stuff.&lt;/p&gt;&lt;p&gt;Cheers,&lt;/p&gt;&lt;p&gt;&amp;nbsp;Brent&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;img src="http://blogs.orcsweb.com/aggbug.aspx?PostID=1314" width="1" height="1"&gt;</content><author><name>Brent</name><uri>http://blogs.orcsweb.com/members/Brent.aspx</uri></author></entry><entry><title>Pre-Loading vs. Lazy Loading</title><link rel="alternate" type="text/html" href="http://blogs.orcsweb.com/brent/archive/2007/06/14/pre-loading-vs-lazy-loading.aspx" /><link rel="enclosure" type="application/x-zip-compressed" length="64915" href="http://blogs.orcsweb.com/brent/attachment/1840.ashx" /><id>http://blogs.orcsweb.com/brent/archive/2007/06/14/pre-loading-vs-lazy-loading.aspx</id><published>2007-06-15T03:54:00Z</published><updated>2007-06-15T03:54:00Z</updated><content type="html">&lt;p class="MsoNormal" style="margin:0in 0in 10pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;color:black;font-family:'Arial','sans-serif';"&gt;Well, it has been a while since my last post. No, I wasn&amp;#39;t in Turkish prison, I just&amp;nbsp;got busy with, well you know,&amp;nbsp;my real job. So I apologize to my regulars (if I have any at this point ;-). But hopefully this post will make up for the delay.&lt;/span&gt;&lt;span style="font-size:12pt;font-family:'Times New Roman','serif';"&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 10pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;color:black;font-family:'Arial','sans-serif';"&gt;I&amp;#39;ve noticed lately (especially with&amp;nbsp;LINQ coming soon), that lazy-loading of data from the database has become the de-facto method for many applications. While this works relatively well when you application has a low-latency connection to the database (i.e. webapps), it is not ideal for client-based applications, where data has to be sent over the Internet and cached on a local machine, until it is synchronized again with the server. Lazy loading also introduces a few issues even when connection latency is low,&amp;nbsp;foremost being that since loading occurs unpredictably throughout your code execution; data may have changed during the load process.&lt;/span&gt;&lt;span style="font-size:12pt;font-family:'Times New Roman','serif';"&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 10pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;color:black;font-family:'Arial','sans-serif';"&gt;Pre-loading data is arguably a cleaner approach, since it can always be born out into a simple set of steps:&lt;/span&gt;&lt;span style="font-size:12pt;font-family:'Times New Roman','serif';"&gt;&lt;/span&gt;&lt;/p&gt;&lt;ol style="margin-top:0in;"&gt;&lt;li class="MsoNormal" style="margin:0in 0in 10pt;color:black;line-height:normal;tab-stops:list .5in;"&gt;&lt;span style="font-size:10pt;font-family:'Arial','sans-serif';"&gt;Load the record you are after, and all its related records (ideally in one transaction)&lt;/span&gt;&lt;/li&gt;&lt;li class="MsoNormal" style="margin:0in 0in 10pt;color:black;line-height:normal;tab-stops:list .5in;"&gt;&lt;span style="font-size:10pt;font-family:'Arial','sans-serif';"&gt;Cache the data in memory while it is displayed and manipulated by the user&lt;/span&gt;&lt;/li&gt;&lt;li class="MsoNormal" style="margin:0in 0in 10pt;color:black;line-height:normal;tab-stops:list .5in;"&gt;&lt;span style="font-size:10pt;font-family:'Arial','sans-serif';"&gt;Persist the data back to the server, wrapped in a transaction, with optimistic concurrency checks&lt;/span&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p class="MsoNormal" style="margin:0in 0in 10pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;color:black;font-family:'Arial','sans-serif';"&gt;This three step process always ensures that data is read and written at the same time, reducing over-head, and ensuring that all data is from a particular snapshot in time. Unfortunately it can be extremely cumbersome to write the necessary SQL to load not only a record, but all of its parents, pertinent children, and type-table entries necessary for a given web page or windows form to work properly. This rather difficult step has lead the way to the domination of the lazy-loading approach -- but it doesn&amp;#39;t have to be so. If there was a convent way (i.e. not involving hundreds of lines of SQL) to load all the records related to a particular target record (or records), then step #1 would become simple.&lt;/span&gt;&lt;span style="font-size:12pt;font-family:'Times New Roman','serif';"&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 10pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;color:black;font-family:'Arial','sans-serif';"&gt;All of which are reasons why I wrote a class to perform automated related record loading. Its called FriendlyLoader, and it can take a simple SQL query, for a single record (or more), and parse the relationships in the DataSet, loading all parent records and (optionally) child records as well. This allows you to easily pull back an entire chunk of the database, bring it to the client-side, manipulate it as need be, then persist it back again. But why stop with making the retrieval of data convenient? FriendlyLoader also has a companion class, Persistor, which persists data in appropriate order, inserting parents first, deleting children first, etc. It&amp;#39;s a one-stop shop for convenient loading and persistence of DataSets!&lt;/span&gt;&lt;span style="font-size:12pt;font-family:'Times New Roman','serif';"&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 10pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;color:black;font-family:'Arial','sans-serif';"&gt;So, on to syntax; basically the FriendlyLoader class simply consists of one public method (with various overrides). The most basic of these just accepts a DataSet to fill, a string containing the SQL command to fill it, a SqlConnection to the DB, and the names of the tables (in order) that it will be filling.&lt;/span&gt;&lt;span style="font-size:12pt;font-family:'Times New Roman','serif';"&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 10pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;color:black;font-family:'Arial','sans-serif';"&gt;So, if you&amp;rsquo;re select command is&lt;/span&gt;&lt;span style="font-size:10pt;color:blue;font-family:'Arial','sans-serif';"&gt;:&lt;/span&gt;&lt;span style="font-size:12pt;font-family:'Times New Roman','serif';"&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 10pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;color:blue;font-family:'Courier New';"&gt;select&lt;/span&gt;&lt;span style="font-size:10pt;font-family:'Courier New';"&gt; &lt;span style="color:gray;"&gt;*&lt;/span&gt; &lt;span style="color:blue;"&gt;from&lt;/span&gt; Customers&lt;/span&gt;&lt;span style="font-size:12pt;font-family:'Times New Roman','serif';"&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;color:blue;font-family:'Courier New';"&gt;select&lt;/span&gt;&lt;span style="font-size:10pt;font-family:'Courier New';"&gt; &lt;span style="color:gray;"&gt;*&lt;/span&gt; &lt;span style="color:blue;"&gt;from&lt;/span&gt; Employees&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:12pt;font-family:'Times New Roman','serif';"&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Arial','sans-serif';"&gt;Then your TableNames parameter should be &amp;ldquo;Customers,Employees&amp;rdquo;.&lt;/span&gt;&lt;span style="font-size:12pt;font-family:'Times New Roman','serif';"&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Arial','sans-serif';"&gt;No matter which method you call, your SQL command will be executed, then all parent rows will be loaded that are necessary to enable constraints. The various other methods simply include different ways to load optional child rows:&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:12pt;font-family:'Times New Roman','serif';"&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;color:green;font-family:'Courier New';"&gt;&amp;#39; Load only parent rows&lt;/span&gt;&lt;span style="font-size:12pt;font-family:'Times New Roman','serif';"&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;color:blue;font-family:'Courier New';"&gt;Public&lt;/span&gt;&lt;span style="font-size:10pt;font-family:'Courier New';"&gt; &lt;span style="color:blue;"&gt;Shared&lt;/span&gt; &lt;span style="color:blue;"&gt;Sub&lt;/span&gt; ClientFill(&lt;span style="color:blue;"&gt;ByVal&lt;/span&gt; Ds &lt;span style="color:blue;"&gt;As&lt;/span&gt; DataSet, &lt;span style="color:blue;"&gt;ByVal&lt;/span&gt; Sql &lt;span style="color:blue;"&gt;As&lt;/span&gt; &lt;span style="color:blue;"&gt;String&lt;/span&gt;, &lt;span style="color:blue;"&gt;ByVal&lt;/span&gt; Con &lt;span style="color:blue;"&gt;As&lt;/span&gt; SqlConnection, &lt;span style="color:blue;"&gt;ByVal&lt;/span&gt; TableNames &lt;span style="color:blue;"&gt;As&lt;/span&gt; &lt;span style="color:blue;"&gt;String&lt;/span&gt;)&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:12pt;font-family:'Times New Roman','serif';"&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;color:green;font-family:'Courier New';"&gt;&amp;#39; Load all posible child rows&lt;/span&gt;&lt;span style="font-size:12pt;font-family:'Times New Roman','serif';"&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;color:blue;font-family:'Courier New';"&gt;Public&lt;/span&gt;&lt;span style="font-size:10pt;font-family:'Courier New';"&gt; &lt;span style="color:blue;"&gt;Shared&lt;/span&gt; &lt;span style="color:blue;"&gt;Sub&lt;/span&gt; ClientFill(&lt;span style="color:blue;"&gt;ByVal&lt;/span&gt; Ds &lt;span style="color:blue;"&gt;As&lt;/span&gt; DataSet, &lt;span style="color:blue;"&gt;ByVal&lt;/span&gt; Sql &lt;span style="color:blue;"&gt;As&lt;/span&gt; &lt;span style="color:blue;"&gt;String&lt;/span&gt;, &lt;span style="color:blue;"&gt;ByVal&lt;/span&gt; Con &lt;span style="color:blue;"&gt;As&lt;/span&gt; SqlConnection, &lt;span style="color:blue;"&gt;ByVal&lt;/span&gt; TableNames &lt;span style="color:blue;"&gt;As&lt;/span&gt; &lt;span style="color:blue;"&gt;String&lt;/span&gt;, &lt;span style="color:blue;"&gt;ByVal&lt;/span&gt; LoadAllChildren &lt;span style="color:blue;"&gt;As&lt;/span&gt; &lt;span style="color:blue;"&gt;Boolean&lt;/span&gt;)&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:12pt;font-family:'Times New Roman','serif';"&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;color:green;font-family:'Courier New';"&gt;&amp;#39; Load only child rows that reside in tables named in the ChildTableNames parameter&lt;/span&gt;&lt;span style="font-size:12pt;font-family:'Times New Roman','serif';"&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;color:blue;font-family:'Courier New';"&gt;Public&lt;/span&gt;&lt;span style="font-size:10pt;font-family:'Courier New';"&gt; &lt;span style="color:blue;"&gt;Shared&lt;/span&gt; &lt;span style="color:blue;"&gt;Sub&lt;/span&gt; ClientFill(&lt;span style="color:blue;"&gt;ByVal&lt;/span&gt; Ds &lt;span style="color:blue;"&gt;As&lt;/span&gt; DataSet, &lt;span style="color:blue;"&gt;ByVal&lt;/span&gt; Sql &lt;span style="color:blue;"&gt;As&lt;/span&gt; &lt;span style="color:blue;"&gt;String&lt;/span&gt;, &lt;span style="color:blue;"&gt;ByVal&lt;/span&gt; Con &lt;span style="color:blue;"&gt;As&lt;/span&gt; SqlConnection, &lt;span style="color:blue;"&gt;ByVal&lt;/span&gt; TableNames &lt;span style="color:blue;"&gt;As&lt;/span&gt; &lt;span style="color:blue;"&gt;String&lt;/span&gt;, &lt;span style="color:blue;"&gt;ByVal&lt;/span&gt; ChildTableNames &lt;span style="color:blue;"&gt;As&lt;/span&gt; &lt;span style="color:blue;"&gt;String&lt;/span&gt;)&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:12pt;font-family:'Times New Roman','serif';"&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;color:green;font-family:'Courier New';"&gt;&amp;#39; Load only child rows that reside in tables that are related to parent tables by a relation in the RelationNames parameter&lt;/span&gt;&lt;span style="font-size:12pt;font-family:'Times New Roman','serif';"&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Courier New';"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color:blue;"&gt;Public&lt;/span&gt; &lt;span style="color:blue;"&gt;Shared&lt;/span&gt; &lt;span style="color:blue;"&gt;Sub&lt;/span&gt; ClientFillByRelation(&lt;span style="color:blue;"&gt;ByVal&lt;/span&gt; Ds &lt;span style="color:blue;"&gt;As&lt;/span&gt; DataSet, &lt;span style="color:blue;"&gt;ByVal&lt;/span&gt; Sql &lt;span style="color:blue;"&gt;As&lt;/span&gt; &lt;span style="color:blue;"&gt;String&lt;/span&gt;, &lt;span style="color:blue;"&gt;ByVal&lt;/span&gt; Con &lt;span style="color:blue;"&gt;As&lt;/span&gt; SqlConnection, &lt;span style="color:blue;"&gt;ByVal&lt;/span&gt; TableNames &lt;span style="color:blue;"&gt;As&lt;/span&gt; &lt;span style="color:blue;"&gt;String&lt;/span&gt;, &lt;span style="color:blue;"&gt;ByVal&lt;/span&gt; RelationNames &lt;span style="color:blue;"&gt;As&lt;/span&gt; &lt;span style="color:blue;"&gt;String&lt;/span&gt;)&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:12pt;font-family:'Times New Roman','serif';"&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;color:green;font-family:'Courier New';"&gt;&amp;#39; Load only child rows that reside in tables named in the list of tables&lt;/span&gt;&lt;span style="font-size:12pt;font-family:'Times New Roman','serif';"&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;color:blue;font-family:'Courier New';"&gt;Public&lt;/span&gt;&lt;span style="font-size:10pt;font-family:'Courier New';"&gt; &lt;span style="color:blue;"&gt;Shared&lt;/span&gt; &lt;span style="color:blue;"&gt;Sub&lt;/span&gt; ClientFill(&lt;span style="color:blue;"&gt;ByVal&lt;/span&gt; Ds &lt;span style="color:blue;"&gt;As&lt;/span&gt; DataSet, &lt;span style="color:blue;"&gt;ByVal&lt;/span&gt; Sql &lt;span style="color:blue;"&gt;As&lt;/span&gt; &lt;span style="color:blue;"&gt;String&lt;/span&gt;, &lt;span style="color:blue;"&gt;ByVal&lt;/span&gt; Con &lt;span style="color:blue;"&gt;As&lt;/span&gt; SqlConnection, &lt;span style="color:blue;"&gt;ByVal&lt;/span&gt; TableNames &lt;span style="color:blue;"&gt;As&lt;/span&gt; &lt;span style="color:blue;"&gt;String&lt;/span&gt;, &lt;span style="color:blue;"&gt;ByVal&lt;/span&gt; ChildTables &lt;span style="color:blue;"&gt;As&lt;/span&gt; List(&lt;span style="color:blue;"&gt;Of&lt;/span&gt; DataTable))&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:12pt;font-family:'Times New Roman','serif';"&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;color:green;font-family:'Courier New';"&gt;&amp;#39; Load only child rows that reside in tables that are related to parent tables by a relation in the list of relations&lt;/span&gt;&lt;span style="font-size:12pt;font-family:'Times New Roman','serif';"&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Courier New';"&gt;&amp;nbsp;&amp;nbsp; &lt;span style="color:blue;"&gt;Public&lt;/span&gt; &lt;span style="color:blue;"&gt;Shared&lt;/span&gt; &lt;span style="color:blue;"&gt;Sub&lt;/span&gt; ClientFill(&lt;span style="color:blue;"&gt;ByVal&lt;/span&gt; Ds &lt;span style="color:blue;"&gt;As&lt;/span&gt; DataSet, &lt;span style="color:blue;"&gt;ByVal&lt;/span&gt; Sql &lt;span style="color:blue;"&gt;As&lt;/span&gt; &lt;span style="color:blue;"&gt;String&lt;/span&gt;, &lt;span style="color:blue;"&gt;ByVal&lt;/span&gt; Con &lt;span style="color:blue;"&gt;As&lt;/span&gt; SqlConnection, &lt;span style="color:blue;"&gt;ByVal&lt;/span&gt; TableNames &lt;span style="color:blue;"&gt;As&lt;/span&gt; &lt;span style="color:blue;"&gt;String&lt;/span&gt;, &lt;span style="color:blue;"&gt;ByVal&lt;/span&gt; ChildRelations &lt;span style="color:blue;"&gt;As&lt;/span&gt; List(&lt;span style="color:blue;"&gt;Of&lt;/span&gt; DataRelation))&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Courier New';"&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:12pt;font-family:'Times New Roman','serif';"&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 10pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Arial','sans-serif';"&gt;If you are still paying attention at this point, you may wonder why the LoadAllChildren=True doesn&amp;rsquo;t just load the entire database. The answer lies in the execution order. First your SQL statement is run, after that all children are loaded, then children&amp;rsquo;s children, and so on.&amp;nbsp; Lastly all necessary parent rows are loaded. So theoretically, if all the records in your DB are descended from one parent record, then yes, it could load your whole database, but if your query is fairly specific, then relatively few rows will be loaded. &lt;/span&gt;&lt;span style="font-size:12pt;font-family:'Times New Roman','serif';"&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 10pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Arial','sans-serif';"&gt;This is definitely something to watch out for when loading tables that are high in the genealogy of the DB. &amp;ldquo;select * from Customers&amp;rdquo; with LoadAllChildren=True would load all Invoices and InvoiceItems as well. So when loading a table that is known to have hundreds of thousands of children, it is probably best to use one of the methods that lets you more specifically identify which children should be loaded.&lt;/span&gt;&lt;span style="font-size:12pt;font-family:'Times New Roman','serif';"&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 10pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Arial','sans-serif';"&gt;One other thing to note:&amp;nbsp; type tables are treated differently than all other tables (object tables, link tables, etc). If a Table has its IsTypeTable property set to True, than all of its contents will be loaded with every query. This is done to accommodate constraints, and also to provide appropriate data to fill DropDown boxes.&lt;/span&gt;&lt;span style="font-size:12pt;font-family:'Times New Roman','serif';"&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 10pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Arial','sans-serif';"&gt;Ok, that about does it for this post. There is a demonstration project in a zip file below, feel free to download it and play around. You will need a copy of the Northwind DB and a SQL server of some kind. Also, as usual, this code is provided as-is and without warranty. Use it if you like, but be sure to test thoroughly first!&lt;/span&gt;&lt;span style="font-size:12pt;font-family:'Times New Roman','serif';"&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 10pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Arial','sans-serif';"&gt;Until next time,&lt;/span&gt;&lt;span style="font-size:12pt;font-family:'Times New Roman','serif';"&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 10pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Arial','sans-serif';"&gt;Brent&lt;/span&gt;&lt;span style="font-size:12pt;font-family:'Times New Roman','serif';"&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 10pt;"&gt;&lt;font face="Calibri" size="3"&gt;&amp;nbsp;&lt;/font&gt;&lt;/p&gt;&lt;img src="http://blogs.orcsweb.com/aggbug.aspx?PostID=1840" width="1" height="1"&gt;</content><author><name>Brent</name><uri>http://blogs.orcsweb.com/members/Brent.aspx</uri></author></entry><entry><title>Combining the DataGrid and DetailsView</title><link rel="alternate" type="text/html" href="http://blogs.orcsweb.com/brent/archive/2007/04/21/combining-the-datagrid-and-detailsview2.aspx" /><link rel="enclosure" type="application/x-zip-compressed" length="20453" href="http://blogs.orcsweb.com/brent/attachment/1346.ashx" /><id>http://blogs.orcsweb.com/brent/archive/2007/04/21/combining-the-datagrid-and-detailsview2.aspx</id><published>2007-04-21T23:51:00Z</published><updated>2007-04-21T23:51:00Z</updated><content type="html">&lt;p&gt;Web pages in data-driven web applications can pretty much be reduced down to two types: list pages and edit pages.&amp;nbsp;If you can view a list of objects, create a&amp;nbsp;new object,&amp;nbsp;and update&amp;nbsp;and delete existing objects, then you&amp;nbsp;have all the components of a CRUD (create, read, update, delete). If you are&amp;nbsp;a web developer, you have probably spent countless hours creating and re-creating similar pages to do these four tasks. Some upcoming tools (like BLINQ) look to help in this regard, but for now we are more or less on our own.&lt;/p&gt;&lt;p&gt;The introduction of the DataGrid in ASP.NET 2.0 was an exciting event. It took care of three steps of the CRUD for us: It can list objects, edit them, and delete them. Unfortunately it lacks any kind of create. For create operations, you have to redirect to a page with a DetailsView. And, truth-be-told, the update on the DataGrid control is pretty un-friendly, since if you have more than a few fields, it becomes be wider than any user&amp;#39;s screen. So we are pretty much stuck making two pages for each object:&amp;nbsp;a list/delete page with a GridView, and an create/update page with a DetailsView. &lt;/p&gt;&lt;p&gt;Wouldn&amp;#39;t it be nice to halve your work by only having one page per object? That sort of thinking led me to create a ComboGrid control which, as the name implies, consists principally of a GridView, but switches to a DetailsView on edit and insert. This sweet little guy has saved me a bunch of work, and reduced the amount of web pages I&amp;#39;ve had to create. So I figured I would post the code, so that it can help other people as well. If it isn&amp;#39;t directly helpful, then perhaps at least it will be a good starting point for others, or a&amp;nbsp;useful insight into how these controls work behind the scenes.&lt;/p&gt;&lt;p&gt;A few notes:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;The ComboMaster is the primary control&lt;/li&gt;&lt;li&gt;It instantiates the ComboGrid and ComboView and necessary&lt;/li&gt;&lt;li&gt;It is bindable in the same ways as either of the controls it represents (DataSource, DataSourceId)&lt;/li&gt;&lt;li&gt;It uses the Columns collection for its properties, as opposed to the Fields collection&lt;/li&gt;&lt;li&gt;It only supports TemplateFields for the moment. (Why? Because I haven&amp;#39;t gotten around to any others yet)&lt;/li&gt;&lt;li&gt;I&amp;#39;ve been using this one for a bit, so it is pretty stable, but as usual, this is intended primarily for example purposes, and comes with no warranty&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;a href="http://blogs.orcsweb.com/brent/attachment/1346.ashx"&gt;Download the Sample Code!&lt;/a&gt;&lt;/p&gt;&lt;p&gt;- Brent&lt;/p&gt;&lt;img src="http://blogs.orcsweb.com/aggbug.aspx?PostID=1346" width="1" height="1"&gt;</content><author><name>Brent</name><uri>http://blogs.orcsweb.com/members/Brent.aspx</uri></author></entry><entry><title>.NET Sid2User and User2Sid</title><link rel="alternate" type="text/html" href="http://blogs.orcsweb.com/brent/archive/2007/04/20/net-sid2user-and-user2sid.aspx" /><id>http://blogs.orcsweb.com/brent/archive/2007/04/20/net-sid2user-and-user2sid.aspx</id><published>2007-04-20T21:22:00Z</published><updated>2007-04-20T21:22:00Z</updated><content type="html">&lt;p&gt;Every once in a while, I have to resolve a SID (Windows Security IDentifier) to its corresponding user. Throughout the years I&amp;#39;ve had to do this with the &lt;a href="http://msdn2.microsoft.com/en-us/library/aa379159.aspx"&gt;LookupAccountName&lt;/a&gt;&amp;nbsp;API call, be it through C++, VB 6, etc. I was doing it that way in .NET, until&amp;nbsp;&lt;a href="http://blogs.orcsweb.com/steve/default.aspx"&gt;Steve Schofield&lt;/a&gt; altered me to a post on &lt;a href="http://forums.iis.net/"&gt;forums.iis.net&lt;/a&gt; this morning. A bit of sample code from that site made me realize there was a much easier way to do Sid2User and User2Sid resolution in .NET:&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;color:blue;font-family:'Courier New';"&gt;Public&lt;/span&gt;&lt;span style="font-size:10pt;font-family:'Courier New';"&gt; &lt;span style="color:blue;"&gt;Shared&lt;/span&gt; &lt;span style="color:blue;"&gt;Function&lt;/span&gt; SidToUser(&lt;span style="color:blue;"&gt;ByVal&lt;/span&gt; Sid &lt;span style="color:blue;"&gt;As&lt;/span&gt; &lt;span style="color:blue;"&gt;String&lt;/span&gt;) &lt;span style="color:blue;"&gt;As&lt;/span&gt; &lt;span style="color:blue;"&gt;String&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;color:blue;font-family:'Courier New';"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;Dim&lt;/span&gt;&lt;span style="font-size:10pt;font-family:'Courier New';"&gt; Si &lt;span style="color:blue;"&gt;As&lt;/span&gt; &lt;span style="color:blue;"&gt;New&lt;/span&gt; SecurityIdentifier(SID)&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Courier New';"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color:blue;"&gt;Dim&lt;/span&gt; Nta &lt;span style="color:blue;"&gt;As&lt;/span&gt; NTAccount = &lt;span style="color:blue;"&gt;CType&lt;/span&gt;(Si.Translate(&lt;span style="color:blue;"&gt;GetType&lt;/span&gt;(NTAccount)), NTAccount)&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Courier New';"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color:blue;"&gt;Return&lt;/span&gt; Nta.Value&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;color:blue;font-family:'Courier New';"&gt;End&lt;/span&gt;&lt;span style="font-size:10pt;font-family:'Courier New';"&gt; &lt;span style="color:blue;"&gt;Function&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;color:blue;font-family:'Courier New';"&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;color:blue;font-family:'Courier New';"&gt;Public&lt;/span&gt;&lt;span style="font-size:10pt;font-family:'Courier New';"&gt; &lt;span style="color:blue;"&gt;Shared&lt;/span&gt; &lt;span style="color:blue;"&gt;Function&lt;/span&gt; UserToSid(&lt;span style="color:blue;"&gt;ByVal&lt;/span&gt; Username &lt;span style="color:blue;"&gt;As&lt;/span&gt; &lt;span style="color:blue;"&gt;String&lt;/span&gt;) &lt;span style="color:blue;"&gt;As&lt;/span&gt; &lt;span style="color:blue;"&gt;String&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Courier New';"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color:blue;"&gt;Dim&lt;/span&gt; Terms() &lt;span style="color:blue;"&gt;As&lt;/span&gt; &lt;span style="color:blue;"&gt;String&lt;/span&gt; = Split(Username, &lt;span style="color:#a31515;"&gt;&amp;quot;\&amp;quot;&lt;/span&gt;)&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Courier New';"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color:blue;"&gt;If&lt;/span&gt; Terms.Length &amp;gt; 1 &lt;span style="color:blue;"&gt;Then&lt;/span&gt; &lt;span style="color:blue;"&gt;Return&lt;/span&gt; UserToSid(Terms(0), Terms(1))&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Courier New';"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color:blue;"&gt;Return&lt;/span&gt; UserToSid(&lt;span style="color:#a31515;"&gt;&amp;quot;&amp;quot;&lt;/span&gt;, Username)&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;color:blue;font-family:'Courier New';"&gt;End&lt;/span&gt;&lt;span style="font-size:10pt;font-family:'Courier New';"&gt; &lt;span style="color:blue;"&gt;Function&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;color:blue;font-family:'Courier New';"&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;color:blue;font-family:'Courier New';"&gt;Public&lt;/span&gt;&lt;span style="font-size:10pt;font-family:'Courier New';"&gt; &lt;span style="color:blue;"&gt;Shared&lt;/span&gt; &lt;span style="color:blue;"&gt;Function&lt;/span&gt; UserToSid(&lt;span style="color:blue;"&gt;ByVal&lt;/span&gt; DomainName &lt;span style="color:blue;"&gt;As&lt;/span&gt; &lt;span style="color:blue;"&gt;String&lt;/span&gt;, &lt;span style="color:blue;"&gt;ByVal&lt;/span&gt; Username &lt;span style="color:blue;"&gt;As&lt;/span&gt; &lt;span style="color:blue;"&gt;String&lt;/span&gt;) &lt;span style="color:blue;"&gt;As&lt;/span&gt; &lt;span style="color:blue;"&gt;String&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Courier New';"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color:blue;"&gt;Dim&lt;/span&gt; Nta &lt;span style="color:blue;"&gt;As&lt;/span&gt; &lt;span style="color:blue;"&gt;New&lt;/span&gt; NTAccount(DomainName, Username)&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Courier New';"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color:blue;"&gt;Dim&lt;/span&gt; Si &lt;span style="color:blue;"&gt;As&lt;/span&gt; SecurityIdentifier = &lt;span style="color:blue;"&gt;CType&lt;/span&gt;(Nta.Translate(&lt;span style="color:blue;"&gt;GetType&lt;/span&gt;(SecurityIdentifier)), SecurityIdentifier)&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Courier New';"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color:blue;"&gt;Return&lt;/span&gt; Si.Value&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;color:blue;font-family:'Courier New';"&gt;End&lt;/span&gt;&lt;span style="font-size:10pt;font-family:'Courier New';"&gt; &lt;span style="color:blue;"&gt;Function&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;Cheers,&lt;/p&gt;&lt;p&gt;- Brent&lt;/p&gt;&lt;img src="http://blogs.orcsweb.com/aggbug.aspx?PostID=1337" width="1" height="1"&gt;</content><author><name>Brent</name><uri>http://blogs.orcsweb.com/members/Brent.aspx</uri></author></entry><entry><title>Strip HTML from a String</title><link rel="alternate" type="text/html" href="http://blogs.orcsweb.com/brent/archive/2007/04/19/strip-html-from-a-string.aspx" /><id>http://blogs.orcsweb.com/brent/archive/2007/04/19/strip-html-from-a-string.aspx</id><published>2007-04-19T17:12:00Z</published><updated>2007-04-19T17:12:00Z</updated><content type="html">&lt;p&gt;While not exactly earth-shattering, I thought I would post some handy code. Recently, I had to save some data from a &lt;a href="http://freetextbox.com/default.aspx" title="FreeTextBox"&gt;FreeTextBox&lt;/a&gt;, in both HTML and plain text form (so that it could be full-text indexed). It looks like there are a number of components out there, but I knew the IE HTML DOM was very liberal in its interpretation of HTML and therefor a good choice, not to mention it would be hard to find a system without this component installed. (Although you need to make an interop reference to mshtml.tlb)&lt;/p&gt;&lt;p&gt;Without further ado, the code:&lt;/p&gt;&lt;font size="2"&gt;&lt;/font&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Courier New';"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color:blue;"&gt;Protected&lt;/span&gt; &lt;span style="color:blue;"&gt;Function&lt;/span&gt; StipHtml(&lt;span style="color:blue;"&gt;ByVal&lt;/span&gt; Html &lt;span style="color:blue;"&gt;As&lt;/span&gt; &lt;span style="color:blue;"&gt;String&lt;/span&gt;) &lt;span style="color:blue;"&gt;As&lt;/span&gt; &lt;span style="color:blue;"&gt;String&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Courier New';"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color:blue;"&gt;Dim&lt;/span&gt; Doc &lt;span style="color:blue;"&gt;As&lt;/span&gt; &lt;span style="color:blue;"&gt;New&lt;/span&gt; mshtml.HTMLDocument()&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Courier New';"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color:blue;"&gt;Dim&lt;/span&gt; d1 &lt;span style="color:blue;"&gt;As&lt;/span&gt; mshtml.IHTMLDocument4 = Doc&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Courier New';"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color:blue;"&gt;Dim&lt;/span&gt; d2 &lt;span style="color:blue;"&gt;As&lt;/span&gt; mshtml.IHTMLDocument4 = Doc&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Courier New';"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;d2.write(Html)&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Courier New';"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;d2.close()&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Courier New';"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color:blue;"&gt;Return&lt;/span&gt; Doc.body.innerText&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Courier New';"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color:blue;"&gt;End&lt;/span&gt; &lt;span style="color:blue;"&gt;Function&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Happy coding,&lt;/p&gt;&lt;p&gt;- Brent&lt;/p&gt;&lt;img src="http://blogs.orcsweb.com/aggbug.aspx?PostID=1329" width="1" height="1"&gt;</content><author><name>Brent</name><uri>http://blogs.orcsweb.com/members/Brent.aspx</uri></author></entry><entry><title>DataSet to Database Persistance, Examined</title><link rel="alternate" type="text/html" href="http://blogs.orcsweb.com/brent/archive/2007/04/19/dataset-to-database-persistance-examined.aspx" /><id>http://blogs.orcsweb.com/brent/archive/2007/04/19/dataset-to-database-persistance-examined.aspx</id><published>2007-04-19T14:47:00Z</published><updated>2007-04-19T14:47:00Z</updated><content type="html">&lt;p&gt;If you already know allot about it, go on an skip this blog. I thought I would cover this topic because I think it is not fully understood by allot of developers, and it is an essential step on the road to developing a full-fledged Data Access Layer (can you guess where this series of posts is headed?).&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Negative Indexes&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;One of the first steps to writing a clean DAL starts with the DataSets themselves. It is a good idea to set all your auto-increment columns to IncrementSeed=-1, IncrementStep=-1. This way, as you add rows to your tables, their PK&amp;#39;s will count: -1, -2, -3. This prevents the rows you are adding in your DataSet from conflicting with the Primary Keys of any new rows added back on the Database server.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Concurrency Checks&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;The SqlDataAdapter class has a wonderful feature, which is enabled by default, where it examines the number of affected rows reported by SQL. If the number of rows actually updated (always zero or one), doesn&amp;#39;t match the number the DataAdapter was expecting (always one), it throws an exception! This should prevent unexpected results when you update query fails. You can also use it to deliberately throw a ConcurrencyException if the data has changed by adding a where clause to your update query:&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;color:blue;font-family:'Courier New';"&gt;set&lt;/span&gt;&lt;span style="font-size:10pt;font-family:'Courier New';"&gt; @NewDate&lt;span style="color:gray;"&gt;=&lt;/span&gt;&lt;span style="color:fuchsia;"&gt;getdate&lt;/span&gt;&lt;span style="color:gray;"&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;color:blue;font-family:'Courier New';"&gt;update&lt;/span&gt;&lt;span style="font-size:10pt;font-family:'Courier New';"&gt; Employees &lt;span style="color:blue;"&gt;set&lt;/span&gt; &lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Courier New';"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;FirstName&lt;span style="color:gray;"&gt;=&lt;/span&gt;@FirstName&lt;span style="color:gray;"&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Courier New';"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;LastName&lt;span style="color:gray;"&gt;=&lt;/span&gt;@LastName&lt;span style="color:gray;"&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Courier New';"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;LastUpdatedDate&lt;span style="color:gray;"&gt;=&lt;/span&gt;@NewDate&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;color:blue;font-family:'Courier New';"&gt;where&lt;/span&gt;&lt;span style="font-size:10pt;font-family:'Courier New';"&gt; &lt;a href="mailto:EmployeeId=@EmployeeId"&gt;EmployeeId&lt;span style="color:gray;"&gt;=&lt;/span&gt;@EmployeeId&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Courier New';"&gt;&lt;/span&gt;&lt;span style="font-size:10pt;font-family:'Courier New';"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color:gray;"&gt;and&lt;/span&gt; &lt;a href="mailto:LastUpdateDate=@LastUpdatedDate"&gt;LastUpdateDate&lt;span style="color:gray;"&gt;=&lt;/span&gt;@LastUpdatedDate&lt;/a&gt;&lt;/span&gt;&lt;strong&gt;&amp;nbsp;&lt;/strong&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;In this case, if the Employee.LastUpdateDate in the DB doesn&amp;#39;t equal your DataRow.LastUpdateDate, then the query will return zero rows, and the DataAdapter will throw an exception.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Transactions&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;It might be obvious by now, but since the DataAdapter might throw&amp;nbsp;a ConcurrencyException half-way through your update process, you may want to wrap the process in a&amp;nbsp;client-side transaction. That way if any of your updates (or inserts or deletes for that matter)&amp;nbsp;fail, then everything will be rolled back. This is pretty simple in ADO.NET 2.0: Just create a new SqlTransaction object, and pass it to all of your SqlCommands.&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Output Parameters&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;You may have noticed in the above example, that we are updating the DB with the @NewDate parameter, but how might we get that back into our DataSet? If we don&amp;#39;t, then our next update will fail, but surely we don&amp;#39;t want to manually keep a list of all updated rows, and select() them all back from the DB? Well, the DataAdapter makes this easy for us as well. When you add your SqlParameter object to the SqlCommand, you can set it update as an &amp;quot;output&amp;quot; parameter (or even InputOutput). Then you can define the parameter as &amp;quot;output&amp;quot; in your stored procedure, and whatever value it has will be inserted back into your DataRow when the sproc completes. (Same thing goes for non-sproc commands). This is especially handy on inserts. For your insert queries you can simply append: &amp;quot;set @OutputId = @@Identity&amp;quot;, and your -12345 PK in the DataSet will be automatically updated to 3725 or whatever the auto-increment in the DB happens to be set to. Pretty cool huh? Now you see why we use negative keys on the client-side.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;UpdateAction = Cascade&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;We&amp;#39;ve reviewed some pretty cool stuff, but this last bit is killer. Going back to one more DataSet based thing, on all your relationships, you&amp;#39;ll want to set&amp;nbsp;UpdateRule = Cascade. The reason for this, is that when your Employee.EmployeeId=-1 is inserted into the DB, and comes back as an output parameter as Employee.EmployeeId=3725, the UpdateRule=Cascade will go around to all related tables, and change the FK from -1 to 3725 on those as well. So you can insert an Employee into your DataSet, then insert a bunch of EmployeeRole records, then persist them to the DB all at the same time, and when you persist is finished, they will have all gone from fairy-land-style negative keys to real-world values auto-magically! And all your DataSet constraints will remain intact! How cool is that?&lt;/p&gt;&lt;p&gt;&lt;strong&gt;DataRowVersion&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Ok, although maybe not as cool as the last one, the SqlParameter.DataRowVersion is sometimes handy. Lets say you don&amp;#39;t have a handy Employee.LastUpdatedDate field in your table to check for concurrency, but you still want to make sure that no one has updated the record in the DB while you were looking at it. One interesting feature of DataRows is that they track not only what value they have now, but also what value they originally had when you loaded them from the DB. You can create SqlParameters with DataRowVersion=Original, and pass them into your sproc in the where clause. You will be checking many more fields than is probably necessary, but if any of them don&amp;#39;t match, then you can still get the same optimistic concurrency as with UpdatedDate (or Timestamp), but without changing your DB schema.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Persistence Order&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;I might be going a little too far here, but for the sake of completeness, I will mention it. With typed DataSets, you don&amp;#39;t even need to worry about persistence order (i.e. insert Employees first, then insert EmployeeRoles). Since all the relations should have been brought over from the database into your DataSet by the designer, you should have all the info you need to determine parent/child relations, and insert/update/delete in the correct order: Insert parent rows first, update parent rows second &lt;em&gt;(* update, see below),&lt;/em&gt; then delete child rows last. As easy as this sounds, there is actually a good bit of work to it, which I won&amp;#39;t get into here. Instead I will focus on both loading and persistence in my next post, as well as post sample code for a Data Acess Layer that should make both a piece of cake. What&amp;#39;s that? You don&amp;#39;t want to use proprietary code in your application&amp;#39;s DAL? Well if you can sit tight for a little while, ADO.NET 3.5 should include a new feature where it can automatically loop through an entire DataSet persisting rows in the correct order!&lt;/p&gt;&lt;p&gt;Sorry, no code this time :-(&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;Until next time,&lt;/p&gt;&lt;p&gt;- Brent&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Update 6/13/2007&lt;/strong&gt;: &lt;/p&gt;&lt;p&gt;&lt;span style="font-size:10pt;font-family:'Arial','sans-serif';"&gt;In the article above I said to &amp;quot;update parent rows second&amp;quot;. This was how I had my code working until I ran into a situation where two rows were each other&amp;#39;s parents. This threw everything into an infinite loop. If updating PrimaryKeys were possible in DataSets, then there would be problems, but since the ADO guys had the foresight not to allow this, modified rows should be able to be persisted in any order (and should be to avoid infinite loops). More correctly worded, the aforementioned sentence should omit the word &amp;quot;parent&amp;quot; to read: &amp;quot;update modified rows second&amp;quot;.&lt;/span&gt;&lt;/p&gt;&lt;img src="http://blogs.orcsweb.com/aggbug.aspx?PostID=1327" width="1" height="1"&gt;</content><author><name>Brent</name><uri>http://blogs.orcsweb.com/members/Brent.aspx</uri></author></entry><entry><title>Programmatically Generate Typed DataSets</title><link rel="alternate" type="text/html" href="http://blogs.orcsweb.com/brent/archive/2007/04/17/programmatically-generate-typed-datasets.aspx" /><link rel="enclosure" type="application/x-zip-compressed" length="28424" href="http://blogs.orcsweb.com/brent/attachment/1315.ashx" /><id>http://blogs.orcsweb.com/brent/archive/2007/04/17/programmatically-generate-typed-datasets.aspx</id><published>2007-04-18T00:20:00Z</published><updated>2007-04-18T00:20:00Z</updated><content type="html">&lt;p&gt;As perhaps you may have gathered from my DataSetSource post, I think typed DataSets are the bee&amp;#39;s knees. As a general coding practice, I like to write the code-behind-the-code, rather than the code itself, and typed DataSet&amp;#39;s allow me to do this, so I like them very much. That being said, they took a big hit with Visual Studio.NET 2005. I don&amp;#39;t know why exactly, perhaps because of deadlines, the typed DataSet creator in VS 2005 has a few problems. I&amp;#39;ve had it fail to import relations, fail to find new columns, and even dragging a DataTable to a new location can take 15-20 seconds in a large dataset!&amp;nbsp;All in all, VS 2005 was a step backward for this particular tool.&lt;/p&gt;&lt;p&gt;In order to continue using these wonderful classes, despite the &lt;span style="font-size:10pt;line-height:115%;font-family:'Arial','sans-serif';"&gt;idiosyncrasies &lt;/span&gt;of the new tool, I&amp;#39;ve created my own typed DataSet generation utility. It queries the schema of a SQL DB, allows you to select which tables you want to export, then creates the appropriate .vb and .xsd files. Best of all, having the source code, it can be modified to be scripted (perhaps as part of&amp;nbsp;a build script?), run as often as necessary, and modified to suit particular tastes. For example, I have turned GetChildRows() into a property, and used Nullable(Of T) to represent null values, instead of the old &amp;quot;IsMyCollumnNull()&amp;quot; methods.&lt;/p&gt;&lt;p&gt;It&amp;#39;s called the &amp;quot;Enhanced&amp;nbsp;Generator of Advanced Data Sets&amp;quot;, and it looks like this:&lt;/p&gt;&lt;p&gt;&lt;img alt="Egads" height="474" src="http://blogs.orcsweb.com/brent/attachment/1313.ashx" style="width:550px;height:474px;" title="Egads" width="550" /&gt;&lt;/p&gt;&lt;p&gt;To use it, simply:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Enter the path you want it to create its classes under&lt;/li&gt;&lt;li&gt;Enter the connection string to your database&lt;/li&gt;&lt;li&gt;Enter the DataSetName you want your new dataset to be called&lt;/li&gt;&lt;li&gt;Click &amp;quot;Get Tables&amp;quot; - select the tables you want&lt;/li&gt;&lt;li&gt;Click &amp;quot;Generate&amp;quot;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Please Note:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Note that this code is for example purposes only, its meant as a base for you to develop off of, and an example of how to use the CodeDom&lt;/li&gt;&lt;li&gt;You may need to delete / rename / exclude the .xsd file, because Visual Studio tends to want to generate its own code, which will conflict with Egads&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;a href="http://blogs.orcsweb.com/brent/attachment/1315.ashx" title="Egads"&gt;Download Egads!&lt;/a&gt;&lt;/p&gt;&lt;img src="http://blogs.orcsweb.com/aggbug.aspx?PostID=1315" width="1" height="1"&gt;</content><author><name>Brent</name><uri>http://blogs.orcsweb.com/members/Brent.aspx</uri></author></entry><entry><title>ASP.NET Bindable DataSet DataSource</title><link rel="alternate" type="text/html" href="http://blogs.orcsweb.com/brent/archive/2007/04/12/asp-net-datasetsource.aspx" /><link rel="enclosure" type="application/x-zip-compressed" length="11272" href="http://blogs.orcsweb.com/brent/attachment/1273.ashx" /><id>http://blogs.orcsweb.com/brent/archive/2007/04/12/asp-net-datasetsource.aspx</id><published>2007-04-13T03:01:00Z</published><updated>2007-04-13T03:01:00Z</updated><content type="html">&lt;p class="MsoNormal" style="margin:0in 0in 10pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Arial','sans-serif';"&gt;O/R mappers have gotten allot of press lately, and for good reason. They take away much of the busy work of building a data access layer (DAL). They work fantastically for smaller projects, and as of Visual Studio 2007, they will receive true legitimacy with&amp;nbsp;support from Microsoft (via LINQ-to-SQL). Occasionally I run into various limitations however, such as the inability to perform advanced operations like recursing relationships. Fortunately, Object Models have a more advanced, if not slightly trickier to implement cousin: Typed-Datasets.&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 10pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Arial','sans-serif';"&gt;Typed-Datasets have&amp;nbsp;the features of a DataSet (run-time parsable schema, constraint enforcement, xml exportability), as well as the features that make O/R generated object models handy (compile-time parsable schema, i.e. intellisense). Unfortunately DataSets haven&amp;#39;t received as much attention in databinding as have other object models. For one thing, they don&amp;#39;t have an associated DataSource. The ObjectDataSource doesn&amp;#39;t work with them for many reasons, least of which because DataRow&amp;#39;s don&amp;#39;t have a default constructor. The SqlDataSource is great, but it accesses the database directly, making a middle tier impossible. &lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 10pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Arial','sans-serif';"&gt;Not wanting to see DataSets left feeling isolated and unwanted, I&amp;#39;ve created a bindable DataSource for them, thanks in part to&amp;nbsp;example code in a blog post by&amp;nbsp;&lt;a href="http://www.manuelabadia.com/blog/PermaLink,guid,5a03e8da-fd85-4aed-8c3f-298086f5c153.aspx"&gt;&lt;span style="color:blue;"&gt;Manuel Abadi&lt;/span&gt;&lt;/a&gt;&lt;/span&gt;&lt;span style="font-size:10pt;font-family:'Arial','sans-serif';"&gt;&lt;a href="http://www.manuelabadia.com/blog/PermaLink,guid,5a03e8da-fd85-4aed-8c3f-298086f5c153.aspx"&gt;&lt;span style="color:blue;"&gt;a&lt;/span&gt;&lt;/a&gt;. There are just a few things that bear explaining first. Unlike most O/R mapper code, the DsDataSource is designed for pre-loading (vs. lazy loading). The idea being to bind all DsDataSources on the page to different tables within a single DataSet, and to populate that DataSet completely and immediately upon page load:&lt;/span&gt;&lt;span style="font-size:10pt;font-family:'Arial','sans-serif';"&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;color:blue;font-family:'Courier New';"&gt;Partial&lt;/span&gt;&lt;span style="font-size:10pt;font-family:'Courier New';"&gt; &lt;span style="color:blue;"&gt;Class&lt;/span&gt; _Default&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Courier New';"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color:blue;"&gt;Inherits&lt;/span&gt; System.Web.UI.Page&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Courier New';"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color:green;"&gt;&amp;#39; First, we create a new dataset attached to the page instance:&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Courier New';"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color:blue;"&gt;Protected&lt;/span&gt; pDs &lt;span style="color:blue;"&gt;As&lt;/span&gt; &lt;span style="color:blue;"&gt;New&lt;/span&gt; ExampleDs&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Courier New';"&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Courier New';"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color:green;"&gt;&amp;#39; Right off the bat, we want to populate the DataSet from the DB:&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Courier New';"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color:blue;"&gt;Protected&lt;/span&gt; &lt;span style="color:blue;"&gt;Sub&lt;/span&gt; Page_Load() &lt;span style="color:blue;"&gt;Handles&lt;/span&gt; &lt;span style="color:blue;"&gt;Me&lt;/span&gt;.Load&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Courier New';"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;ExampleDs.EmployeeDataTable.LoadAll(Ds)&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Courier New';"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color:blue;"&gt;End&lt;/span&gt; &lt;span style="color:blue;"&gt;Sub&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;color:blue;font-family:'Courier New';"&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Courier New';"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color:green;"&gt;&amp;#39; Lastly, we need to expose the DataSet as a property&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;color:green;font-family:'Courier New';"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&amp;rsquo;so that the DsDataSource controls can access it:&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Courier New';"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color:blue;"&gt;Public&lt;/span&gt; &lt;span style="color:blue;"&gt;ReadOnly&lt;/span&gt; &lt;span style="color:blue;"&gt;Property&lt;/span&gt; Ds() &lt;span style="color:blue;"&gt;As&lt;/span&gt; ExampleDs&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Courier New';"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color:blue;"&gt;Get&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Courier New';"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color:blue;"&gt;Return&lt;/span&gt; pDs&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Courier New';"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color:blue;"&gt;End&lt;/span&gt; &lt;span style="color:blue;"&gt;Get&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Courier New';"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color:blue;"&gt;End&lt;/span&gt; &lt;span style="color:blue;"&gt;Property&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;color:blue;font-family:'Courier New';"&gt;End&lt;/span&gt;&lt;span style="font-size:10pt;font-family:'Courier New';"&gt; &lt;span style="color:blue;"&gt;Class&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 10pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Arial','sans-serif';"&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 10pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Arial','sans-serif';"&gt;The .aspx code looks like this:&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;color:blue;font-family:'Courier New';"&gt;&amp;lt;&lt;/span&gt;&lt;span style="font-size:10pt;color:#a31515;font-family:'Courier New';"&gt;ow&lt;/span&gt;&lt;span style="font-size:10pt;color:blue;font-family:'Courier New';"&gt;:&lt;/span&gt;&lt;span style="font-size:10pt;color:#a31515;font-family:'Courier New';"&gt;DsDataSource&lt;/span&gt;&lt;span style="font-size:10pt;font-family:'Courier New';"&gt; &lt;span style="color:red;"&gt;ID&lt;/span&gt;&lt;span style="color:blue;"&gt;=&amp;quot;dsEmployee&amp;quot;&lt;/span&gt; &lt;span style="color:red;"&gt;runat&lt;/span&gt;&lt;span style="color:blue;"&gt;=&amp;quot;server&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;&lt;span style="color:green;"&gt;&amp;lt;!&amp;mdash;Property from .vb code --&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;color:red;font-family:'Courier New';"&gt;DataSetProperty&lt;/span&gt;&lt;span style="font-size:10pt;color:blue;font-family:'Courier New';"&gt;=&amp;quot;Ds&amp;quot;&lt;/span&gt;&lt;span style="font-size:10pt;font-family:'Courier New';"&gt; &lt;span style="color:red;"&gt;TableName&lt;/span&gt;&lt;span style="color:blue;"&gt;=&amp;quot;Employee&amp;quot; &lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;color:red;font-family:'Courier New';"&gt;&lt;span style="color:green;"&gt;&amp;lt;!-- TypeName of the DataSet --&amp;gt;&lt;/span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;color:red;font-family:'Courier New';"&gt;TypeName&lt;/span&gt;&lt;span style="font-size:10pt;color:blue;font-family:'Courier New';"&gt;=&amp;quot;ExampleDs&amp;quot;&lt;/span&gt;&lt;span style="font-size:10pt;font-family:'Courier New';"&gt; &lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;color:red;font-family:'Courier New';"&gt;&lt;span style="color:green;"&gt;&amp;lt;!-- TypeName of the DataTable --&amp;gt;&lt;/span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;color:red;font-family:'Courier New';"&gt;DataObjectTypeName&lt;/span&gt;&lt;span style="font-size:10pt;color:blue;font-family:'Courier New';"&gt;=&amp;quot;ExampleDs+Employee&amp;quot;&lt;/span&gt;&lt;span style="font-size:10pt;font-family:'Courier New';"&gt; &lt;span style="color:blue;"&gt;/&amp;gt;&lt;/span&gt; &lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Courier New';"&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;color:green;font-family:'Courier New';"&gt;&amp;lt;!&amp;mdash;- Then, just set the DataSourceId on the GridView: --&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;color:blue;font-family:'Courier New';"&gt;&amp;lt;&lt;/span&gt;&lt;span style="font-size:10pt;color:#a31515;font-family:'Courier New';"&gt;asp&lt;/span&gt;&lt;span style="font-size:10pt;color:blue;font-family:'Courier New';"&gt;:&lt;/span&gt;&lt;span style="font-size:10pt;color:#a31515;font-family:'Courier New';"&gt;GridView&lt;/span&gt;&lt;span style="font-size:10pt;font-family:'Courier New';"&gt; &lt;span style="color:red;"&gt;runat&lt;/span&gt;&lt;span style="color:blue;"&gt;=&amp;quot;server&amp;quot;&lt;/span&gt; &lt;span style="color:red;"&gt;ID&lt;/span&gt;&lt;span style="color:blue;"&gt;=&amp;quot;gvEmployee&amp;quot;&lt;/span&gt; &lt;span style="color:red;"&gt;DataSourceID&lt;/span&gt;&lt;span style="color:blue;"&gt;=&amp;quot;dsEmployee&amp;quot;&lt;/span&gt; &lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;color:red;font-family:'Courier New';"&gt;AutoGenerateColumns&lt;/span&gt;&lt;span style="font-size:10pt;color:blue;font-family:'Courier New';"&gt;=&amp;quot;false&amp;quot;&lt;/span&gt;&lt;span style="font-size:10pt;font-family:'Courier New';"&gt; &lt;span style="color:red;"&gt;DataKeyNames&lt;/span&gt;&lt;span style="color:blue;"&gt;=&amp;quot;EmployeeId&amp;quot;&amp;gt;&lt;/span&gt; &lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Courier New';"&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;color:blue;font-family:'Courier New';"&gt;&amp;lt;&lt;/span&gt;&lt;span style="font-size:10pt;color:#a31515;font-family:'Courier New';"&gt;Columns&lt;/span&gt;&lt;span style="font-size:10pt;color:blue;font-family:'Courier New';"&gt;&amp;gt;&amp;hellip;&amp;lt;/&lt;/span&gt;&lt;span style="font-size:10pt;color:#a31515;font-family:'Courier New';"&gt;Columns&lt;/span&gt;&lt;span style="font-size:10pt;color:blue;font-family:'Courier New';"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="font-size:10pt;color:#a31515;font-family:'Courier New';"&gt;asp&lt;/span&gt;&lt;span style="font-size:10pt;color:blue;font-family:'Courier New';"&gt;:&lt;/span&gt;&lt;span style="font-size:10pt;color:#a31515;font-family:'Courier New';"&gt;GridView&lt;/span&gt;&lt;span style="font-size:10pt;color:blue;font-family:'Courier New';"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 0pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;color:blue;font-family:'Courier New';"&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 10pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Arial','sans-serif';"&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 10pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Arial','sans-serif';"&gt;With no SelectMethod, as shown, the DsDataSource will display all rows in the target table. If necessary, you can specify a SelectMethod to return a subset of rows. The InsertMethod and UpdateMethod have been rolled into a common &amp;quot;Persist&amp;quot; method, and the obligatory DeleteMethod property is available as well. Aside from these minor differences, the DsDataSource functions much like the ObjectDataSource. It even attempts to use reflection to set the row properties if available, so that you can put business logic in your typed DataRow classes.&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 10pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Arial','sans-serif';"&gt;Hopefully that will be enough to get you coding, and I have an &lt;a href="http://blogs.orcsweb.com/brent/attachment/1273.ashx"&gt;&lt;span style="color:blue;"&gt;example&lt;/span&gt;&lt;/a&gt; available for download as well.&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 10pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Arial','sans-serif';"&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 10pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Arial','sans-serif';"&gt;Happy coding!&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 10pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Arial','sans-serif';"&gt;- Brent&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 10pt;"&gt;&lt;font face="Calibri" size="3"&gt;&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;img src="http://blogs.orcsweb.com/aggbug.aspx?PostID=1273" width="1" height="1"&gt;</content><author><name>Brent</name><uri>http://blogs.orcsweb.com/members/Brent.aspx</uri></author></entry><entry><title>ASP.NET Custom ObjectDataSource</title><link rel="alternate" type="text/html" href="http://blogs.orcsweb.com/brent/archive/2007/04/12/asp-net-custom-objectsource.aspx" /><link rel="enclosure" type="application/x-zip-compressed" length="8394" href="http://blogs.orcsweb.com/brent/attachment/1268.ashx" /><id>http://blogs.orcsweb.com/brent/archive/2007/04/12/asp-net-custom-objectsource.aspx</id><published>2007-04-13T02:36:00Z</published><updated>2007-04-13T02:36:00Z</updated><content type="html">&lt;p&gt;I suppose it would be debatable, but I would venture to suggest that with the ObjectDataSource, ASP.NET has caught up with, and &lt;span style="font-size:10pt;line-height:115%;font-family:'Arial','sans-serif';"&gt;surpassed &lt;/span&gt;Windows Forms in terms of databinding. Unfortunately, it has one major problem that makes it incompatible with many O/R mappers: It only supports default (&lt;span style="font-size:10pt;line-height:115%;font-family:'Arial','sans-serif';"&gt;parameter-less&lt;/span&gt;) constructors. &lt;/p&gt;&lt;p&gt;The solution? Why make your own DataSource of course! While I looked into this briefly, the MSDN documentation is mostly from a usage perspective. It does little to describe how the base DataSource and DataSourceView classes work. Recently I found a fantastic &lt;a href="http://www.manuelabadia.com/blog/PermaLink,guid,5a03e8da-fd85-4aed-8c3f-298086f5c153.aspx" title="blog post"&gt;blog&lt;/a&gt; post by M&lt;span class="searchword"&gt;a&lt;/span&gt;nuel &lt;span class="searchword"&gt;A&lt;/span&gt;b&lt;span class="searchword"&gt;a&lt;/span&gt;di&lt;span class="searchword"&gt;a that does a great job of explaining their interaction, and exactly what needs to be done to create your own ObjectDataSource. Using his advice, I was able to create a version of the ObjectDataSource that can call a constructor, and pass it pertinent parameters (like primary key information). This simple change allows the ObjectDataSource to work flawlessly with most code generated by O/R mappers!&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;img height="529" src="http://blogs.orcsweb.com/brent/attachment/1278.ashx" width="596" /&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;If you like, you can &lt;a href="http://blogs.orcsweb.com/brent/attachment/1268.ashx"&gt;download the custom ObjectDataSource&lt;/a&gt;, and example code.&lt;/p&gt;&lt;p&gt;Hopefully this code will save you as much time as it has saved me!&lt;/p&gt;&lt;p&gt;- Brent&lt;/p&gt;&lt;img src="http://blogs.orcsweb.com/aggbug.aspx?PostID=1268" width="1" height="1"&gt;</content><author><name>Brent</name><uri>http://blogs.orcsweb.com/members/Brent.aspx</uri></author></entry><entry><title>Automatically Generating Audit Tables</title><link rel="alternate" type="text/html" href="http://blogs.orcsweb.com/brent/archive/2007/04/12/automatically-generating-audit-tables.aspx" /><link rel="enclosure" type="application/x-zip-compressed" length="12357" href="http://blogs.orcsweb.com/brent/attachment/1265.ashx" /><id>http://blogs.orcsweb.com/brent/archive/2007/04/12/automatically-generating-audit-tables.aspx</id><published>2007-04-13T01:24:00Z</published><updated>2007-04-13T01:24:00Z</updated><content type="html">&lt;p class="MsoNormal" style="margin:0in 0in 10pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Arial','sans-serif';"&gt;Developers,&amp;nbsp;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 10pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Arial','sans-serif';"&gt;Have you ever been in a situation where data mysteriously goes awry in production? Your boss comes running in, asking &amp;quot;Why are the totals off on the Johnson account? What&amp;#39;s wrong with your code!&amp;quot;. You look at the data. Indeed it is incorrect. You search the code, you can&amp;#39;t find any bugs. You even try some common operations in your test environment. Still you can&amp;#39;t figure out why the data is incorrect. Was it invalid user input? A bug in your code? A new DBA with an overzealous update query? One might never know....&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 10pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Arial','sans-serif';"&gt;Unless that is,&amp;nbsp;you have audit tables; tables that look just like your regular tables, but log every change in your DB! If you had audit tables, in the example above, you would just tell your boss to hang on a minute, run &amp;quot;select * from audit_account where AccountName=&amp;#39;Johnson&amp;#39;&amp;quot; and five seconds later you could tell him that the new girl in marketing entered invalid data on 4/11/2007 at 10:00am local time. That sure makes for a better answer than a shrug and an &amp;quot;I donno...&amp;quot;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 10pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Arial','sans-serif';"&gt;&lt;img alt="DB" height="463" src="http://blogs.orcsweb.com/brent/attachment/1267.ashx" style="width:550px;height:463px;" title="DB" width="550" /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 10pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Arial','sans-serif';"&gt;But, if you&amp;#39;ve ever used audit tables, you know what a pain they are to create and maintain. Each time you add a new column to a production table, you need to remember to update your audit table, or else you will be missing valuable information. Worse yet, if you remove a column, you will get an exception when you try to insert new data :-S. All in all they are invaluable when debugging, but a pain in the butt to implement.&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 10pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Arial','sans-serif';"&gt;Unless that is you have an audit table generator. What? You don&amp;#39;t? For shame. There are probably some good ones out there --&amp;nbsp;I wouldn&amp;#39;t know, I&amp;#39;ve never used one, and the ones I saw that looked good were pricey and overly-complicated. Being a DIY kind of guy, I wrote my own, and now I figured I would share it with you :-)&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 10pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Arial','sans-serif';"&gt;If you are merely here for the code, I suggest you scroll to the download link now. If you are a coder, or are for some incomprehensible way interested in the generation of audit tables, by all means, continue.&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 10pt;line-height:normal;"&gt;&lt;strong&gt;&lt;span style="font-size:10pt;font-family:'Arial','sans-serif';"&gt;Explanation of Code&lt;/span&gt;&lt;/strong&gt;&lt;span style="font-size:10pt;font-family:'Arial','sans-serif';"&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 10pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Arial','sans-serif';"&gt;I&amp;#39;ll try to avoid a long and tedious line by line analysis, but basically it works like this:&lt;/span&gt;&lt;/p&gt;&lt;ol&gt;&lt;li class="MsoNormal" style="margin:0in 0in 10pt;line-height:normal;tab-stops:list .5in;"&gt;&lt;span style="font-size:10pt;font-family:'Arial','sans-serif';"&gt;The program connects to a database, and runs a query against the sysobjects table, and retrieves all the table names for a given DB. If you are not familiar, sysobjects is a very nifty &amp;quot;table of&amp;nbsp;tables&amp;quot; and contains all the information about the structure of the database. Yes that&amp;#39;s correct, T-SQL stores the schema of your database, *in* a database. Mind-bending huh?&lt;/span&gt;&lt;/li&gt;&lt;li class="MsoNormal" style="margin:0in 0in 10pt;line-height:normal;tab-stops:list .5in;"&gt;&lt;span style="font-size:10pt;font-family:'Arial','sans-serif';"&gt;The list of tables gets populated into a ListBox, allowing users to select which ones they want to audit.&lt;/span&gt;&lt;/li&gt;&lt;li class="MsoNormal" style="margin:0in 0in 10pt;line-height:normal;tab-stops:list .5in;"&gt;&lt;span style="font-size:10pt;font-family:'Arial','sans-serif';"&gt;The user hits &amp;quot;Generate&amp;quot; and the app loops through its list of tables, queries sysobjects for their schema, and writes a matching audit table.&lt;/span&gt;&lt;/li&gt;&lt;li class="MsoNormal" style="margin:0in 0in 10pt;line-height:normal;tab-stops:list .5in;"&gt;&lt;span style="font-size:10pt;font-family:'Arial','sans-serif';"&gt;The program adds triggers to the target table for insert, update, and delete.&lt;/span&gt;&lt;/li&gt;&lt;li class="MsoNormal" style="margin:0in 0in 10pt;line-height:normal;tab-stops:list .5in;"&gt;&lt;span style="font-size:10pt;font-family:'Arial','sans-serif';"&gt;Whenever a change to a target table is made, the trigger inserts a copy of the data into the audit table.&lt;/span&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p class="MsoNormal" style="margin:0in 0in 10pt;line-height:normal;"&gt;&lt;strong&gt;&lt;span style="font-size:10pt;font-family:'Arial','sans-serif';"&gt;Usage Notes&lt;/span&gt;&lt;/strong&gt;&lt;span style="font-size:10pt;font-family:'Arial','sans-serif';"&gt;&lt;/span&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;div class="MsoNormal" style="margin:0in 0in 10pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Arial','sans-serif';"&gt;Just paste in your connection string, select your tables, and hit Generate! &lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li&gt;&lt;div class="MsoNormal" style="margin:0in 0in 10pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Arial','sans-serif';"&gt;Compile with Visual Studio .NET 2005&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li&gt;&lt;div class="MsoNormal" style="margin:0in 0in 10pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Arial','sans-serif';"&gt;This code is intended for example purposes only&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li&gt;&lt;div class="MsoNormal" style="margin:0in 0in 10pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Arial','sans-serif';"&gt;If you do run it against a database, try it on a test DB first, and verify that it doesn&amp;#39;t cause any unexpected results.&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p class="MsoNormal" style="margin:0in 0in 10pt;line-height:normal;"&gt;&lt;strong&gt;&lt;span style="font-size:10pt;font-family:'Arial','sans-serif';"&gt;Screenshot:&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 10pt;line-height:normal;"&gt;&lt;strong&gt;&lt;span style="font-size:10pt;font-family:'Arial','sans-serif';"&gt;&lt;img alt="AUditor" height="411" src="http://blogs.orcsweb.com/brent/attachment/1266.ashx" style="width:533px;height:411px;" title="AUditor" width="533" /&gt;&lt;/span&gt;&lt;/strong&gt;&lt;span style="font-size:10pt;font-family:'Arial','sans-serif';"&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 10pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Arial','sans-serif';"&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 10pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Arial','sans-serif';"&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 10pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Arial','sans-serif';"&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 10pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Arial','sans-serif';"&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 10pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Arial','sans-serif';"&gt;&lt;a href="http://blogs.orcsweb.com/brent/attachment/1265.ashx" title="Download Auditor"&gt;Download Auditor&lt;/a&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 10pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Arial','sans-serif';"&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 10pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Arial','sans-serif';"&gt;Happy coding!&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 10pt;line-height:normal;"&gt;&lt;span style="font-size:10pt;font-family:'Arial','sans-serif';"&gt;- Brent&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin:0in 0in 10pt;"&gt;&lt;font face="Calibri" size="3"&gt;&lt;/font&gt;&lt;/p&gt;&lt;img src="http://blogs.orcsweb.com/aggbug.aspx?PostID=1265" width="1" height="1"&gt;</content><author><name>Brent</name><uri>http://blogs.orcsweb.com/members/Brent.aspx</uri></author></entry><entry><title>.NET and DFSR</title><link rel="alternate" type="text/html" href="http://blogs.orcsweb.com/brent/archive/2007/04/09/net-and-dfsr.aspx" /><link rel="enclosure" type="application/x-zip-compressed" length="20135" href="http://blogs.orcsweb.com/brent/attachment/1221.ashx" /><id>http://blogs.orcsweb.com/brent/archive/2007/04/09/net-and-dfsr.aspx</id><published>2007-04-09T18:54:00Z</published><updated>2007-04-09T18:54:00Z</updated><content type="html">&lt;p&gt;Recently I was tasked to create some automated tools that could configure DFSR. If you are not familiar with it, Microsoft has combined DFS (distributed file system) and FRS (file replication service); two fantastic technologies that give Windows Server users the ability to have redundant network drives. The combination of services is now called DFSR, and was a pretty logical and intelligent move. Unfortunately its seems that Microsoft didn&amp;#39;t get around to creating an SDK for this technology before they sent it out the door, which pretty much leaves users with two options:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;The DFS / FRS API&amp;#39;s (&lt;a href="http://msdn2.microsoft.com/en-us/library/aa379538.aspx"&gt;http://msdn2.microsoft.com/en-us/library/aa379538.aspx&lt;/a&gt;). While these seem to work well enough, they are more or less legacy, and don&amp;#39;t have the cool new additions of DFSR, and since they have no managed namespace equivalent, they are a little cumbersome to use from .NET.&lt;/li&gt;&lt;li&gt;The new DFSR WMI provider (&lt;a href="http://msdn2.microsoft.com/en-us/library/aa380990.aspx"&gt;http://msdn2.microsoft.com/en-us/library/aa380990.aspx&lt;/a&gt;). This is quite handy because it is easily accessible from managed code, and it contains all the latest DFSR stuff. The problem is that it seems to be read-only! (or at least I couldn&amp;#39;t find any write methods, and calls to ManagementObject.Put() fail with a generic exception).&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;There is however a MMC snap-in included with Windows Server 2003, so there must be an API out there somewhere right? After some quick poking around its possible to see that the dfsmgnt.msc file loads DfsMgmt.dll, which in turn loads DfsObjectModel.dll. As the name implies, this .dll has a beautifully constructed object model for .NET. One look&amp;nbsp;with Lutz Roeder&amp;#39;s fantastic program Reflector (&lt;a href="http://www.aisto.com/roeder/dotnet/"&gt;http://www.aisto.com/roeder/dotnet/&lt;/a&gt;) quickly reveals a logical class system neatly representing the underlying DFSR objects. The only problem being that all the classes are marked as &amp;quot;friend&amp;quot;, so we can&amp;#39;t simply import the assembly and use it ourselves!&lt;/p&gt;&lt;p&gt;&lt;img height="212" src="http://blogs.orcsweb.com/brent/attachment/1228.ashx" width="639" /&gt;&lt;/p&gt;&lt;p&gt;&lt;img height="214" src="http://blogs.orcsweb.com/brent/attachment/1227.ashx" width="697" /&gt;&lt;/p&gt;&lt;p&gt;&lt;img height="112" src="http://blogs.orcsweb.com/brent/attachment/1229.ashx" width="321" /&gt;&lt;/p&gt;&lt;p&gt;Luckily what Microsoft taketh-away, they also giveth-back. Using reflection, it is possible to instantiate classes and call methods, even if they aren&amp;#39;t exposed. Since there seems to be no clean alternative method for accessing DFS through .NET, I&amp;#39;ve created a some simple wrapper classes which re-expose the friend methods in this .dll. &lt;/p&gt;&lt;p&gt;The code listed below&amp;nbsp;is by no means considered to be a complete recreation, but hopefully it will be a good starting point for others to build on. Bear in mind you will need to:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Create a DFS root to start with&lt;/li&gt;&lt;li&gt;Have a domain&amp;nbsp;&lt;/li&gt;&lt;li&gt;Have at least one server with DFS installed (two would make more sense ;-)&lt;/li&gt;&lt;li&gt;Compile the small forms app with Visual Studio .NET 2005&lt;/li&gt;&lt;li&gt;Copy the DfsObjectModel.dll file from a Windows 2003 server into the \Bin\Debug folder prior to running this app&lt;/li&gt;&lt;li&gt;Update the textbox values to reflect the appropriate values for your environment&lt;/li&gt;&lt;li&gt;Bear in mind this is example code, not intended for production deployment!&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;img height="263" src="http://blogs.orcsweb.com/brent/attachment/1230.ashx" width="306" /&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://blogs.orcsweb.com/brent/attachment/1221.ashx" title="Download DFS.zip"&gt;&lt;strong&gt;Download DFS.zip&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;- Brent&lt;/p&gt;&lt;img src="http://blogs.orcsweb.com/aggbug.aspx?PostID=1221" width="1" height="1"&gt;</content><author><name>Brent</name><uri>http://blogs.orcsweb.com/members/Brent.aspx</uri></author></entry></feed>