<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss'><id>tag:blogger.com,1999:blog-6782310453584500629</id><updated>2009-10-04T06:15:36.606-04:00</updated><title type='text'>Zack's Fiasco</title><subtitle type='html'>This is a place where I can post some ideas and software projects that I'm working on.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://zacksfiasco.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6782310453584500629/posts/default'/><link rel='alternate' type='text/html' href='http://zacksfiasco.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Zack</name><uri>http://www.blogger.com/profile/16452669760064159733</uri><email>noreply@blogger.com</email></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>16</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-6782310453584500629.post-7788621173371673087</id><published>2009-01-14T12:26:00.001-05:00</published><updated>2009-01-14T12:31:44.953-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql server'/><category scheme='http://www.blogger.com/atom/ns#' term='Zack&apos;s Fiasco DAL'/><category scheme='http://www.blogger.com/atom/ns#' term='codegeneration'/><category scheme='http://www.blogger.com/atom/ns#' term='LINQ'/><title type='text'>LINQ and Code Generation Slides</title><content type='html'>&lt;p&gt;On Monday I did a presentation with Chad Brooks and Dave Cameron at our local .NET User Group: &lt;a href="http://MaconDotNet.org/"&gt;MaconDotNet&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;My sections were on LINQ and Code Generation. Other than me running a little long, the presentation went great. Here are my slides and examples but head over to &lt;a href="http://macondotnet.org/post/Slides-from-Mondays-Meeting-(12-Jan-2009).aspx"&gt;the user group page&lt;/a&gt; to grab Chad and Dave's slides and examples when they get posted.&lt;/p&gt;  &lt;p&gt;If you find any errors or typos, let me know. &lt;/p&gt;  &lt;p&gt;(Note: I did a section on LINQ and a section on Code Generation. Not &amp;quot;LINQ and Code Generation&amp;quot;)&lt;/p&gt;  &lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:fb3a1972-4489-4e52-abe7-25a00bb07fdf:aa5c4b0e-1707-4f6e-8aab-cc1bbd620e18" class="wlWriterSmartContent"&gt;&lt;p&gt; &lt;a href="http://zacksfiasco.com/blogimages/SlidesfromMondaysMeeting12Jan2009_AC67/DotNETDataAccessPart1Zack.pptx" target="_blank"&gt;LINQ and Code Generation Slides (Zack)&lt;/a&gt;&lt;br /&gt; &lt;a href="http://zacksfiasco.com/blogimages/SlidesfromMondaysMeeting12Jan2009_AC67/ZacksDataAccessExamples.zip" target="_blank"&gt;LINQ and Code Generation Examples (Zack)&lt;/a&gt;&lt;/p&gt;&lt;/div&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6782310453584500629-7788621173371673087?l=zacksfiasco.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zacksfiasco.blogspot.com/feeds/7788621173371673087/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=6782310453584500629&amp;postID=7788621173371673087' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6782310453584500629/posts/default/7788621173371673087'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6782310453584500629/posts/default/7788621173371673087'/><link rel='alternate' type='text/html' href='http://zacksfiasco.blogspot.com/2009/01/linq-and-code-generation-slides.html' title='LINQ and Code Generation Slides'/><author><name>Zack</name><uri>http://www.blogger.com/profile/16452669760064159733</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='02342781909266978719'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6782310453584500629.post-8235327978502701606</id><published>2009-01-05T12:41:00.001-05:00</published><updated>2009-01-05T12:44:29.220-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ASP.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='eCommerce'/><title type='text'>ASP.NET eCommerce Solutions?</title><content type='html'>&lt;p&gt;I had a long break after Christmas that I used to work on some projects. Sometimes it is hard to get any free time and it was a well enjoyed break.&lt;/p&gt;  &lt;p&gt;I didn't get as much done on my XNA project as I would like but I've been studying the book pretty thoroughly.&lt;/p&gt;  &lt;p&gt;My main project that I worked on was to build a web page for my dad's business. He has an old brink-and-mortar style business that was started by my grandfather. My dad is pretty tech savvy but he never got around to building a web page for his business so I thought it would be a good project. &lt;/p&gt;  &lt;p&gt;I got a lot done on that and I'm talking to my sister and my wife to help me finish writing content for the site.&lt;/p&gt;  &lt;p&gt;For my dad's web page I decided to investigate what it would take to add an eCommerce section and see if he was interested in selling a few items over the 'net as well as in person. So I started looking for a good ASP.NET based free eCommerce solution preferably that had built in support for &lt;a href="http://www.PayPal.com/"&gt;PayPal&lt;/a&gt;'s free (mostly) services. I figured there had to be lots of them out there but I didn't know one off the top of my head so I decided to look. &lt;/p&gt;  &lt;p&gt;Turns out I was wrong, or at least I couldn't find as many as I thought. osCommerce seems to dominate the PHP world with several other strong competitors, but I didn't find as many stand-out ASP.NET kits. &lt;/p&gt;  &lt;p&gt;However I did find 2 that seemed to be the best.&lt;/p&gt;  &lt;p&gt;Microsoft used to have an eCommerce starter kit that you could download for ASP.NET. I don't know the details of how this happened but the kit has now been taken over by someone else and is called &lt;a href="http://dashcommerce.org/"&gt;dashCommerce&lt;/a&gt;. The code is published under a free open source license and a commercial license with the main difference being a support agreement and the requirement that the free version must always display a message at the bottom of the page that reads &amp;quot;Powered by dashCommerce&amp;quot;.&lt;/p&gt;  &lt;p&gt;The other good product I found, which is also listed on Microsoft's ASP.NET web page, is &lt;a href="http://www.dotshoppingcart.com/"&gt;DotShoppingCart&lt;/a&gt;. This product has as far as I can tell the same general options as dashCommerce, that you can use a free open source version as long as you leave the &amp;quot;Powered by DotShoppingCart&amp;quot; message at the bottom of every page or you can buy a commercial license with a support agreement.&lt;/p&gt;  &lt;p&gt;I downloaded both products and tried them out using &lt;a href="https://developer.paypal.com/"&gt;PayPal's sandbox&lt;/a&gt;. (btw, PayPal's sandbox is a pain to use.) I liked both. They are both similar in the features that they offer. They both have basic CMS tools and product catalogs. Both allow products to have configurable attributes like Size or Color or whatever you need. dashCommerce gives each product a different SKU per attribute while DotShoppingCart seems to give a product one SKU no matter the attributes. Both require SQL Server 2005 Express (or greater) with Advanced Services. I believe the main reason for this is that both use the Full Text searching. I don't know if either uses any of the other Advanced Features. Both have source code. dashCommerce uses &lt;a href="http://subsonicproject.com/"&gt;SubSonic&lt;/a&gt; and &lt;a href="http://logging.apache.org/log4net/index.html"&gt;log4net&lt;/a&gt; while DotShoppingCart uses the &lt;a href="http://msdn.microsoft.com/en-us/library/cc467894.aspx"&gt;MS Enterprise Library&lt;/a&gt;. Both appear to have IPN support but I didn't test it.&lt;/p&gt;  &lt;p&gt;I would also like to point out that &lt;a href="http://www.componentone.com/SuperProducts/PayPaleCommerceASPNET/"&gt;ComponentOne&lt;/a&gt; also offers a free control library for dealing with PayPal. I haven't downloaded it or looked at it but it might be worth checking out and kudos to ComponentOne for offering it for free.&lt;/p&gt;  &lt;p&gt;What do most people use? Either of the items I've listed or do you roll your own? Or is there another free or low cost kit or product that I have missed?&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6782310453584500629-8235327978502701606?l=zacksfiasco.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zacksfiasco.blogspot.com/feeds/8235327978502701606/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=6782310453584500629&amp;postID=8235327978502701606' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6782310453584500629/posts/default/8235327978502701606'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6782310453584500629/posts/default/8235327978502701606'/><link rel='alternate' type='text/html' href='http://zacksfiasco.blogspot.com/2009/01/aspnet-ecommerce-solutions.html' title='ASP.NET eCommerce Solutions?'/><author><name>Zack</name><uri>http://www.blogger.com/profile/16452669760064159733</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='02342781909266978719'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6782310453584500629.post-6662175573300435737</id><published>2009-01-05T12:31:00.001-05:00</published><updated>2009-01-05T12:42:07.608-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Zune'/><title type='text'>Zune bug revealed</title><content type='html'>&lt;p&gt;A little update on the Zune issue I mentioned in my last post. Aeroxperience gives a good explanation of the bug and shows some source code &lt;a href="http://www.aeroxp.org/2009/01/lesson-on-infinite-loops/"&gt;here&lt;/a&gt;. The problem ended up being a bad way to calculate years and the date combined with a while() loop with a case that can loop forever. Check it out.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6782310453584500629-6662175573300435737?l=zacksfiasco.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zacksfiasco.blogspot.com/feeds/6662175573300435737/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=6782310453584500629&amp;postID=6662175573300435737' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6782310453584500629/posts/default/6662175573300435737'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6782310453584500629/posts/default/6662175573300435737'/><link rel='alternate' type='text/html' href='http://zacksfiasco.blogspot.com/2009/01/zune-bug-revealed.html' title='Zune bug revealed'/><author><name>Zack</name><uri>http://www.blogger.com/profile/16452669760064159733</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='02342781909266978719'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6782310453584500629.post-4961346167139011983</id><published>2009-01-01T16:16:00.000-05:00</published><updated>2009-01-01T16:43:26.089-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Zune'/><category scheme='http://www.blogger.com/atom/ns#' term='XNA'/><title type='text'>Zune 30 GB crash came and went</title><content type='html'>&lt;p&gt;This may have came and went without you even noticing.&lt;/p&gt;  &lt;p&gt;On 31 Dec 2008 all 30 GB Zunes locked up and stopped working. If you think that MS doesn't make a 30 GB Zune, your confusion is understandable. the 30 GB models were the original Zunes which had the circle style navigator instead of the touch based squarish navigators all the new ones have. &lt;/p&gt;  &lt;p align="justify"&gt;&lt;strong&gt;&lt;font color="#0000ff"&gt;(&lt;u&gt;quick side note&lt;/u&gt;: I like the new Zunes. I got my Mom a &lt;a href="http://www.amazon.com/gp/product/B000WFZRZG?ie=UTF8&amp;amp;tag=zacsfia-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=390957&amp;amp;creativeASIN=B000WFZRZG"&gt;4 GB Zune&lt;/a&gt; for Christmas and I hadn't realized until I played with it that the little square is touch sensitive. I thought it was just a square version of the circle joystick that mine had but its actually very nice upgrade. It was new to me even if this feature has been out a while. Now back to my main point...)&lt;/font&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;I use my Zune quite a bit. In fact I had just used it on Tuesday when I went running. But I hadn't used it yet on Wednesday when I saw an &lt;a href="http://it.slashdot.org/article.pl?sid=08/12/31/1428254"&gt;article&lt;/a&gt; on &lt;a href="http://www.slashdot.org/"&gt;Slashdot&lt;/a&gt; about Zunes mass crashing. I said to myself, &amp;quot;That's weird.&amp;quot; and turned mine on to see that it too was locked up.&lt;/p&gt;  &lt;p&gt;Turns out there was a bug in the original Zune in how it dealt with leap years. 2008 was a leap year and the Zune got confused because it was one day longer than it expected. &lt;/p&gt;  &lt;p&gt;I was wondering how long it would take for a fix to come out but it was pretty quick as it turns out. In fact I didn't have to do anything except let the battery run down. See &lt;a href="http://www.zune.net/en-us/support/zune30.htm"&gt;here&lt;/a&gt; for the details from MS, but all you had to do was let the battery die then wait until after the new year started in GMT and re-synch your Zune and the leap year problem went away.&lt;/p&gt;  &lt;p&gt;So I guess it was mostly a much ado about nothing unless you were using your Zune for your New Years party music.&lt;/p&gt;  &lt;p align="justify"&gt;&lt;font color="#0000ff"&gt;&lt;strong&gt;(&lt;u&gt;another side note&lt;/u&gt;: Over my Christmas break I've been reading about &lt;a href="http://msdn.microsoft.com/en-us/xna/default.aspx"&gt;XNA Game Studio 3.0&lt;/a&gt;. Thats MS tools to write games for Windows, XBox 360, and your Zune. I mention this here because I remember reading that if you want your game to work correctly on the old 30 GB Zunes like mine that you had to be careful how you used the joystick/navigator because it only has up, down, left, right, and click while the new ones have a much more precise control which can detect a greater degree of movement in every direction. Kind'of interesting, to me at least.&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p align="justify"&gt;&lt;strong&gt;&lt;font color="#0000ff"&gt;Here is the XNA book I'm reading now. It doesn't get into super complicated aspects but it covers all of the basics so I would recommend it as a good getting started book.&lt;/font&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p align="justify"&gt;&lt;font color="#0000ff"&gt;&lt;strong&gt;&lt;iframe style="width: 120px; height: 240px" marginheight="0" src="http://rcm.amazon.com/e/cm?t=zacsfia-20&amp;amp;o=1&amp;amp;p=8&amp;amp;l=as1&amp;amp;asins=0596521952&amp;amp;md=10FE9736YVPPT7A0FBG2&amp;amp;fc1=000000&amp;amp;IS2=1&amp;amp;lt1=_blank&amp;amp;m=amazon&amp;amp;lc1=0000FF&amp;amp;bc1=000000&amp;amp;bg1=FFFFFF&amp;amp;f=ifr" frameborder="0" marginwidth="0" scrolling="no"&gt;&lt;/iframe&gt;&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p align="justify"&gt;&lt;font color="#0000ff"&gt;&lt;strong&gt;Here are some other XNA 3.0 books that are coming out in 2009 that I'm interested in. When I bought the above book there were only a few other 3.0 books slated to come out soon. Now it looks like there are quite a few so I'm only listing a few of the most interesting looking ones:&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p align="justify"&gt;&lt;font color="#0000ff"&gt;&lt;strong&gt;&lt;iframe style="width: 120px; height: 240px" marginheight="0" src="http://rcm.amazon.com/e/cm?t=zacsfia-20&amp;amp;o=1&amp;amp;p=8&amp;amp;l=as1&amp;amp;asins=1430218177&amp;amp;md=10FE9736YVPPT7A0FBG2&amp;amp;fc1=000000&amp;amp;IS2=1&amp;amp;lt1=_blank&amp;amp;m=amazon&amp;amp;lc1=0000FF&amp;amp;bc1=000000&amp;amp;bg1=FFFFFF&amp;amp;f=ifr" frameborder="0" marginwidth="0" scrolling="no"&gt;&lt;/iframe&gt;&lt;iframe style="width: 120px; height: 240px" marginheight="0" src="http://rcm.amazon.com/e/cm?t=zacsfia-20&amp;amp;o=1&amp;amp;p=8&amp;amp;l=as1&amp;amp;asins=143021869X&amp;amp;md=10FE9736YVPPT7A0FBG2&amp;amp;fc1=000000&amp;amp;IS2=1&amp;amp;lt1=_blank&amp;amp;m=amazon&amp;amp;lc1=0000FF&amp;amp;bc1=000000&amp;amp;bg1=FFFFFF&amp;amp;f=ifr" frameborder="0" marginwidth="0" scrolling="no"&gt;&lt;/iframe&gt;&lt;iframe style="width: 120px; height: 240px" marginheight="0" src="http://rcm.amazon.com/e/cm?t=zacsfia-20&amp;amp;o=1&amp;amp;p=8&amp;amp;l=as1&amp;amp;asins=143021855X&amp;amp;md=10FE9736YVPPT7A0FBG2&amp;amp;fc1=000000&amp;amp;IS2=1&amp;amp;lt1=_blank&amp;amp;m=amazon&amp;amp;lc1=0000FF&amp;amp;bc1=000000&amp;amp;bg1=FFFFFF&amp;amp;f=ifr" frameborder="0" marginwidth="0" scrolling="no"&gt;&lt;/iframe&gt;&lt;iframe style="width: 120px; height: 240px" marginheight="0" src="http://rcm.amazon.com/e/cm?t=zacsfia-20&amp;amp;o=1&amp;amp;p=8&amp;amp;l=as1&amp;amp;asins=1430218614&amp;amp;md=10FE9736YVPPT7A0FBG2&amp;amp;fc1=000000&amp;amp;IS2=1&amp;amp;lt1=_blank&amp;amp;m=amazon&amp;amp;lc1=0000FF&amp;amp;bc1=000000&amp;amp;bg1=FFFFFF&amp;amp;f=ifr" frameborder="0" marginwidth="0" scrolling="no"&gt;&lt;/iframe&gt;&lt;iframe style="width: 120px; height: 240px" marginheight="0" src="http://rcm.amazon.com/e/cm?t=zacsfia-20&amp;amp;o=1&amp;amp;p=8&amp;amp;l=as1&amp;amp;asins=0672330229&amp;amp;md=10FE9736YVPPT7A0FBG2&amp;amp;fc1=000000&amp;amp;IS2=1&amp;amp;lt1=_blank&amp;amp;m=amazon&amp;amp;lc1=0000FF&amp;amp;bc1=000000&amp;amp;bg1=FFFFFF&amp;amp;f=ifr" frameborder="0" marginwidth="0" scrolling="no"&gt;&lt;/iframe&gt;&lt;iframe style="width: 120px; height: 240px" marginheight="0" src="http://rcm.amazon.com/e/cm?t=zacsfia-20&amp;amp;o=1&amp;amp;p=8&amp;amp;l=as1&amp;amp;asins=1598220659&amp;amp;md=10FE9736YVPPT7A0FBG2&amp;amp;fc1=000000&amp;amp;IS2=1&amp;amp;lt1=_blank&amp;amp;m=amazon&amp;amp;lc1=0000FF&amp;amp;bc1=000000&amp;amp;bg1=FFFFFF&amp;amp;f=ifr" frameborder="0" marginwidth="0" scrolling="no"&gt;&lt;/iframe&gt;&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p align="justify"&gt;&lt;font color="#0000ff"&gt;&lt;strong&gt;)&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6782310453584500629-4961346167139011983?l=zacksfiasco.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zacksfiasco.blogspot.com/feeds/4961346167139011983/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=6782310453584500629&amp;postID=4961346167139011983' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6782310453584500629/posts/default/4961346167139011983'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6782310453584500629/posts/default/4961346167139011983'/><link rel='alternate' type='text/html' href='http://zacksfiasco.blogspot.com/2009/01/zune-30-gb-crash-came-and-went.html' title='Zune 30 GB crash came and went'/><author><name>Zack</name><uri>http://www.blogger.com/profile/16452669760064159733</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='02342781909266978719'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6782310453584500629.post-3489684099518222090</id><published>2009-01-01T15:47:00.001-05:00</published><updated>2009-01-01T16:17:33.534-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql server'/><title type='text'>Getting SQL Express Studio upgraded when upgrading SQL Server Express 2008</title><content type='html'>&lt;p&gt;I've been running SQL Server Express 2005 and the Express Management Studio for all my DB development. Ever since SQL Server 2008 came out I've been thinking about upgrading and today I decided to. However, after I upgraded I noticed that my SQL Management Studio didn't upgrade. After a few minutes I couldn't figure it out so I did a web search and found that Luis Rocha had already figured out the solution to the problem.&lt;/p&gt;  &lt;p&gt;You can read his solution &lt;a href="http://www.luisrocha.net/2008/12/upgrading-to-sql-server-2008-express.html"&gt;here&lt;/a&gt;. Some of the screen shots weren't working when I read it and I think he mis-named one of the items to click on Step #4 but much thanks to him for figuring it out.&lt;/p&gt;  &lt;p&gt;Essentially, the solution is to close the installation program after upgrading SQL Server. Then, re-run the installation program and select Installation-&amp;gt;New SQL Server stand-alone installation or add features to an existing installation. When you are prompted for a new install or add features then select your current instance. Finally, on the feature tree you can select the features to add including the Management Studio.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6782310453584500629-3489684099518222090?l=zacksfiasco.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zacksfiasco.blogspot.com/feeds/3489684099518222090/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=6782310453584500629&amp;postID=3489684099518222090' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6782310453584500629/posts/default/3489684099518222090'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6782310453584500629/posts/default/3489684099518222090'/><link rel='alternate' type='text/html' href='http://zacksfiasco.blogspot.com/2009/01/getting-sql-express-studio-upgraded.html' title='Getting SQL Express Studio upgraded when upgrading SQL Server Express 2008'/><author><name>Zack</name><uri>http://www.blogger.com/profile/16452669760064159733</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='02342781909266978719'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6782310453584500629.post-3110383346118437331</id><published>2008-11-20T14:24:00.001-05:00</published><updated>2008-11-20T14:34:02.777-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JavaScript'/><category scheme='http://www.blogger.com/atom/ns#' term='IE'/><title type='text'>IE Modal Dialog - Debug Y/N Rant</title><content type='html'>&lt;p&gt;I first wrote this up as a post on the &lt;a href="http://forums.asp.net/130.aspx"&gt;ASP.NET Client Side Web Development Forum&lt;/a&gt; when I realized that my blog is badly neglected and I ought to be writing stuff there. You can find my forum post &lt;a href="http://forums.asp.net/t/1350964.aspx"&gt;here&lt;/a&gt; to see if anybody responded over there.&lt;/p&gt;  &lt;p&gt;Yesterday I was reading the Visual Web Developer Blog. They have a really good article on JavaScript Intellisence in Visual Studio. &lt;a href="http://blogs.msdn.com/webdevtools/archive/2008/11/18/jscript-intellisense-faq.aspx"&gt;http://blogs.msdn.com/webdevtools/archive/2008/11/18/jscript-intellisense-faq.aspx&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;In the article and comments the author was really encouraging users to post their issues with the technology because they really did use it to improve the products. &lt;/p&gt;  &lt;p&gt;That request got me to thinking about the different little issues that I run into as a developer and I was reminded of something that I deal with countless times every day. I started writing it up as a comment in that blog post but I stopped because it was a little off topic and I didn't want to pollute the blog comments with off topic stuff. &lt;/p&gt;  &lt;p&gt;So I decided to write up my little rant here . &lt;/p&gt;  &lt;p&gt;I don't know how many other people this affects but the following issue affects me every day. In order to be able to debug JavaScript in web pages, I leave my browser in &amp;quot;debug&amp;quot; mode all the time because it is a pain to switch it on and off. This allows me to quickly jump into some JavaScript if I find a problem. However, the consequence is that now every page I browse to with IE pops up that little dialog asking me if I want to debug a script error on the page. It is amazing to me how many pages have so many script errors (at least in IE). I also think this causes a lot of my IE crashes especially when I get 2 or more dialogs in deadlock with each other on different tabs. Does anyone else get this? &lt;/p&gt;  &lt;p&gt;Every time I go to &lt;a href="http://www.cnn.com/"&gt;cnn.com&lt;/a&gt; I know before I even type in the address that I'm going to get at least 2 Debug popups. &lt;/p&gt;  &lt;p&gt;Something that compounds the problem for me is that I'm a &amp;quot;Right Click -&amp;gt; Open in New Tab&amp;quot; browser. As I read, if I encounter a link that I'm interested in I open it in a new tab and keep reading. After I finish the page I'm on, I go to the next tab and start reading. But this causes conflicts and lockups when multiple tabs popup Modal Debug Dialogs and I think that leads to a lot of the crashes that I get. &lt;/p&gt;  &lt;p&gt;But it is annoying even if you don't browse that way. This problem is at its worst if you even encounter a page that causes a LOT of JavaScript errors or if you browse to a page that triggers an error when your mouse hovers over an element that you have to cross in order to get your mouse out of the browser window so you can close it. Every time you try to get the mouse out you trigger a modal dialog. After you close it, you try to get out again and re-trigger the modal dialog. &lt;/p&gt;  &lt;p&gt;So how do other people deal with this? Is there a trick that I don't know that would make this more bearable? &lt;/p&gt;  &lt;p&gt;How about the IE team? Could that change how this works so that it wouldn't cause so many problems and halts when I'm working? I would love to see a way to turn debugging on and off easier. I would also love to see the modal dialog removed and replaced with something else like a little error icon or something. The work on IE 8 has been awesome so far. the new debug and dev tools are pretty neat. How about making it easier for web developers to browse the web normally when not debugging?&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6782310453584500629-3110383346118437331?l=zacksfiasco.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zacksfiasco.blogspot.com/feeds/3110383346118437331/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=6782310453584500629&amp;postID=3110383346118437331' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6782310453584500629/posts/default/3110383346118437331'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6782310453584500629/posts/default/3110383346118437331'/><link rel='alternate' type='text/html' href='http://zacksfiasco.blogspot.com/2008/11/ie-modal-dialog-debug-yn-rant.html' title='IE Modal Dialog - Debug Y/N Rant'/><author><name>Zack</name><uri>http://www.blogger.com/profile/16452669760064159733</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='02342781909266978719'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6782310453584500629.post-1984380571266864282</id><published>2008-10-15T11:09:00.001-04:00</published><updated>2008-10-15T11:09:03.597-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='MS Office'/><title type='text'>MS Office 2007 "Document Information Panel" Problems</title><content type='html'>&lt;p&gt;I've gotten behind on my posts here but this is worth recording. I don't know how many other people were having this problem but when I first searched for a solution I couldn't find one. &lt;/p&gt;  &lt;p&gt;The problem I was having was that when I would try to view a document's Properties in Word or Excel 2007 I would get the error &amp;quot;Document information panel was unable to load&amp;quot;. &lt;/p&gt;  &lt;p&gt;It turns out that the problem is a missing DLL in one of Office's folders. &lt;/p&gt;  &lt;p&gt;Thanks to Roman Hnatiuk for finding the solution. You can can read his fix &lt;a href="http://rhnatiuk.wordpress.com/2008/10/15/problem-showing-document-properties-in-word-2007/"&gt;here&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;I also want to thank William Boyer for pointing me in the right direction when I couldn't find the answer.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6782310453584500629-1984380571266864282?l=zacksfiasco.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zacksfiasco.blogspot.com/feeds/1984380571266864282/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=6782310453584500629&amp;postID=1984380571266864282' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6782310453584500629/posts/default/1984380571266864282'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6782310453584500629/posts/default/1984380571266864282'/><link rel='alternate' type='text/html' href='http://zacksfiasco.blogspot.com/2008/10/ms-office-2007-information-panel.html' title='MS Office 2007 &amp;quot;Document Information Panel&amp;quot; Problems'/><author><name>Zack</name><uri>http://www.blogger.com/profile/16452669760064159733</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='02342781909266978719'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6782310453584500629.post-5798501797886861500</id><published>2008-01-23T11:43:00.001-05:00</published><updated>2008-01-23T11:43:55.747-05:00</updated><title type='text'>Digital Picture Frames infected with a computer virus</title><content type='html'>&lt;p&gt;This is great! For Christmas, my wife and I bought digital picture frames for my parents and her parents. We looked at all the different ones and picked one from Insignia because it was a good trade-off between price, features, and picture size. &lt;/p&gt;  &lt;p&gt;Well, wouldn't you know it I found out today that a few of the very model that we bought were infected with a computer virus. &lt;/p&gt;  &lt;p&gt;You can read Insignia's announcement &lt;a href="http://www.insignia-products.com/news.aspx?showarticle=13" target="_blank"&gt;here.&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;The article states that the virus was an older virus that is easily detected and deleted by current anti-virus software. At Christmas, I loaded some photos onto each of the frames before we wrapped them up and I didn't detect a virus when the frame was connected our computer, so I feel pretty safe that the ones we bought were ok. But it really sucks that I now have to tell my dad and my wife's parents to watch our for their &amp;quot;nice&amp;quot; new Christmas gifts.&lt;/p&gt;  &lt;p&gt;The picture frames were purchased at Best Buy. Its not Best Buy's fault that they were defective, however I do think that Best Buy should have moved quickly to alert their customers. I would have respected that. I have read that there is an announcement from Best Buy but I have yet to see or hear it and so I am disappointed in Best Buy. &lt;/p&gt;  &lt;p&gt;I first heard about this when my wife saw an article appear on The Red Tape Chronicles on MSNBC.com. You can read that article &lt;a href="http://redtape.msnbc.com/2008/01/digital-picture.html#posts" target="_blank"&gt;here.&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Insignia is the one who should really be ashamed. They are the ones who manufactured this product. I am glad to see that they have this article up on the front of their web page, but how many people saw that? I don't make a habit of visiting Insignia's web page. They should have done more to prevent this and done more to alert their customers. Is Insignia going to be liable to any of their customers who lost data or had their lives disrupted by having to deal with a computer disaster like loosing data or worse spreading across a network or hurting someone's reputation by sending out spam emails?&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6782310453584500629-5798501797886861500?l=zacksfiasco.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zacksfiasco.blogspot.com/feeds/5798501797886861500/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=6782310453584500629&amp;postID=5798501797886861500' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6782310453584500629/posts/default/5798501797886861500'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6782310453584500629/posts/default/5798501797886861500'/><link rel='alternate' type='text/html' href='http://zacksfiasco.blogspot.com/2008/01/digital-picture-frames-infected-with.html' title='Digital Picture Frames infected with a computer virus'/><author><name>Zack</name><uri>http://www.blogger.com/profile/16452669760064159733</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='02342781909266978719'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6782310453584500629.post-6690981168366025693</id><published>2008-01-22T12:20:00.001-05:00</published><updated>2008-01-22T12:38:32.890-05:00</updated><title type='text'>New Address and Missing Images</title><content type='html'>&lt;p&gt;Good News, Zack's Fiasco now has a new URL: &lt;a href="http://Blog.ZacksFiasco.com/"&gt;http://Blog.ZacksFiasco.com/&lt;/a&gt; !&lt;/p&gt;  &lt;p&gt;If you have anything that links to the old address &lt;a href="http://ZacksFiasco.blogspot.com/"&gt;http://ZacksFiasco.blogspot.com/&lt;/a&gt; it should continue to work. However it might be a good idea to go ahead and update your links. If I ever move off of Blogspot then the old URL will stop working.&lt;/p&gt;  &lt;p&gt;&lt;strike&gt;&lt;font color="#ff0000"&gt;Now the bad news. Because of the URL change, Blogspot has stopped serving up some of my screenshots that I have in my articles. I am currently researching a solution and will fix it ASAP. In the meantime, you should still be able to read the articles and I apologize for the problem with the screenshots.&lt;/font&gt;&lt;/strike&gt;&lt;/p&gt;  &lt;p&gt;Screenshots are working again. I just had to upload them to a new location and repost all my old articles.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6782310453584500629-6690981168366025693?l=zacksfiasco.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zacksfiasco.blogspot.com/feeds/6690981168366025693/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=6782310453584500629&amp;postID=6690981168366025693' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6782310453584500629/posts/default/6690981168366025693'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6782310453584500629/posts/default/6690981168366025693'/><link rel='alternate' type='text/html' href='http://zacksfiasco.blogspot.com/2008/01/new-address-and-missing-images.html' title='New Address and Missing Images'/><author><name>Zack</name><uri>http://www.blogger.com/profile/16452669760064159733</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='02342781909266978719'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6782310453584500629.post-112753301562904261</id><published>2008-01-20T03:08:00.000-05:00</published><updated>2008-01-22T13:13:29.578-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ADO.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='sql server'/><category scheme='http://www.blogger.com/atom/ns#' term='Zack&apos;s Fiasco DAL'/><category scheme='http://www.blogger.com/atom/ns#' term='TSQL'/><category scheme='http://www.blogger.com/atom/ns#' term='databinding'/><category scheme='http://www.blogger.com/atom/ns#' term='codegeneration'/><category scheme='http://www.blogger.com/atom/ns#' term='ORM'/><title type='text'>Build a complete Stored Procedure based Data Access Layer using Code Generation - Part 2</title><content type='html'>&lt;p&gt;&lt;em&gt;All code published in this article is published under the Microsoft Public License. See source code download for a copy of the license. &lt;/em&gt;&lt;/p&gt;  &lt;p&gt;&lt;em&gt;Copyright 2008 Zack Moore&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;Code can be downloaded from &lt;a href="http://www.codeplex.com/ZFCGDAL"&gt;here&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;During the course of writing the next part in this series, I made some changes to the scripts. I fixed some bugs in how computed columns were handled, cleaned up some inefficient code, added a lot more comments, and I changed the Insert and Update procedures to make better use of the SQL Server 2005 OUTPUT clause in returning computed and identity columns. This leads into a good discussion of the structure of MyGeneration scripts, how to change them, and how to version them.&lt;/p&gt;  &lt;p&gt;Before I begin discussion of the code there are some things you need to know about MyGeneration scripts. Each script is identified by a Unique ID which is a GUID. If you edit a script that you did not create, then it is a good idea to create a new id for that script. Otherwise it could be overwritten or confused with the original script. It is also a good idea to update the title to reflect that it is a modified version of the original.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://zacksfiasco.com/blogimages/BuildacompleteStoredProcedurebasedData.5_13228/BasicCRUDproperties.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="327" alt="Basic CRUD properties" src="http://zacksfiasco.com/blogimages/BuildacompleteStoredProcedurebasedData.5_13228/BasicCRUDproperties_thumb.png" width="203" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;This also requires you to consider what to do when updating your own script. What do you do if you make a change or fix a bug in your own script? Should you create a new id or keep the old one? One option would be to create a new id every time you edit a script, but that is tedious and would also clutter the namespace with many versions of the same script.&lt;/p&gt;  &lt;div style="border-right: black 1px solid; border-top: black 1px solid; border-left: black 1px solid; border-bottom: black 1px solid"&gt;&lt;em&gt;&lt;font size="1"&gt;Recommended Reading&lt;/font&gt;&lt;/em&gt;     &lt;ul&gt;     &lt;li&gt;&lt;a href="http://www.amazon.com/gp/product/073562206X?ie=UTF8&amp;amp;tag=zacsfia-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=073562206X"&gt;Programming Microsoft ADO.NET 2.0 Core Reference&lt;/a&gt;&lt;img style="margin: 0px; border-top-style: none! important; border-right-style: none! important; border-left-style: none! important; border-bottom-style: none! important" height="1" alt="" src="http://www.assoc-amazon.com/e/ir?t=zacsfia-20&amp;amp;l=as2&amp;amp;o=1&amp;amp;a=073562206X" width="1" border="0" /&gt; &lt;/li&gt;      &lt;li&gt;&lt;a href="http://www.amazon.com/gp/product/0596004796?ie=UTF8&amp;amp;tag=zacsfia-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=0596004796"&gt;Programming SQL Server 2005&lt;/a&gt;&lt;img style="margin: 0px; border-top-style: none! important; border-right-style: none! important; border-left-style: none! important; border-bottom-style: none! important" height="1" alt="" src="http://www.assoc-amazon.com/e/ir?t=zacsfia-20&amp;amp;l=as2&amp;amp;o=1&amp;amp;a=0596004796" width="1" border="0" /&gt; &lt;/li&gt;      &lt;li&gt;&lt;a href="http://www.amazon.com/gp/product/0672328240?ie=UTF8&amp;amp;tag=zacsfia-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=0672328240"&gt;Microsoft(R) SQL Server 2005 Unleashed&lt;/a&gt;&lt;img style="margin: 0px; border-top-style: none! important; border-right-style: none! important; border-left-style: none! important; border-bottom-style: none! important" height="1" alt="" src="http://www.assoc-amazon.com/e/ir?t=zacsfia-20&amp;amp;l=as2&amp;amp;o=1&amp;amp;a=0672328240" width="1" border="0" /&gt; &lt;/li&gt;   &lt;/ul&gt; &lt;/div&gt;  &lt;p&gt;For my scripts, if the change is small and does not cause a breaking change in the interface then I keep the same id and I add a version to the Title and update the minor version number. If the change is major, then I create a new id and update the Title of the script to include a version number and update the major or minor version number. &lt;/p&gt;  &lt;p&gt;In this example, I'm going to modify the SQL that the stored procedures produce, so I'm only going to update the minor version number and keep the same id.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://zacksfiasco.com/blogimages/BuildacompleteStoredProcedurebasedData.5_13228/BasicCRUDpropertiesupdated.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="371" alt="Basic CRUD properties (updated)" src="http://zacksfiasco.com/blogimages/BuildacompleteStoredProcedurebasedData.5_13228/BasicCRUDpropertiesupdated_thumb.png" width="206" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;As you can see from the script properties, the CRUD script is written in JScript. This script has the following basic format. &lt;/p&gt;  &lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;var&lt;/span&gt; fkProcList = &lt;span class="kwrd"&gt;new&lt;/span&gt; Array();

&lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;var&lt;/span&gt; i = 0; i &amp;lt; tablenames.Count; i++)
{
    &lt;span class="rem"&gt;// Loop through all the columns of the table &lt;/span&gt;
    &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;var&lt;/span&gt; j = 0; j &amp;lt; tableMeta.Columns.Count; j++) 
    {

    }

%&amp;gt;
Stored procedures
&amp;lt;%

    &lt;span class="kwrd"&gt;for&lt;/span&gt;(&lt;span class="kwrd"&gt;var&lt;/span&gt; x = 0; x &amp;lt; tableMeta.ForeignKeys.Count; x++)
    {
%&amp;gt;
SelectByFK procedures
&amp;lt;%
    }

    &lt;span class="rem"&gt;// Save this set of procedures to disk&lt;/span&gt;
    output.save(filename, &lt;span class="kwrd"&gt;false&lt;/span&gt;);
    buffer += output.text;
    output.clear();
}

output.write(buffer);&lt;/pre&gt;
&lt;style type="text/css"&gt;














.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;There is a lot left out of this skeleton, but essentially the script loops through each table and processes each column. The script then creates the Select, Select All, Insert, Update, and Delete procedures. Then the script examines the foreign keys and creates the SelectBy Foreign key procedures. Then all of the TSQL is written to a file and the process starts over with the next table.&lt;/p&gt;

&lt;p&gt;The CRUD script v1.0 produces the following TSQL for INSERT and UPDATE.&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: green"&gt;-- Proc: Table1Insert
-- This proc was created by script. You can edit it, but if you do
-- then DO NOT regenerate it from the script or you will loose your edits.
-- &amp;lt;MetaData entityName=&amp;quot;Table1&amp;quot; commandType=&amp;quot;Insert&amp;quot;/&amp;gt;
&lt;/span&gt;&lt;span style="color: blue"&gt;CREATE PROCEDURE &lt;/span&gt;[api].[Table1Insert]
(
    @Table1Id uniqueidentifier,
    @Col1 &lt;span style="color: blue"&gt;varchar&lt;/span&gt;(50),
    @Col2 &lt;span style="color: blue"&gt;int &lt;/span&gt;= &lt;span style="color: blue"&gt;NULL&lt;/span&gt;,
    @rowversion &lt;span style="color: blue"&gt;timestamp OUTPUT
&lt;/span&gt;)
&lt;span style="color: blue"&gt;AS
BEGIN
    SET NOCOUNT ON
    

    INSERT INTO &lt;/span&gt;[dbo].[Table1]
    (
        [Table1Id],
        [Col1],
        [Col2]
    )
    &lt;span style="color: blue"&gt;VALUES
    &lt;/span&gt;(
        @Table1Id,
        @Col1,
        @Col2
    )

    &lt;span style="color: blue"&gt;SELECT         &lt;/span&gt;@rowversion = [rowversion]
    &lt;span style="color: blue"&gt;FROM &lt;/span&gt;[dbo].[Table1]
    &lt;span style="color: blue"&gt;WHERE         &lt;/span&gt;[Table1Id] = @Table1Id;

    &lt;span style="color: blue"&gt;RETURN &lt;/span&gt;@@Error
&lt;span style="color: blue"&gt;END
&lt;/span&gt;GO&lt;/pre&gt;

&lt;p&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: green"&gt;-- Proc: Table1Update
-- This proc was created by script. You can edit it, but if you do
-- then DO NOT regenerate it from the script or you will loose your edits.
-- &amp;lt;MetaData entityName=&amp;quot;Table1&amp;quot; commandType=&amp;quot;Update&amp;quot;/&amp;gt;
&lt;/span&gt;&lt;span style="color: blue"&gt;CREATE PROCEDURE &lt;/span&gt;[api].[Table1Update]
(
    @Table1Id uniqueidentifier,
    @Col1 &lt;span style="color: blue"&gt;varchar&lt;/span&gt;(50),
    @Col2 &lt;span style="color: blue"&gt;int &lt;/span&gt;= &lt;span style="color: blue"&gt;NULL&lt;/span&gt;,
    @rowversion &lt;span style="color: blue"&gt;timestamp OUTPUT
&lt;/span&gt;)
&lt;span style="color: blue"&gt;AS
BEGIN
    SET NOCOUNT ON
    DECLARE &lt;/span&gt;@t &lt;span style="color: blue"&gt;TABLE&lt;/span&gt;(x &lt;span style="color: blue"&gt;int&lt;/span&gt;);    

    
    &lt;span style="color: blue"&gt;UPDATE &lt;/span&gt;[dbo].[Table1]
    &lt;span style="color: blue"&gt;SET
        &lt;/span&gt;[Table1Id] = @Table1Id,
        [Col1] = @Col1,
        [Col2] = @Col2
    &lt;span style="color: blue"&gt;OUTPUT &lt;/span&gt;1 &lt;span style="color: blue"&gt;into &lt;/span&gt;@t(x)
    &lt;span style="color: blue"&gt;WHERE 
        &lt;/span&gt;[Table1Id] = @Table1Id &lt;span style="color: blue"&gt;AND
        &lt;/span&gt;[rowversion] = @rowversion

    &lt;span style="color: blue"&gt;IF&lt;/span&gt;(&lt;span style="color: blue"&gt;SELECT COUNT&lt;/span&gt;(*) &lt;span style="color: blue"&gt;FROM &lt;/span&gt;@t) = 0
    &lt;span style="color: blue"&gt;BEGIN
        RAISERROR&lt;/span&gt;(&lt;span style="color: #a31515"&gt;'Concurrency Error'&lt;/span&gt;,16,1)
    &lt;span style="color: blue"&gt;END

    SELECT         &lt;/span&gt;@rowversion = [rowversion]
    &lt;span style="color: blue"&gt;FROM &lt;/span&gt;[dbo].[Table1]
    &lt;span style="color: blue"&gt;WHERE         &lt;/span&gt;[Table1Id] = @Table1Id;


    &lt;span style="color: blue"&gt;RETURN &lt;/span&gt;@@Error
&lt;span style="color: blue"&gt;END
&lt;/span&gt;GO&lt;/pre&gt;

&lt;p&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These procedures add and update records to the table and then run a second query to retrieve the rowversion which is returned as a OUTPUT parameter. The purpose of this is to allow an application to continue to use the data they have and if necessary perform an update. If the rowversion wasn't returned, then the application would have to query the entire record again in order to perform an update.&lt;/p&gt;

&lt;p&gt;I would like to modify the code generation script so that it produces INSERT procedures that don't need to run a separate query to return the rowversion.&lt;/p&gt;

&lt;p&gt;Using a text editor, I edited the above TSQL until it looked how I think I want it. After testing the new procedures, we end up with the following:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: green"&gt;-- Proc: Table1Insert
-- This proc was created by script. You can edit it, but if you do
-- then DO NOT regenerate it from the script or you will loose your edits.
-- &amp;lt;MetaData entityName=&amp;quot;Table1&amp;quot; commandType=&amp;quot;Insert&amp;quot;/&amp;gt;
&lt;/span&gt;&lt;span style="color: blue"&gt;CREATE PROCEDURE &lt;/span&gt;[api].[Table1Insert]
(
    @Table1Id uniqueidentifier,
    @Col1 &lt;span style="color: blue"&gt;varchar&lt;/span&gt;(50),
    @Col2 &lt;span style="color: blue"&gt;int &lt;/span&gt;= &lt;span style="color: blue"&gt;NULL&lt;/span&gt;,
    @rowversion &lt;span style="color: blue"&gt;timestamp = NULL OUTPUT
&lt;/span&gt;)
&lt;span style="color: blue"&gt;AS
BEGIN
    SET NOCOUNT ON
    
    DECLARE &lt;/span&gt;@t &lt;span style="color: blue"&gt;TABLE
    &lt;/span&gt;(
        [&lt;span style="color: blue"&gt;rowversion] binary(8)
    &lt;/span&gt;);

    &lt;span style="color: blue"&gt;INSERT INTO &lt;/span&gt;[dbo].[Table1]
    (
        [Table1Id],
        [Col1],
        [Col2]
    )
    &lt;span style="color: blue"&gt;OUTPUT 
        rowversion
        INTO &lt;/span&gt;@t
        (
            [&lt;span style="color: blue"&gt;rowversion]
        &lt;/span&gt;)
    &lt;span style="color: blue"&gt;VALUES
    &lt;/span&gt;(
        @Table1Id,
        @Col1,
        @Col2
    )

    &lt;span style="color: blue"&gt;SELECT
        &lt;/span&gt;@rowversion = [rowversion]
    &lt;span style="color: blue"&gt;FROM &lt;/span&gt;@t

    &lt;span style="color: blue"&gt;RETURN &lt;/span&gt;@@Error
&lt;span style="color: blue"&gt;END
&lt;/span&gt;GO

&lt;span style="color: green"&gt;-- Proc: Table1Update
-- This proc was created by script. You can edit it, but if you do
-- then DO NOT regenerate it from the script or you will loose your edits.
-- &amp;lt;MetaData entityName=&amp;quot;Table1&amp;quot; commandType=&amp;quot;Update&amp;quot;/&amp;gt;
&lt;/span&gt;&lt;span style="color: blue"&gt;CREATE PROCEDURE &lt;/span&gt;[api].[Table1Update]
(
    @Table1Id uniqueidentifier,
    @Col1 &lt;span style="color: blue"&gt;varchar&lt;/span&gt;(50),
    @Col2 &lt;span style="color: blue"&gt;int &lt;/span&gt;= &lt;span style="color: blue"&gt;NULL&lt;/span&gt;,
    @rowversion &lt;span style="color: blue"&gt;timestamp OUTPUT
&lt;/span&gt;)
&lt;span style="color: blue"&gt;AS
BEGIN
    SET NOCOUNT ON
    DECLARE &lt;/span&gt;@t &lt;span style="color: blue"&gt;TABLE
    &lt;/span&gt;(
        [rowversion] &lt;span style="color: blue"&gt;binary(8)
    &lt;/span&gt;);
    
    &lt;span style="color: blue"&gt;UPDATE &lt;/span&gt;[dbo].[Table1]
    &lt;span style="color: blue"&gt;SET
        &lt;/span&gt;[Table1Id] = @Table1Id,
        [Col1] = @Col1,
        [Col2] = @Col2
    &lt;span style="color: blue"&gt;OUTPUT
        &lt;/span&gt;[rowversion]
        &lt;span style="color: blue"&gt;into &lt;/span&gt;@t
        (
            [rowversion]
        )
    &lt;span style="color: blue"&gt;WHERE 
        &lt;/span&gt;[Table1Id] = @Table1Id &lt;span style="color: blue"&gt;AND
        &lt;/span&gt;[rowversion] = @rowversion

    &lt;span style="color: blue"&gt;IF&lt;/span&gt;(&lt;span style="color: blue"&gt;SELECT COUNT&lt;/span&gt;(*) &lt;span style="color: blue"&gt;FROM &lt;/span&gt;@t) = 0
    &lt;span style="color: blue"&gt;BEGIN
        RAISERROR&lt;/span&gt;(&lt;span style="color: #a31515"&gt;'Concurrency Error'&lt;/span&gt;,16,1)
    &lt;span style="color: blue"&gt;END

    SELECT
        &lt;/span&gt;@rowversion = [rowversion]
    &lt;span style="color: blue"&gt;FROM &lt;/span&gt;@t
    &lt;span style="color: blue"&gt;WHERE
        &lt;/span&gt;[Table1Id] = @Table1Id;

    &lt;span style="color: blue"&gt;RETURN &lt;/span&gt;@@Error
&lt;span style="color: blue"&gt;END
&lt;/span&gt;GO&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;The updated procedures use the new OUTPUT clause to return the rowversion to a table variable. We can then query the table variable for the rowversion and return it in the OUTPUT parameter. The query against the table variable should be much faster than a query against the main table since the table variable has fewer records and is in memory.&lt;/p&gt;

&lt;p&gt;In order to produce this new TSQL we need to modify our code generation script. &lt;/p&gt;

&lt;p&gt;When the script loops over each column, it builds the pieces it needs to build the the procedures. The variable insertParams contains the string of comma seperated parameters of the Insert procedure. The variable insertFields is the list of columns to be inserted by the insert statement. The variable insertValues maps the insert parameters to the columns. &lt;/p&gt;

&lt;p&gt;The section of code that produces the INSERT procedure looks like the following:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="rem"&gt;-- Proc: &amp;lt;%= insertProcName %&amp;gt;&lt;/span&gt;
&lt;span class="rem"&gt;-- This proc was created by script. You can edit it, but if you do&lt;/span&gt;
&lt;span class="rem"&gt;-- then DO NOT regenerate it from the script or you will loose your edits.&lt;/span&gt;
&lt;span class="rem"&gt;-- &amp;lt;MetaData entityName=&amp;quot;&amp;lt;%=tablename%&amp;gt;&amp;quot; commandType=&amp;quot;Insert&amp;quot;/&amp;gt;&lt;/span&gt;
&lt;span class="kwrd"&gt;CREATE&lt;/span&gt; &lt;span class="kwrd"&gt;PROCEDURE&lt;/span&gt; [&amp;lt;%=mySchema%&amp;gt;].[&amp;lt;%= insertProcName %&amp;gt;]
(
&amp;lt;%= insertParams %&amp;gt;
)
&lt;span class="kwrd"&gt;AS&lt;/span&gt;
&lt;span class="kwrd"&gt;BEGIN&lt;/span&gt;
    &lt;span class="kwrd"&gt;SET&lt;/span&gt; NOCOUNT &lt;span class="kwrd"&gt;ON&lt;/span&gt;
    &amp;lt;% &lt;span class="kwrd"&gt;if&lt;/span&gt;(updatedOn == &lt;span class="kwrd"&gt;true&lt;/span&gt;) { %&amp;gt;
    &lt;span class="kwrd"&gt;set&lt;/span&gt; @UpdatedOn = getdate();
    &amp;lt;%}%&amp;gt;

    INSERT &lt;span class="kwrd"&gt;INTO&lt;/span&gt; &amp;lt;%= tablenameFull %&amp;gt;
    (
&amp;lt;%= insertFields %&amp;gt;
    )
    &lt;span class="kwrd"&gt;VALUES&lt;/span&gt;
    (
&amp;lt;%= insertValues %&amp;gt;
    )
&amp;lt;%= (insertAutoKeyCode == &amp;quot;&amp;quot; ? &amp;quot;&amp;quot; : &amp;quot;\r\n&amp;quot; + insertAutoKeyCode) %&amp;gt;&amp;lt;%

&lt;span class="kwrd"&gt;if&lt;/span&gt; (hasComputedFields) 
{
    insertComputedCode += &amp;quot;\r\n\tFROM &amp;quot; + tablenameFull + &amp;quot;\r\n&amp;quot;;
    insertComputedCode += &amp;quot;\tWHERE &amp;quot; + deleteWhere + &amp;quot;;\r\n&amp;quot;;
}

%&amp;gt;
&amp;lt;%=insertComputedCode%&amp;gt;
    &lt;span class="kwrd"&gt;RETURN&lt;/span&gt; &lt;span class="preproc"&gt;@@Error&lt;/span&gt;
&lt;span class="kwrd"&gt;END&lt;/span&gt;
&lt;span class="kwrd"&gt;GO&lt;/span&gt;&lt;/pre&gt;
&lt;style type="text/css"&gt;













.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;The deleteWhere variable may stand out as being out of place. This variable contains the code for the delete WHERE clause, but some of the other procedures require exactly the same code so it gets reused in several places.&lt;/p&gt;

&lt;div style="border-right: black 1px solid; border-top: black 1px solid; border-left: black 1px solid; border-bottom: black 1px solid"&gt;&lt;em&gt;&lt;font size="1"&gt;Recommended Reading&lt;/font&gt;&lt;/em&gt; 

  &lt;ul&gt;
    &lt;li&gt;&lt;a href="http://www.amazon.com/gp/product/1590598938?ie=UTF8&amp;amp;tag=zacsfia-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=1590598938"&gt;Pro ASP.NET 3.5 in C# 2008, Second Edition (Expert's Voice in .Net)&lt;/a&gt;&lt;img style="border-right: medium none; border-top: medium none; margin: 0px; border-left: medium none; border-bottom: medium none" height="1" alt="" src="http://www.assoc-amazon.com/e/ir?t=zacsfia-20&amp;amp;l=as2&amp;amp;o=1&amp;amp;a=1590598938" width="1" border="0" /&gt; &lt;/li&gt;

    &lt;li&gt;&lt;a href="http://www.amazon.com/gp/product/159059794X?ie=UTF8&amp;amp;tag=zacsfia-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=159059794X"&gt;Pro T-SQL 2005 Programmer's Guide (Expert's Voice)&lt;/a&gt;&lt;img style="margin: 0px; border-top-style: none! important; border-right-style: none! important; border-left-style: none! important; border-bottom-style: none! important" height="1" alt="" src="http://www.assoc-amazon.com/e/ir?t=zacsfia-20&amp;amp;l=as2&amp;amp;o=1&amp;amp;a=159059794X" width="1" border="0" /&gt; &lt;/li&gt;

    &lt;li&gt;&lt;a href="http://www.amazon.com/gp/product/1590598938?ie=UTF8&amp;amp;tag=zacsfia-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=1590598938"&gt;Pro ASP.NET 3.5 in C# 2008, Second Edition (Expert's Voice in .Net)&lt;/a&gt;&lt;img style="border-right: medium none; border-top: medium none; margin: 0px; border-left: medium none; border-bottom: medium none" height="1" alt="" src="http://www.assoc-amazon.com/e/ir?t=zacsfia-20&amp;amp;l=as2&amp;amp;o=1&amp;amp;a=1590598938" width="1" border="0" /&gt; &lt;/li&gt;
  &lt;/ul&gt;
&lt;/div&gt;

&lt;p&gt;One of the things to notice is the computed fields section. In the current script, this is where the timestamp field value is retrieved since technically a timestamp is computed automatically. So when we change the code that returns the timestamp columns, this also needs to work for other computed columns.&lt;/p&gt;

&lt;p&gt;In order to retrieve the computed columns we need to create our table variable, specify our OUTPUT clause, copy the values from the table variable into the OUTPUT parameters. This is accomplished by using these three variables.&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;var&lt;/span&gt; insertComputedTableVar = &lt;span class="str"&gt;&amp;quot;&amp;quot;&lt;/span&gt;;    &lt;span class="rem"&gt;// generated TSQL to hold computed values&lt;/span&gt;
&lt;span class="kwrd"&gt;var&lt;/span&gt; insertComputedCode = &lt;span class="str"&gt;&amp;quot;&amp;quot;&lt;/span&gt;;    &lt;span class="rem"&gt;// generated TSQL to retrieve Computed values&lt;/span&gt;
&lt;span class="kwrd"&gt;var&lt;/span&gt; insertComputedReturn = &lt;span class="str"&gt;&amp;quot;&amp;quot;&lt;/span&gt;;    &lt;span class="rem"&gt;// code to return values into output parameters&lt;/span&gt;&lt;/pre&gt;
&lt;style type="text/css"&gt;










.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;You can see the first variable used in the script above, but we are going to modify the values it holds. The second two variables are new. In addition, we are getting rid of insertAutoKeyCode. AutoKeys are what MyGeneration calls like identity columns and in our modification they will be handled by the computed column code.&lt;/p&gt;

&lt;p&gt;The code below is executed inside a loop over each table's columns and populates our three variables. It uses a simple&amp;#160; pattern to append a comma and new line if there is more than one computed value. &lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="rem"&gt;// generate code to retrieve computed values on insert&lt;/span&gt;
&lt;span class="kwrd"&gt;if&lt;/span&gt; (column.IsComputed || column.IsAutoKey)
{
    hasComputedFields = &lt;span class="kwrd"&gt;true&lt;/span&gt;;
        
    &lt;span class="rem"&gt;// build the list of values to go in the&lt;/span&gt;
    &lt;span class="rem"&gt;// OUTPUT clause&lt;/span&gt;
    &lt;span class="kwrd"&gt;if&lt;/span&gt; (insertComputedCode != &lt;span class="str"&gt;&amp;quot;&amp;quot;&lt;/span&gt;) 
    {
        insertComputedCode += &lt;span class="str"&gt;&amp;quot;, \r\n&amp;quot;&lt;/span&gt;;
    }
    
    insertComputedCode += &lt;span class="str"&gt;&amp;quot;\t\tINSERTED.[&amp;quot;&lt;/span&gt; + column.Name + &lt;span class="str"&gt;&amp;quot;]&amp;quot;&lt;/span&gt;;
    
    &lt;span class="rem"&gt;// build the list of columns for the table variable&lt;/span&gt;
    &lt;span class="rem"&gt;// to hold the OUTPUT values&lt;/span&gt;
    &lt;span class="kwrd"&gt;if&lt;/span&gt;(insertComputedTableVar != &lt;span class="str"&gt;&amp;quot;&amp;quot;&lt;/span&gt;)
    {
        insertComputedTableVar += &lt;span class="str"&gt;&amp;quot;, \r\n&amp;quot;&lt;/span&gt;;
    }
    
    &lt;span class="kwrd"&gt;if&lt;/span&gt;(column.DataTypeName == &lt;span class="str"&gt;&amp;quot;timestamp&amp;quot;&lt;/span&gt;)
    {
        insertComputedTableVar += &lt;span class="str"&gt;&amp;quot;\t\t[&amp;quot;&lt;/span&gt; + column.Name + &lt;span class="str"&gt;&amp;quot;] binary(8)&amp;quot;&lt;/span&gt;;
    }
    &lt;span class="kwrd"&gt;else&lt;/span&gt;
    {
        insertComputedTableVar += &lt;span class="str"&gt;&amp;quot;\t\t[&amp;quot;&lt;/span&gt; + column.Name + &lt;span class="str"&gt;&amp;quot;] &amp;quot;&lt;/span&gt; + column.DataTypeNameComplete;
    }
    
    &lt;span class="rem"&gt;// build a list of select columns to return &lt;/span&gt;
    &lt;span class="rem"&gt;// output parameters&lt;/span&gt;
    &lt;span class="kwrd"&gt;if&lt;/span&gt;(insertComputedReturn != &lt;span class="str"&gt;&amp;quot;&amp;quot;&lt;/span&gt;)
    {
        insertComputedReturn += &lt;span class="str"&gt;&amp;quot;, \r\n&amp;quot;&lt;/span&gt;;
    }
    
    insertComputedReturn += &lt;span class="str"&gt;&amp;quot;\t\t@&amp;quot;&lt;/span&gt; + paramName + &lt;span class="str"&gt;&amp;quot; = [&amp;quot;&lt;/span&gt; + column.Name + &lt;span class="str"&gt;&amp;quot;]&amp;quot;&lt;/span&gt;;
}&lt;/pre&gt;
&lt;style type="text/css"&gt;










.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;Take note that this code contains a special case for timestamp in the table variable code that it generates. The table variable is used to store values that get spit out by the insert statement when we use an OUTPUT clause. So we declare a column in the table variable for each value we want to output and we create each column in the temp table to be the same data type as they are in the real table. The only problem is if we declare a timestamp column on our temp table, it wants to behave the way timestamp columns always behave and it will forbid you form trying to insert a value into it. The solution is to use a binary(8) column to store the timestamp and all is well.&lt;/p&gt;

&lt;p&gt;With this new code we can update our procedure generation script to the following.&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="rem"&gt;-- Proc: &amp;lt;%= insertProcName %&amp;gt;&lt;/span&gt;
&lt;span class="rem"&gt;-- This proc was created by script. You can edit it, but if you do&lt;/span&gt;
&lt;span class="rem"&gt;-- then DO NOT regenerate it from the script or you will loose your edits.&lt;/span&gt;
&lt;span class="rem"&gt;-- &amp;lt;MetaData entityName=&amp;quot;&amp;lt;%=tablename%&amp;gt;&amp;quot; commandType=&amp;quot;Insert&amp;quot;/&amp;gt;&lt;/span&gt;
&lt;span class="kwrd"&gt;CREATE&lt;/span&gt; &lt;span class="kwrd"&gt;PROCEDURE&lt;/span&gt; [&amp;lt;%=mySchema%&amp;gt;].[&amp;lt;%= insertProcName %&amp;gt;]
(
&amp;lt;%= insertParams %&amp;gt;
)
&lt;span class="kwrd"&gt;AS&lt;/span&gt;
&lt;span class="kwrd"&gt;BEGIN&lt;/span&gt;
    &lt;span class="kwrd"&gt;SET&lt;/span&gt; NOCOUNT &lt;span class="kwrd"&gt;ON&lt;/span&gt;
    &amp;lt;% &lt;span class="kwrd"&gt;if&lt;/span&gt;(hasComputedFields) { %&amp;gt;
    &lt;span class="kwrd"&gt;declare&lt;/span&gt; @t &lt;span class="kwrd"&gt;table&lt;/span&gt;
    (
&amp;lt;%=insertComputedTableVar%&amp;gt;
    )
    &amp;lt;% 
    }
    &lt;span class="kwrd"&gt;if&lt;/span&gt;(updatedOn == &lt;span class="kwrd"&gt;true&lt;/span&gt;) { %&amp;gt;
    &lt;span class="kwrd"&gt;set&lt;/span&gt; @UpdatedOn = getdate();
    &amp;lt;%
    }%&amp;gt;

    INSERT &lt;span class="kwrd"&gt;INTO&lt;/span&gt; &amp;lt;%= tablenameFull %&amp;gt;
    (
&amp;lt;%= insertFields %&amp;gt;
    )&amp;lt;% 
    &lt;span class="kwrd"&gt;if&lt;/span&gt;(hasComputedFields) { %&amp;gt;
    &lt;span class="kwrd"&gt;OUTPUT&lt;/span&gt;
&amp;lt;%=insertComputedCode%&amp;gt;
    &lt;span class="kwrd"&gt;INTO&lt;/span&gt; @t&amp;lt;%
    }%&amp;gt;
    &lt;span class="kwrd"&gt;VALUES&lt;/span&gt;
    (
&amp;lt;%= insertValues %&amp;gt;
    )
    &amp;lt;%&lt;span class="kwrd"&gt;if&lt;/span&gt;(hasComputedFields) { %&amp;gt;
    &lt;span class="kwrd"&gt;SELECT&lt;/span&gt;
&amp;lt;%=insertComputedReturn%&amp;gt;    
    &lt;span class="kwrd"&gt;FROM&lt;/span&gt; @t
    &amp;lt;%}%&amp;gt;
    &lt;span class="kwrd"&gt;RETURN&lt;/span&gt; &lt;span class="preproc"&gt;@@Error&lt;/span&gt;
&lt;span class="kwrd"&gt;END&lt;/span&gt;
&lt;span class="kwrd"&gt;GO&lt;/span&gt;&lt;/pre&gt;
&lt;style type="text/css"&gt;










.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;The same process is repeated for update and then all we have to do is regenerate our stored procedures.&lt;/p&gt;

&lt;p&gt;The final TSQL looks like this.&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="rem"&gt;-- Proc: Table1Insert&lt;/span&gt;
&lt;span class="rem"&gt;-- This proc was created by script. You can edit it, but if you do&lt;/span&gt;
&lt;span class="rem"&gt;-- then DO NOT regenerate it from the script or you will loose your edits.&lt;/span&gt;
&lt;span class="rem"&gt;-- &amp;lt;MetaData entityName=&amp;quot;Table1&amp;quot; commandType=&amp;quot;Insert&amp;quot;/&amp;gt;&lt;/span&gt;
&lt;span class="kwrd"&gt;CREATE&lt;/span&gt; &lt;span class="kwrd"&gt;PROCEDURE&lt;/span&gt; [api].[Table1Insert]
(
    @Table1Id uniqueidentifier,
    @Col1 &lt;span class="kwrd"&gt;varchar&lt;/span&gt;(50),
    @Col2 &lt;span class="kwrd"&gt;int&lt;/span&gt; = &lt;span class="kwrd"&gt;NULL&lt;/span&gt;,
    @rowversion &lt;span class="kwrd"&gt;timestamp&lt;/span&gt; = &lt;span class="kwrd"&gt;NULL&lt;/span&gt; &lt;span class="kwrd"&gt;OUTPUT&lt;/span&gt;
)
&lt;span class="kwrd"&gt;AS&lt;/span&gt;
&lt;span class="kwrd"&gt;BEGIN&lt;/span&gt;
    &lt;span class="kwrd"&gt;SET&lt;/span&gt; NOCOUNT &lt;span class="kwrd"&gt;ON&lt;/span&gt;
    
    &lt;span class="kwrd"&gt;declare&lt;/span&gt; @t &lt;span class="kwrd"&gt;table&lt;/span&gt;
    (
        [rowversion] &lt;span class="kwrd"&gt;binary&lt;/span&gt;(8)
    )
    

    INSERT &lt;span class="kwrd"&gt;INTO&lt;/span&gt; [dbo].[Table1]
    (
        [Table1Id],
        [Col1],
        [Col2]
    )
    &lt;span class="kwrd"&gt;OUTPUT&lt;/span&gt;
        INSERTED.[rowversion]
    &lt;span class="kwrd"&gt;INTO&lt;/span&gt; @t
    &lt;span class="kwrd"&gt;VALUES&lt;/span&gt;
    (
        @Table1Id,
        @Col1,
        @Col2
    )
    
    &lt;span class="kwrd"&gt;SELECT&lt;/span&gt;
        @rowversion = [rowversion]    
    &lt;span class="kwrd"&gt;FROM&lt;/span&gt; @t
    
    &lt;span class="kwrd"&gt;RETURN&lt;/span&gt; &lt;span class="preproc"&gt;@@Error&lt;/span&gt;
&lt;span class="kwrd"&gt;END&lt;/span&gt;
&lt;span class="kwrd"&gt;GO&lt;/span&gt;

&lt;span class="rem"&gt;-- Proc: Table1Update&lt;/span&gt;
&lt;span class="rem"&gt;-- This proc was created by script. You can edit it, but if you do&lt;/span&gt;
&lt;span class="rem"&gt;-- then DO NOT regenerate it from the script or you will loose your edits.&lt;/span&gt;
&lt;span class="rem"&gt;-- &amp;lt;MetaData entityName=&amp;quot;Table1&amp;quot; commandType=&amp;quot;Update&amp;quot;/&amp;gt;&lt;/span&gt;
&lt;span class="kwrd"&gt;CREATE&lt;/span&gt; &lt;span class="kwrd"&gt;PROCEDURE&lt;/span&gt; [api].[Table1Update]
(
    @Table1Id uniqueidentifier,
    @Col1 &lt;span class="kwrd"&gt;varchar&lt;/span&gt;(50),
    @Col2 &lt;span class="kwrd"&gt;int&lt;/span&gt;,
    @rowversion &lt;span class="kwrd"&gt;timestamp&lt;/span&gt; = &lt;span class="kwrd"&gt;NULL&lt;/span&gt; &lt;span class="kwrd"&gt;OUTPUT&lt;/span&gt;
)
&lt;span class="kwrd"&gt;AS&lt;/span&gt;
&lt;span class="kwrd"&gt;BEGIN&lt;/span&gt;
    &lt;span class="kwrd"&gt;SET&lt;/span&gt; NOCOUNT &lt;span class="kwrd"&gt;ON&lt;/span&gt;
    
    &lt;span class="kwrd"&gt;declare&lt;/span&gt; @t &lt;span class="kwrd"&gt;table&lt;/span&gt;
    (
        [rowversion] &lt;span class="kwrd"&gt;binary&lt;/span&gt;(8)
    )
    
    &lt;span class="kwrd"&gt;UPDATE&lt;/span&gt; [dbo].[Table1]
    &lt;span class="kwrd"&gt;SET&lt;/span&gt;
        [Table1Id] = @Table1Id,
        [Col1] = @Col1,
        [Col2] = @Col2
    &lt;span class="kwrd"&gt;OUTPUT&lt;/span&gt;
        INSERTED.[rowversion]
    &lt;span class="kwrd"&gt;INTO&lt;/span&gt; @t
    &lt;span class="kwrd"&gt;WHERE&lt;/span&gt; 
        [Table1Id] = @Table1Id &lt;span class="kwrd"&gt;AND&lt;/span&gt;
        [rowversion] = @rowversion

    &lt;span class="kwrd"&gt;IF&lt;/span&gt;(&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; &lt;span class="kwrd"&gt;COUNT&lt;/span&gt;(*) &lt;span class="kwrd"&gt;FROM&lt;/span&gt; @t) = 0
    &lt;span class="kwrd"&gt;BEGIN&lt;/span&gt;
        &lt;span class="kwrd"&gt;RAISERROR&lt;/span&gt;(&lt;span class="str"&gt;'Concurrency Error'&lt;/span&gt;,16,1)
    &lt;span class="kwrd"&gt;END&lt;/span&gt;

    &lt;span class="kwrd"&gt;SELECT&lt;/span&gt;
        @rowversion = [rowversion]    
    &lt;span class="kwrd"&gt;FROM&lt;/span&gt; @t
    &lt;span class="kwrd"&gt;RETURN&lt;/span&gt; &lt;span class="preproc"&gt;@@Error&lt;/span&gt;
&lt;span class="kwrd"&gt;END&lt;/span&gt;
&lt;span class="kwrd"&gt;GO&lt;/span&gt;&lt;/pre&gt;
&lt;style type="text/css"&gt;










.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;The updated code generation scripts are posted as &lt;a href="http://www.codeplex.com/ZFCGDAL/" target="_blank"&gt;Release 1.2&lt;/a&gt; on CodePlex. &lt;/p&gt;

&lt;p&gt;Give this a try in your own databases.&lt;/p&gt;

&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fblog.zacksfiasco.com%2f2008%2f01%2fbuild-complete-stored-procedure-based.html"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fblog.zacksfiasco.com%2f2008%2f01%2fbuild-complete-stored-procedure-based.html" border="0" alt="kick it on DotNetKicks.com" /&gt;&lt;/a&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6782310453584500629-112753301562904261?l=zacksfiasco.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zacksfiasco.blogspot.com/feeds/112753301562904261/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=6782310453584500629&amp;postID=112753301562904261' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6782310453584500629/posts/default/112753301562904261'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6782310453584500629/posts/default/112753301562904261'/><link rel='alternate' type='text/html' href='http://zacksfiasco.blogspot.com/2008/01/build-complete-stored-procedure-based.html' title='Build a complete Stored Procedure based Data Access Layer using Code Generation - Part 2'/><author><name>Zack</name><uri>http://www.blogger.com/profile/16452669760064159733</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='02342781909266978719'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6782310453584500629.post-6396362249467453111</id><published>2008-01-16T15:44:00.001-05:00</published><updated>2008-01-16T15:44:58.156-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='funny'/><title type='text'>Bill Gates' Last Day Video</title><content type='html'>&lt;p&gt;I just saw this and it was hilarious.&lt;/p&gt;  &lt;div class="wlWriterSmartContent" id="scid:5737277B-5D6D-4f48-ABFC-DD9C333F4C5D:4a36637f-ba9e-4e8c-ac90-a3264cb9489e" style="padding-right: 0px; display: inline; padding-left: 0px; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;&lt;div&gt;&lt;embed src="http://images.video.msn.com/flash/soapbox1_1.swf" quality="high" width="432" height="364" wmode="transparent" type="application/x-shockwave-flash" pluginspage="http://macromedia.com/go/getflashplayer" flashvars="c=v&amp;v=be9075bb-df0a-41c9-8d86-7ded46627e26&amp;ifs=true&amp;fr=msnvideo&amp;mkt=en-US&amp;brand=&amp;from=writer"&gt;&lt;/embed&gt;&lt;/div&gt;&lt;/div&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6782310453584500629-6396362249467453111?l=zacksfiasco.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zacksfiasco.blogspot.com/feeds/6396362249467453111/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=6782310453584500629&amp;postID=6396362249467453111' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6782310453584500629/posts/default/6396362249467453111'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6782310453584500629/posts/default/6396362249467453111'/><link rel='alternate' type='text/html' href='http://zacksfiasco.blogspot.com/2008/01/bill-gates-last-day-video.html' title='Bill Gates&amp;#39; Last Day Video'/><author><name>Zack</name><uri>http://www.blogger.com/profile/16452669760064159733</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='02342781909266978719'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6782310453584500629.post-3388870410379335182</id><published>2007-12-10T00:28:00.001-05:00</published><updated>2007-12-10T00:29:27.134-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ADO.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='sql server'/><category scheme='http://www.blogger.com/atom/ns#' term='TSQL'/><category scheme='http://www.blogger.com/atom/ns#' term='databinding'/><category scheme='http://www.blogger.com/atom/ns#' term='codegeneration'/><title type='text'>DAL scripts were updated</title><content type='html'>&lt;p&gt;svnbridge keeps crashing so I wasn't able to updated the code on Codeplex Source Code section hasn't been updated, but I posted a new release which is the templates in source code form.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6782310453584500629-3388870410379335182?l=zacksfiasco.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zacksfiasco.blogspot.com/feeds/3388870410379335182/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=6782310453584500629&amp;postID=3388870410379335182' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6782310453584500629/posts/default/3388870410379335182'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6782310453584500629/posts/default/3388870410379335182'/><link rel='alternate' type='text/html' href='http://zacksfiasco.blogspot.com/2007/12/dal-scripts-were-updated.html' title='DAL scripts were updated'/><author><name>Zack</name><uri>http://www.blogger.com/profile/16452669760064159733</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='02342781909266978719'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6782310453584500629.post-7171561221461839376</id><published>2007-12-07T17:47:00.001-05:00</published><updated>2007-12-10T00:29:48.276-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ADO.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='sql server'/><category scheme='http://www.blogger.com/atom/ns#' term='TSQL'/><category scheme='http://www.blogger.com/atom/ns#' term='databinding'/><category scheme='http://www.blogger.com/atom/ns#' term='codegeneration'/><title type='text'>DAL Code generation scripts are currently written for MyGeneration v1.2</title><content type='html'>&lt;p&gt;As chance would have it, MyGeneration released v1.3 the same day I published this project. The scripts &amp;quot;Data Access Layer (C#, SQL Server) v1.0&amp;quot; and &amp;quot;Data Access Layer (C#, SQL Server) v2.0&amp;quot; were written to take into account certain bugs in MyGeneration v1.2. Those bugs have been fixed in MyGeneration v1.3 so if you are seeing weird results like SQL Server datatypes being used as C# data types then this is why. &lt;/p&gt;  &lt;p&gt;An update will be released soon that fixes this problem and I will post an update here and on codeplex when this issue has been resolved.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6782310453584500629-7171561221461839376?l=zacksfiasco.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zacksfiasco.blogspot.com/feeds/7171561221461839376/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=6782310453584500629&amp;postID=7171561221461839376' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6782310453584500629/posts/default/7171561221461839376'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6782310453584500629/posts/default/7171561221461839376'/><link rel='alternate' type='text/html' href='http://zacksfiasco.blogspot.com/2007/12/dal-code-generation-scripts-are.html' title='DAL Code generation scripts are currently written for MyGeneration v1.2'/><author><name>Zack</name><uri>http://www.blogger.com/profile/16452669760064159733</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='02342781909266978719'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6782310453584500629.post-8015800504838980298</id><published>2007-12-07T02:33:00.001-05:00</published><updated>2009-02-27T13:53:30.413-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ADO.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='sql server'/><category scheme='http://www.blogger.com/atom/ns#' term='Zack&apos;s Fiasco DAL'/><category scheme='http://www.blogger.com/atom/ns#' term='TSQL'/><category scheme='http://www.blogger.com/atom/ns#' term='databinding'/><category scheme='http://www.blogger.com/atom/ns#' term='codegeneration'/><category scheme='http://www.blogger.com/atom/ns#' term='ORM'/><title type='text'>Build a complete Stored Procedure based Data Access Layer using Code Generation - Part 1</title><content type='html'>&lt;p&gt;&lt;em&gt;All code published in this article is published under the Microsoft Public License. See source code download for a copy of the license. &lt;/em&gt;&lt;/p&gt;  &lt;p&gt;&lt;em&gt;Copyright 2007 Zack Moore&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;Code can be downloaded from &lt;a href="http://www.codeplex.com/ZFCGDAL" target="_blank"&gt;here&lt;/a&gt;.&lt;/p&gt;  &lt;h4&gt;Intro&lt;/h4&gt;  &lt;p&gt;Data Access Layers are one of those problems that people keep coming up with solutions for. There are many reasons for this, but basically it boils down to two things. People are different and different people solve problems differently. Data is different and people need to access different kinds of data differently. &lt;/p&gt;  &lt;p&gt;I wanted to build something that was simple, easy to use, easy to extend, and compatible with data binding. I wanted to be able to automatically generate well written stored procedures for all the standard CRUD (&lt;u&gt;C&lt;/u&gt;reate &lt;u&gt;R&lt;/u&gt;ead &lt;u&gt;U&lt;/u&gt;pdate &lt;u&gt;D&lt;/u&gt;elete) and also allow me to add my own custom written stored procedures. I wanted to be able to call all of my stored procedures from .NET code without having to manually write all of the ADO.NET and I wanted the compiler to check my method names and my parameters like a regular .NET method. I wanted to be able to use data binding with objects instead of DataSets. And last, the data binding had to be two way and not just for display.&lt;/p&gt;  &lt;h4&gt;Code Generation&lt;/h4&gt;  &lt;p&gt;Code Generation is the act of having one computer program write another computer program and it is a great way to build components that repeat a pattern like stored procedures and ADO.NET code. &lt;/p&gt;  &lt;p&gt;There are different ways of performing code generation. One way is text output. A computer program can easily spit out a file containing C# or VB.NET or any language you want. That is how MyGeneration and CodeSmith work or you could write a program yourself that builds a code file. In .NET you could also use the Code DOM to write code using a structured framework.&lt;/p&gt;  &lt;p&gt;I use MyGeneration: &lt;a title="http://www.mygenerationsoftware.com/" href="http://www.mygenerationsoftware.com/"&gt;http://www.mygenerationsoftware.com/&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;div style="border-bottom: black 1px solid; border-left: black 1px solid; border-top: black 1px solid; border-right: black 1px solid"&gt;&lt;em&gt;&lt;font size="1"&gt;Recomended Reading&lt;/font&gt;&lt;/em&gt;     &lt;ul&gt;     &lt;li&gt;&lt;a href="http://www.amazon.com/gp/product/073562206X?ie=UTF8&amp;amp;tag=zacsfia-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=073562206X"&gt;Programming Microsoft ADO.NET 2.0 Core Reference&lt;/a&gt;&lt;img style="border-bottom-style: none !important; border-right-style: none !important; margin: 0px; border-top-style: none !important; border-left-style: none !important" border="0" alt="" src="http://www.assoc-amazon.com/e/ir?t=zacsfia-20&amp;amp;l=as2&amp;amp;o=1&amp;amp;a=073562206X" width="1" height="1" /&gt; &lt;/li&gt;      &lt;li&gt;&lt;a href="http://www.amazon.com/gp/product/0596004796?ie=UTF8&amp;amp;tag=zacsfia-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=0596004796"&gt;Programming SQL Server 2005&lt;/a&gt;&lt;img style="border-bottom-style: none !important; border-right-style: none !important; margin: 0px; border-top-style: none !important; border-left-style: none !important" border="0" alt="" src="http://www.assoc-amazon.com/e/ir?t=zacsfia-20&amp;amp;l=as2&amp;amp;o=1&amp;amp;a=0596004796" width="1" height="1" /&gt; &lt;/li&gt;      &lt;li&gt;&lt;a href="http://www.amazon.com/gp/product/0672328240?ie=UTF8&amp;amp;tag=zacsfia-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=0672328240"&gt;Microsoft(R) SQL Server 2005 Unleashed&lt;/a&gt;&lt;img style="border-bottom-style: none !important; border-right-style: none !important; margin: 0px; border-top-style: none !important; border-left-style: none !important" border="0" alt="" src="http://www.assoc-amazon.com/e/ir?t=zacsfia-20&amp;amp;l=as2&amp;amp;o=1&amp;amp;a=0672328240" width="1" height="1" /&gt; &lt;/li&gt;   &lt;/ul&gt; &lt;/div&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;MyGeneration is a free open source code code generation tool. Codge Generation scripts are writing like classic ASP. You use a set of tags to escape in and out of script text and script code. Usually these are the same tags as used in classic ASP &amp;lt;% and %&amp;gt; but they are configurable. My Generation supports writing scripts in VB Script, JScript, C#, and VB.NET. In addition to the code generation code, each script also supports a user interface section where you can prompt the user for code generation parameters. MyGeneration also supports saving the script parameters in a file so that you can run the script over and over without having to go through the UI each time so long as you don't need to change the parameters.&lt;/p&gt;  &lt;h4&gt;Stored Procedures&lt;/h4&gt;  &lt;p&gt;The first step in building a stored procedure based DAL is to generate your stored procedures. I started with an excellent script titled &amp;quot;Script Insert/Update/Delete Procedures for SQL Server&amp;quot; written by Justin Greenwood. Justin wrote his script in February of 2004 for SQL Server 2000&amp;#160; and I wanted my script to work with SQL Server 2005 so I needed to make some changes. In addition, I had some additional features that I wanted to add. &lt;/p&gt;  &lt;p&gt;I would like to extend my thanks to Justin for writing his very useful script and for giving me permission to redistribute my modified version.&lt;/p&gt;  &lt;p&gt;Justin's original script included a lot of features like its handling of primary keys in where clauses, treatment of computed and identity columns, and its use of timestamp columns in update procedures. &lt;/p&gt;  &lt;p&gt;I made a lot of changes, so I am sure that any mistakes are more likely mine.&lt;/p&gt;  &lt;p&gt;Lets take a look at how the script handles a simple sample database.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://zacksfiasco.com/blogimages/BuildacompleteStoredProcedurebasedDataAc_216/TestDatabaseDiagram.png"&gt;&lt;img style="border-right-width: 0px; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" border="0" alt="TestDatabaseDiagram" src="http://zacksfiasco.com/blogimages/BuildacompleteStoredProcedurebasedDataAc_216/TestDatabaseDiagram_thumb.png" width="416" height="137" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;One point I would like to make as we begin looking at generated code is that none of the generated code has a date emended in it. Its common for programmers to want to put a generated on date in code that is output so that they can tell when it was produced, but there is a very good reason not to. If you use source control, every time you check in a file your source control system checks to see if the file changed. If not, then it doesn't do anything, but if it did then it creates a new revision and checks in your changes. Now if you add a generated on date to your output, then every time you regenerate you create a new generated on date even if the actual code that was output didn't change at all. This means that your source control system has to create a new revision and it becomes harder for you to track real changes when you are having to sort through a bunch of revisions where only the dates changed. Let your source control system track when things changed. Leave dates and other unnecessary artifacts out of your generated code.&lt;/p&gt;  &lt;p&gt;To begin, run the script &amp;quot;Basic CRUD Plus SelectBy FK&amp;quot;. This script is under the MyGeneration namespace &amp;quot;ZacksFiasco.DataAccessLayer.SQLServer2005&amp;quot;. You should see a UI screen that looks like the following:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://zacksfiasco.com/blogimages/BuildacompleteStoredProcedurebasedDataAc_216/StoredProcUIScreen.png"&gt;&lt;img style="border-right-width: 0px; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" border="0" alt="StoredProcUIScreen" src="http://zacksfiasco.com/blogimages/BuildacompleteStoredProcedurebasedDataAc_216/StoredProcUIScreen_thumb.png" width="237" height="368" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;The first parameter is the path on your computer to write the stored procedure files to. For testing, you could leave it to the default. However, if you use this for a project then I suggest you point it to a folder in your project where you would like to store your stored procedure scripts.&lt;/p&gt;  &lt;p&gt;The second parameter is the SQL Server schema to store your procedures under. The UI defaults this to 'api'. You could put your procedures under 'dbo' but I suggest that you don't. Lots of things can put procedures into 'dbo'. In a later part of this series we will look at another code generation script that will take our stored procedures and build a .NET DAL and it will use the schema to filter only the stored procedures that we want. &lt;strong&gt;(Note: if you use 'api' or another schema that doesn't exist, the be sure to create that schema in your database before trying to load your stored procedures.)&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;The next parameter is the database to read.&lt;/p&gt;  &lt;p&gt;The last parameter is the set of tables to generate procedures for. One file will be generated for each table, so for our test two files while be generated: sql_procs_Table1.sql and sql_procs_Table2.sql.&lt;/p&gt;  &lt;h4&gt;Generated TSQL&lt;/h4&gt;  &lt;p&gt;This example generates 381 lines of TSQL so I won't be able to go over the entire output. Instead I will try to give a quick synopsis of the key points.&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;The insert statements are pretty basic. &lt;/p&gt;  &lt;pre class="code"&gt;&lt;span style="color: green"&gt;-- Proc: Table1Insert
-- This proc was created by script. You can edit it, but if you do
-- then DO NOT regenerate it from the script or you will loose your edits.
-- &amp;lt;MetaData entityName=&amp;quot;Table1&amp;quot; commandType=&amp;quot;Insert&amp;quot;/&amp;gt;
&lt;/span&gt;&lt;span style="color: blue"&gt;CREATE PROCEDURE &lt;/span&gt;[api].[Table1Insert]
(
    @Table1Id uniqueidentifier,
    @Col1 &lt;span style="color: blue"&gt;varchar&lt;/span&gt;(50),
    @Col2 &lt;span style="color: blue"&gt;int &lt;/span&gt;= &lt;span style="color: blue"&gt;NULL&lt;/span&gt;,
    @rowversion &lt;span style="color: blue"&gt;timestamp OUTPUT
&lt;/span&gt;)
&lt;span style="color: blue"&gt;AS
BEGIN
    SET NOCOUNT ON
    

    INSERT INTO &lt;/span&gt;[dbo].[Table1]
    (
        [Table1Id],
        [Col1],
        [Col2]
    )
    &lt;span style="color: blue"&gt;VALUES
    &lt;/span&gt;(
        @Table1Id,
        @Col1,
        @Col2
    )

    &lt;span style="color: blue"&gt;SELECT         &lt;/span&gt;@rowversion = [rowversion]
    &lt;span style="color: blue"&gt;FROM &lt;/span&gt;[dbo].[Table1]
    &lt;span style="color: blue"&gt;WHERE         &lt;/span&gt;[Table1Id] = @Table1Id;

    &lt;span style="color: blue"&gt;RETURN &lt;/span&gt;@@Error
&lt;span style="color: blue"&gt;END
&lt;/span&gt;GO&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;The stored procedure does not use newid() to generate the key. My personal preference is to generate the key in the application. There are many times when it is beneficial to know the key in the application before inserting the record. In this example we are using a uniqueidentifier which in .NET is a System.Guid but if we were using an int there are other ways of generating a unique value. &lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;div style="border-bottom: black 1px solid; border-left: black 1px solid; border-top: black 1px solid; border-right: black 1px solid"&gt;&lt;em&gt;&lt;font size="1"&gt;Recomended Reading&lt;/font&gt;&lt;/em&gt; 

  &lt;ul&gt;
    &lt;li&gt;&lt;a href="http://www.amazon.com/gp/product/1590598938?ie=UTF8&amp;amp;tag=zacsfia-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=1590598938"&gt;Pro ASP.NET 3.5 in C# 2008, Second Edition (Expert's Voice in .Net)&lt;/a&gt;&lt;img style="border-bottom: medium none; border-left: medium none; margin: 0px; border-top: medium none; border-right: medium none" border="0" alt="" src="http://www.assoc-amazon.com/e/ir?t=zacsfia-20&amp;amp;l=as2&amp;amp;o=1&amp;amp;a=1590598938" width="1" height="1" /&gt; &lt;/li&gt;

    &lt;li&gt;&lt;a href="http://www.amazon.com/gp/product/159059794X?ie=UTF8&amp;amp;tag=zacsfia-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=159059794X"&gt;Pro T-SQL 2005 Programmer's Guide (Expert's Voice)&lt;/a&gt;&lt;img style="border-bottom-style: none !important; border-right-style: none !important; margin: 0px; border-top-style: none !important; border-left-style: none !important" border="0" alt="" src="http://www.assoc-amazon.com/e/ir?t=zacsfia-20&amp;amp;l=as2&amp;amp;o=1&amp;amp;a=159059794X" width="1" height="1" /&gt; &lt;/li&gt;
  &lt;/ul&gt;
&lt;/div&gt;

&lt;p&gt;
  &lt;br /&gt;&lt;/p&gt;

&lt;p&gt;If you are concerned about SQL Server clustering of uniqueidentifiers I suggest that you use custom code to generate your Guids.&lt;/p&gt;

&lt;p&gt;If this table did use a auto-key, this script is smart enough return the generated value as an OUTPUT parameter.&lt;/p&gt;

&lt;p&gt;Also note that the rowversion column is returned as an OUTPUT parameter.&lt;/p&gt;

&lt;p&gt;Take a look at the last line of the comment section. It is an XML block. For now I will defer the discussion of this, but we will use this in our DAL code.&lt;/p&gt;

&lt;p&gt;The update procedure attempts to update the row in the database. Rowversion is an OUTPUT parameter which is in/out. First rowversion is used for optimistic concurrency. If the update succeeds, the the new rowversion is returned in the same parameter. If the update fails then an error is raised.&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: green"&gt;-- Proc: Table1Update
-- This proc was created by script. You can edit it, but if you do
-- then DO NOT regenerate it from the script or you will loose your edits.
-- &amp;lt;MetaData entityName=&amp;quot;Table1&amp;quot; commandType=&amp;quot;Update&amp;quot;/&amp;gt;
&lt;/span&gt;&lt;span style="color: blue"&gt;CREATE PROCEDURE &lt;/span&gt;[api].[Table1Update]
(
    @Table1Id uniqueidentifier,
    @Col1 &lt;span style="color: blue"&gt;varchar&lt;/span&gt;(50),
    @Col2 &lt;span style="color: blue"&gt;int &lt;/span&gt;= &lt;span style="color: blue"&gt;NULL&lt;/span&gt;,
    @rowversion &lt;span style="color: blue"&gt;timestamp OUTPUT
&lt;/span&gt;)
&lt;span style="color: blue"&gt;AS
BEGIN
    SET NOCOUNT ON
    DECLARE &lt;/span&gt;@t &lt;span style="color: blue"&gt;TABLE&lt;/span&gt;(x &lt;span style="color: blue"&gt;int&lt;/span&gt;);    

    
    &lt;span style="color: blue"&gt;UPDATE &lt;/span&gt;[dbo].[Table1]
    &lt;span style="color: blue"&gt;SET
        &lt;/span&gt;[Table1Id] = @Table1Id,
        [Col1] = @Col1,
        [Col2] = @Col2
    &lt;span style="color: blue"&gt;OUTPUT &lt;/span&gt;1 &lt;span style="color: blue"&gt;into &lt;/span&gt;@t(x)
    &lt;span style="color: blue"&gt;WHERE 
        &lt;/span&gt;[Table1Id] = @Table1Id &lt;span style="color: blue"&gt;AND
        &lt;/span&gt;[rowversion] = @rowversion

    &lt;span style="color: blue"&gt;IF&lt;/span&gt;(&lt;span style="color: blue"&gt;SELECT COUNT&lt;/span&gt;(*) &lt;span style="color: blue"&gt;FROM &lt;/span&gt;@t) = 0
    &lt;span style="color: blue"&gt;BEGIN
        RAISERROR&lt;/span&gt;(&lt;span style="color: #a31515"&gt;'Concurrency Error'&lt;/span&gt;,16,1)
    &lt;span style="color: blue"&gt;END

    SELECT         &lt;/span&gt;@rowversion = [rowversion]
    &lt;span style="color: blue"&gt;FROM &lt;/span&gt;[dbo].[Table1]
    &lt;span style="color: blue"&gt;WHERE         &lt;/span&gt;[Table1Id] = @Table1Id;


    &lt;span style="color: blue"&gt;RETURN &lt;/span&gt;@@Error
&lt;span style="color: blue"&gt;END
&lt;/span&gt;GO&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;The delete procedure is pretty simple. It just deletes by the primary key.&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: green"&gt;-- Proc: Table1Delete
-- This proc was created by script. You can edit it, but if you do
-- then DO NOT regenerate it from the script or you will loose your edits.
-- &amp;lt;MetaData entityName=&amp;quot;Table1&amp;quot; commandType=&amp;quot;Delete&amp;quot;/&amp;gt;
&lt;/span&gt;&lt;span style="color: blue"&gt;CREATE PROCEDURE &lt;/span&gt;[api].[Table1Delete]
(
    @Table1Id uniqueidentifier
)
&lt;span style="color: blue"&gt;AS
BEGIN
    SET NOCOUNT ON

    DELETE 
    FROM &lt;/span&gt;[dbo].[Table1]
    &lt;span style="color: blue"&gt;WHERE  
        &lt;/span&gt;[Table1Id] = @Table1Id

    &lt;span style="color: blue"&gt;RETURN &lt;/span&gt;@@Error
&lt;span style="color: blue"&gt;END
&lt;/span&gt;GO&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;The select procedure is also pretty basic. There is also a SelectAll procedure which is identical except it doesn't have a where clause.&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: green"&gt;-- Proc: Table1Select
-- This proc was created by script. You can edit it, but if you do
-- then DO NOT regenerate it from the script or you will loose your edits.
-- &amp;lt;MetaData entityName=&amp;quot;Table1&amp;quot; commandType=&amp;quot;Select&amp;quot;&amp;gt;&amp;lt;!--
--&amp;gt;&amp;lt;Keys&amp;gt;&amp;lt;!--
--&amp;gt;&amp;lt;Key&amp;gt;Table1Id&amp;lt;/Key&amp;gt;&amp;lt;!--
--&amp;gt;&amp;lt;/Keys&amp;gt;&amp;lt;!--
--&amp;gt;&amp;lt;/MetaData&amp;gt;
&lt;/span&gt;&lt;span style="color: blue"&gt;CREATE PROCEDURE &lt;/span&gt;[api].[Table1Select]
(
    @Table1Id uniqueidentifier
)
&lt;span style="color: blue"&gt;AS
BEGIN
    SET NOCOUNT ON

    select
        &lt;/span&gt;[Table1Id],
        [Col1],
        [Col2],
        [rowversion]
    &lt;span style="color: blue"&gt;FROM &lt;/span&gt;[dbo].[Table1]
    &lt;span style="color: blue"&gt;WHERE  
        &lt;/span&gt;[Table1Id] = @Table1Id

    &lt;span style="color: blue"&gt;RETURN &lt;/span&gt;@@Error
&lt;span style="color: blue"&gt;END
&lt;/span&gt;GO&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;One of the cool enhancements of my updated script is that it also generates SelectBy&amp;lt;ForeignKey&amp;gt; procedures. In this example we generated a procedure that selects records from Table2 where it matches the foreign key from Table1.&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: green"&gt;-- Proc: Table2SelectByTable1
-- This proc was created by script. You can edit it, but if you do
-- then DO NOT regenerate it from the script or you will loose your edits.
-- &amp;lt;MetaData entityName=&amp;quot;Table2&amp;quot; commandType=&amp;quot;Select&amp;quot;&amp;gt;&amp;lt;!--
--&amp;gt;&amp;lt;Keys&amp;gt;&amp;lt;!--
--&amp;gt;&amp;lt;Key&amp;gt;Table2Id&amp;lt;/Key&amp;gt;&amp;lt;!--
--&amp;gt;&amp;lt;/Keys&amp;gt;&amp;lt;!--
--&amp;gt;&amp;lt;/MetaData&amp;gt;
&lt;/span&gt;&lt;span style="color: blue"&gt;CREATE PROCEDURE &lt;/span&gt;[api].[Table2SelectByTable1]
(
    @Table1Id uniqueidentifier
)
&lt;span style="color: blue"&gt;AS
BEGIN
    SET NOCOUNT ON

    select
        &lt;/span&gt;[Table2Id],
        [Col1],
        [Table1Id],
        [UpdatedOn],
        [UpdatedBy]
    &lt;span style="color: blue"&gt;FROM &lt;/span&gt;[dbo].[Table2]
    &lt;span style="color: blue"&gt;WHERE  
        &lt;/span&gt;[Table1Id] = @Table1Id

    &lt;span style="color: blue"&gt;RETURN &lt;/span&gt;@@Error
&lt;span style="color: blue"&gt;END
&lt;/span&gt;GO&lt;/pre&gt;

&lt;p&gt;This script looks for certain column names that it treats differently. If a column is named 'UpdatedOn' then the script generates code to mark this parameter as an OUTPUT parameter in insert and update procedures and assigns the value from getdate(). A future enhancement might make these columns configurable instead of hard-coding the column names in the script.&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: green"&gt;-- Proc: Table2Insert
-- This proc was created by script. You can edit it, but if you do
-- then DO NOT regenerate it from the script or you will loose your edits.
-- &amp;lt;MetaData entityName=&amp;quot;Table2&amp;quot; commandType=&amp;quot;Insert&amp;quot;/&amp;gt;
&lt;/span&gt;&lt;span style="color: blue"&gt;CREATE PROCEDURE &lt;/span&gt;[api].[Table2Insert]
(
    @Table2Id uniqueidentifier,
    @Col1 &lt;span style="color: blue"&gt;varchar&lt;/span&gt;(50) = &lt;span style="color: blue"&gt;NULL&lt;/span&gt;,
    @Table1Id uniqueidentifier,
    @UpdatedOn &lt;span style="color: blue"&gt;datetime OUTPUT&lt;/span&gt;,
    @UpdatedBy uniqueidentifier = &lt;span style="color: blue"&gt;NULL
&lt;/span&gt;)
&lt;span style="color: blue"&gt;AS
BEGIN
    SET NOCOUNT ON
    
    set &lt;/span&gt;@UpdatedOn = &lt;span style="color: blue"&gt;getdate&lt;/span&gt;();
    

    &lt;span style="color: blue"&gt;INSERT INTO &lt;/span&gt;[dbo].[Table2]
    (
        [Table2Id],
        [Col1],
        [Table1Id],
        [UpdatedOn],
        [UpdatedBy]
    )
    &lt;span style="color: blue"&gt;VALUES
    &lt;/span&gt;(
        @Table2Id,
        @Col1,
        @Table1Id,
        @UpdatedOn,
        @UpdatedBy
    )


    &lt;span style="color: blue"&gt;RETURN &lt;/span&gt;@@Error
&lt;span style="color: blue"&gt;END
&lt;/span&gt;GO

&lt;span style="color: green"&gt;-- Proc: Table2Update
-- This proc was created by script. You can edit it, but if you do
-- then DO NOT regenerate it from the script or you will loose your edits.
-- &amp;lt;MetaData entityName=&amp;quot;Table2&amp;quot; commandType=&amp;quot;Update&amp;quot;/&amp;gt;
&lt;/span&gt;&lt;span style="color: blue"&gt;CREATE PROCEDURE &lt;/span&gt;[api].[Table2Update]
(
    @Table2Id uniqueidentifier,
    @Col1 &lt;span style="color: blue"&gt;varchar&lt;/span&gt;(50) = &lt;span style="color: blue"&gt;NULL&lt;/span&gt;,
    @Table1Id uniqueidentifier,
    @UpdatedOn &lt;span style="color: blue"&gt;datetime OUTPUT&lt;/span&gt;,
    @UpdatedBy uniqueidentifier = &lt;span style="color: blue"&gt;NULL
&lt;/span&gt;)
&lt;span style="color: blue"&gt;AS
BEGIN
    SET NOCOUNT ON
    
    set &lt;/span&gt;@UpdatedOn = &lt;span style="color: blue"&gt;getdate&lt;/span&gt;();
    
    &lt;span style="color: blue"&gt;UPDATE &lt;/span&gt;[dbo].[Table2]
    &lt;span style="color: blue"&gt;SET
        &lt;/span&gt;[Table2Id] = @Table2Id,
        [Col1] = @Col1,
        [Table1Id] = @Table1Id,
        [UpdatedOn] = @UpdatedOn,
        [UpdatedBy] = @UpdatedBy

    &lt;span style="color: blue"&gt;WHERE 
        &lt;/span&gt;[Table2Id] = @Table2Id



    &lt;span style="color: blue"&gt;RETURN &lt;/span&gt;@@Error
&lt;span style="color: blue"&gt;END
&lt;/span&gt;GO&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;I've talked mostly in this article about what the code generation script outputs and not how it generates code. The key to generating a good code generation script is to first decide what it should output for each scenario. The second key is a good meta-data engine. MyGeneration has an excellent meta-data engine and this is how I can easily gather information on the tables and their keys.&lt;/p&gt;

&lt;p&gt;Download the source code and take a look at how the scripts work.&lt;/p&gt;

&lt;p&gt;This concludes Part 1. We have seen how you can generate basic CRUD stored procedures for our database. The script generates good TSQL and includes features for rowversion/timestamp columns, UpdatedOn columns, identities, keys, and foreign keys.&lt;/p&gt;

&lt;p&gt;Part 2 will talk about taking these stored procedures, writing custom stored procedures and generating a basic Data Access Layer where we can call each of these stored procedures from .NET applications.&lt;/p&gt;
&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fblog.zacksfiasco.com%2f2007%2f12%2fbuild-complete-stored-procedure-based.html"&gt;&lt;img border="0" alt="kick it on DotNetKicks.com" src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fblog.zacksfiasco.com%2f2007%2f12%2fbuild-complete-stored-procedure-based.html" /&gt;&lt;/a&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6782310453584500629-8015800504838980298?l=zacksfiasco.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zacksfiasco.blogspot.com/feeds/8015800504838980298/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=6782310453584500629&amp;postID=8015800504838980298' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6782310453584500629/posts/default/8015800504838980298'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6782310453584500629/posts/default/8015800504838980298'/><link rel='alternate' type='text/html' href='http://zacksfiasco.blogspot.com/2007/12/build-complete-stored-procedure-based.html' title='Build a complete Stored Procedure based Data Access Layer using Code Generation - Part 1'/><author><name>Zack</name><uri>http://www.blogger.com/profile/16452669760064159733</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='02342781909266978719'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6782310453584500629.post-2261597845339412091</id><published>2007-11-26T21:52:00.001-05:00</published><updated>2008-01-22T13:15:42.460-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Web Navigation'/><category scheme='http://www.blogger.com/atom/ns#' term='ASP.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='SiteMapProvider'/><title type='text'>Make programmatic navigation easier in ASP.NET 2.0</title><content type='html'>&lt;p&gt;&lt;em&gt;All code published in this article is published under the Microsoft Public License. See source code download for a copy of the license. &lt;/em&gt;&lt;/p&gt;  &lt;p&gt;&lt;em&gt;Copyright 2007 Zack Moore&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;This is a small project I built earlier this year that I thought I would share.    &lt;br /&gt;ASP.NET web pages usually consist of several pages and users transition from page to page through a few different mechanisms. The simplest method is through clicking a link. Links can appear on menus or could be placed anywhere on a page. This is an example of a self guided transition.     &lt;br /&gt;Users can also be transitioned to different pages programmatically. Usually, this happens when a users performs an action like clicking a command button. When this happens, the page posts back to the server and the command button event handler runs. The event handler runs some code, perhaps making a decision, and then calls Response.Redirect() or perhaps Server.Transfer().     &lt;br /&gt;Most ASP.NET applications probably contain this same sequence many times. The code to perform the redirect should look something like this:     &lt;br /&gt;&lt;strong&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;pre class="code"&gt;&lt;span style="color: blue"&gt;string &lt;/span&gt;url = &lt;span style="color: blue"&gt;string&lt;/span&gt;.Format(&lt;span style="color: #a31515"&gt;&amp;quot;~/Output.aspx?ID={0}&amp;amp;StartDT={1}&amp;quot;&lt;/span&gt;, 
    Server.UrlEncode(id), Server.UrlEncode(StartDate.ToShortDateString())); 
Response.Redirect(&lt;span style="color: blue"&gt;this&lt;/span&gt;.ResolveUrl(url));&lt;/pre&gt;

&lt;p&gt;There are several problems with this code. While this is short at only 2 lines it is overly complex and repetitive. Second, the developer has to remember to URL Encode each query string parameter. The developer must also correctly type in the URL. Lastly, if a resource moves then every page that does a redirect to that resource must be edited and retested. 
  &lt;br /&gt;That's a lot for just a couple of lines of code. Wouldn't it be nicer if we could wrap some of the repetitive parts of this together and only have one place to change the URL if the page or resource moved? 

  &lt;br /&gt;As it turns out, ASP.NET 2.0 has already given us the base on which to build something to do just that. The &lt;a href="http://msdn2.microsoft.com/en-us/library/e468hxky(vs.80).aspx"&gt;ASP.NET Site Navigation system &lt;/a&gt;is very nice and it is now standard on most of the new web projects that I start. This system allows you to define the navigation of your web site and bind that information to either a standard databinding control or a specialized navigation control. You can define hierarchy and even limit which user roles can see which navigation nodes. This is a powerful framework, and we can extend it a little further. 

  &lt;br /&gt;What we want, is a system that will automatically perform URL Encoding for us, and which will allow us to redirect or transfer users to different pages without having to put the URL in each page. &lt;/p&gt;

&lt;div style="border-right: black 1px solid; border-top: black 1px solid; border-left: black 1px solid; border-bottom: black 1px solid"&gt;&lt;em&gt;&lt;font size="1"&gt;Recomended Reading&lt;/font&gt;&lt;/em&gt; 

  &lt;ul&gt;
    &lt;li&gt;&lt;a href="http://www.amazon.com/gp/product/1590598938?ie=UTF8&amp;amp;tag=zacsfia-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=1590598938"&gt;Pro ASP.NET 3.5 in C# 2008, Second Edition (Expert's Voice in .Net)&lt;/a&gt;&lt;img style="border-right: medium none; border-top: medium none; margin: 0px; border-left: medium none; border-bottom: medium none" height="1" alt="" src="http://www.assoc-amazon.com/e/ir?t=zacsfia-20&amp;amp;l=as2&amp;amp;o=1&amp;amp;a=1590598938" width="1" border="0" /&gt; &lt;/li&gt;

    &lt;li&gt;&lt;a href="http://www.amazon.com/gp/product/0789736659?ie=UTF8&amp;amp;tag=zacsfia-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=0789736659"&gt;The Microsoft Expression Web Developer's Guide to ASP.NET 3.5: Learn to create ASP.NET applications using Visual Web Developer 2008&lt;/a&gt;&lt;img style="border-right: medium none; border-top: medium none; margin: 0px; border-left: medium none; border-bottom: medium none" height="1" alt="" src="http://www.assoc-amazon.com/e/ir?t=zacsfia-20&amp;amp;l=as2&amp;amp;o=1&amp;amp;a=0789736659" width="1" border="0" /&gt; &lt;/li&gt;
  &lt;/ul&gt;
&lt;/div&gt;

&lt;p&gt;
  &lt;br /&gt;The ASP.NET Site Navigation by default uses an XML file, usually with the file extension &amp;quot;.sitemap&amp;quot;, to define the page locations and hierarchy. The Site Navigation system uses the provider model, so there are other providers that retrieve navigation information from other sources such as a database, however in this article we are focusing on the XmlSiteMapProvider. 

  &lt;br /&gt;Here is an example sitemap file: &lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color: #a31515"&gt;xml &lt;/span&gt;&lt;span style="color: red"&gt;version&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;1.0&lt;/span&gt;&amp;quot; &lt;span style="color: red"&gt;encoding&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;utf-8&lt;/span&gt;&amp;quot; &lt;span style="color: blue"&gt;?&amp;gt;
&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;siteMap &lt;/span&gt;&lt;span style="color: red"&gt;xmlns&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;http://schemas.microsoft.com/AspNet/SiteMap-File-1.0&lt;/span&gt;&amp;quot; &lt;span style="color: blue"&gt;&amp;gt;
    &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;siteMapNode &lt;/span&gt;&lt;span style="color: red"&gt;url&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;~/Default.aspx&lt;/span&gt;&amp;quot; &lt;span style="color: red"&gt;title&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;Home&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;&amp;gt;
        &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;siteMapNode &lt;/span&gt;&lt;span style="color: red"&gt;url&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;~/Details.aspx&lt;/span&gt;&amp;quot; &lt;span style="color: red"&gt;title&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;Details&lt;/span&gt;&amp;quot; &lt;span style="color: blue"&gt;/&amp;gt;
        &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;siteMapNode &lt;/span&gt;&lt;span style="color: red"&gt;url&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;~/ContactUs.aspx&lt;/span&gt;&amp;quot; &lt;span style="color: red"&gt;title&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;Contact Us&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;/&amp;gt;
    &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;siteMapNode&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;siteMap&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;This sitemap defines a Default page as the root of a hierarchy containing a &amp;#8216;Details&amp;#8217; and &amp;#8216;Contact Us&amp;#8217; page below it. The sitemap defines a title for each page and the URL for each page. This is a minimum set of information, but each node can have more information associated with it depending on your needs.&lt;/p&gt;

&lt;p&gt;When a menu or other control binds to this sitemap, the nodes for the correct level will be displayed. That means that you typically wouldn&amp;#8217;t put nodes in the sitemap that you wouldn&amp;#8217;t want displayed on a menu. Consequently, there could be many pages not represented in the sitemap, but that you may wish to be able to navigate to through code. &lt;/p&gt;

&lt;p&gt;In order to create a solution for this, I am going to add two new attributes to the siteMapNode. The first new attribute I am going to add is a &amp;#8216;visible&amp;#8217; attribute which can be either true or false. This will be used to tell the site map provider whether or not this node should be shown on a menu.&lt;/p&gt;

&lt;p&gt;In order to be able to direct our navigation to a particular node, we need to be able to uniquely identify a particular node. The site map provider assigns a key for each node already, but the XmlSiteMapProvider uses the URL as the key. This doesn&amp;#8217;t help us, so I am going to define a new attribute which I will call &amp;#8216;navigatorId&amp;#8217;. This can be any string which will be easy for you and your developers to use as an identifier for a page or resource. I could have used the already existing &amp;#8216;title&amp;#8217;, but there may be a scenario where you need more than one node to have the same title.&lt;/p&gt;

&lt;p&gt;If you are observant, you may have realized that siteMap defines a namespace and adding new attributes to siteMapNode would violate that schema. Luckily for use, the XmlSiteMapProvider doesn&amp;#8217;t use a validating XML Reader. However if it did, we could attempt to define a different schema which extended the default schema.&lt;/p&gt;

&lt;p&gt;Our new site sitemap file looks like this:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color: #a31515"&gt;xml &lt;/span&gt;&lt;span style="color: red"&gt;version&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;1.0&lt;/span&gt;&amp;quot; &lt;span style="color: red"&gt;encoding&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;utf-8&lt;/span&gt;&amp;quot; &lt;span style="color: blue"&gt;?&amp;gt;
&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;siteMap &lt;/span&gt;&lt;span style="color: red"&gt;xmlns&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;http://schemas.microsoft.com/AspNet/SiteMap-File-1.0&lt;/span&gt;&amp;quot; &lt;span style="color: blue"&gt;&amp;gt;
    &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;siteMapNode &lt;/span&gt;&lt;span style="color: red"&gt;url&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;~/Default.aspx&lt;/span&gt;&amp;quot; &lt;span style="color: red"&gt;title&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;Home&lt;/span&gt;&amp;quot; &lt;span style="color: red"&gt;navigatorId&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;Default&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;&amp;gt;
        &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;siteMapNode &lt;/span&gt;&lt;span style="color: red"&gt;url&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;~/Details.aspx&lt;/span&gt;&amp;quot; &lt;span style="color: red"&gt;title&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;Details&lt;/span&gt;&amp;quot; &lt;span style="color: red"&gt;navigatorId&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;Details&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;/&amp;gt;
        &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;siteMapNode &lt;/span&gt;&lt;span style="color: red"&gt;url&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;~/ContactUs.aspx&lt;/span&gt;&amp;quot; &lt;span style="color: red"&gt;title&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;Contact Us&lt;/span&gt;&amp;quot; &lt;span style="color: red"&gt;navigatorId&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;ContactUs&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;/&amp;gt;
        &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;siteMapNode &lt;/span&gt;&lt;span style="color: red"&gt;url&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;~/ContactUsEmailSent.aspx&lt;/span&gt;&amp;quot; &lt;span style="color: red"&gt;title&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;Contact Us&lt;/span&gt;&amp;quot; &lt;span style="color: red"&gt;navigatorId&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;ContactUsEmailSent&lt;/span&gt;&amp;quot; &lt;span style="color: red"&gt;visible&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;false&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;/&amp;gt;
    &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;siteMapNode&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;siteMap&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;The first change is adding a &amp;#8216;navigatorId&amp;#8217; attribute to each node. Notice that I also added a new node which has its &amp;#8216;visible&amp;#8217; attribute set to false.&lt;/p&gt;

&lt;p&gt;Just adding these attributes isn&amp;#8217;t enough. In order to take advantage of this new data, we need to extend the XmlSiteMapProvider and configure our new provider in the web.config file.&lt;/p&gt;

&lt;p&gt;In order to accomplish what we want, I could write our own site map provider and add all the features we want. But with only a few new features, we can get by simply extending the existing provider and this saves us the trouble of having to re-implement all the parts that we want to keep.&lt;/p&gt;

&lt;p&gt;Site map providers implement a method named IsAccessibleToUser() to determine if a node should be shown. This is typically used with security trimming, but we can extend this method along with our &amp;#8216;visible&amp;#8217; attribute to hide nodes that we don&amp;#8217;t want to show up on a menu. Take a look at the code below.&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;using &lt;/span&gt;System;
&lt;span style="color: blue"&gt;using &lt;/span&gt;System.Collections.Generic;
&lt;span style="color: blue"&gt;using &lt;/span&gt;System.Text;
&lt;span style="color: blue"&gt;using &lt;/span&gt;System.Web;

&lt;span style="color: blue"&gt;namespace &lt;/span&gt;ZacksFiasco.Web.Navigation
{
    &lt;span style="color: blue"&gt;public class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;NavigatorSiteMapProvider &lt;/span&gt;: &lt;span style="color: #2b91af"&gt;XmlSiteMapProvider
    &lt;/span&gt;{
        &lt;span style="color: blue"&gt;public override bool &lt;/span&gt;IsAccessibleToUser(&lt;span style="color: #2b91af"&gt;HttpContext &lt;/span&gt;context, &lt;span style="color: #2b91af"&gt;SiteMapNode &lt;/span&gt;node)
        {
            &lt;span style="color: blue"&gt;bool &lt;/span&gt;isVisible = &lt;span style="color: blue"&gt;true&lt;/span&gt;;
            &lt;span style="color: blue"&gt;bool &lt;/span&gt;rc = &lt;span style="color: blue"&gt;false&lt;/span&gt;;

            &lt;span style="color: blue"&gt;return &lt;/span&gt;rc;
        }        
    }
}&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;IsAccessibleToUser() takes two parameters: the current HttpContext and the SiteMapNode to test. SiteMapNode has an indexer that enumerates all of the attributes&amp;#160; of the node, including the custom attributes that we added. If you check the 'visible' attribute, you can determine if the node should be visible to the user or not.&amp;#160; You should be sure to test if the node that was passed to you is not null, that the attribute exists, and that the attribute value can be parsed into a boolean. For this implementation because this is a new attribute, if the attribute does not exists, then we are going to assume that the node is visible. &lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;if &lt;/span&gt;(node != &lt;span style="color: blue"&gt;null &lt;/span&gt;&amp;amp;&amp;amp; node[&lt;span style="color: #a31515"&gt;&amp;quot;visible&amp;quot;&lt;/span&gt;] != &lt;span style="color: blue"&gt;null &lt;/span&gt;&amp;amp;&amp;amp; &lt;span style="color: blue"&gt;bool&lt;/span&gt;.TryParse(node[&lt;span style="color: #a31515"&gt;&amp;quot;visible&amp;quot;&lt;/span&gt;], &lt;span style="color: blue"&gt;out &lt;/span&gt;isVisible))
{&lt;/pre&gt;

&lt;pre class="code"&gt;}&lt;/pre&gt;

&lt;p&gt;If the visible attribute exists and is true, you should not return true. For a correct implementation you should call down to the base class and return the base class's result. This allows the base class to have the final say and apply any logic that the base class implements. If the attribute does not exist, you should call down to the base class.&amp;#160; The only time you should return a value different than the base class is if the attribute exists, but is false. In that case, we definitely do not want to show the node and so we want to return false.&lt;/p&gt;

&lt;p&gt;The provider code ends up looking like this&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;using &lt;/span&gt;System;
&lt;span style="color: blue"&gt;using &lt;/span&gt;System.Collections.Generic;
&lt;span style="color: blue"&gt;using &lt;/span&gt;System.Text;
&lt;span style="color: blue"&gt;using &lt;/span&gt;System.Web;

&lt;span style="color: blue"&gt;namespace &lt;/span&gt;ZacksFiasco.Web.Navigation
{
    &lt;span style="color: blue"&gt;public class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;NavigatorSiteMapProvider &lt;/span&gt;: &lt;span style="color: #2b91af"&gt;XmlSiteMapProvider
    &lt;/span&gt;{
        &lt;span style="color: blue"&gt;public override bool &lt;/span&gt;IsAccessibleToUser(&lt;span style="color: #2b91af"&gt;HttpContext &lt;/span&gt;context, &lt;span style="color: #2b91af"&gt;SiteMapNode &lt;/span&gt;node)
        {
            &lt;span style="color: blue"&gt;bool &lt;/span&gt;isVisible = &lt;span style="color: blue"&gt;true&lt;/span&gt;;
            &lt;span style="color: blue"&gt;bool &lt;/span&gt;rc = &lt;span style="color: blue"&gt;false&lt;/span&gt;;

            &lt;span style="color: blue"&gt;if &lt;/span&gt;(node != &lt;span style="color: blue"&gt;null &lt;/span&gt;&amp;amp;&amp;amp; node[&lt;span style="color: #a31515"&gt;&amp;quot;visible&amp;quot;&lt;/span&gt;] != &lt;span style="color: blue"&gt;null &lt;/span&gt;&amp;amp;&amp;amp; &lt;span style="color: blue"&gt;bool&lt;/span&gt;.TryParse(node[&lt;span style="color: #a31515"&gt;&amp;quot;visible&amp;quot;&lt;/span&gt;], &lt;span style="color: blue"&gt;out &lt;/span&gt;isVisible))
            {
                &lt;span style="color: blue"&gt;if &lt;/span&gt;(isVisible)
                {
                    rc = &lt;span style="color: blue"&gt;base&lt;/span&gt;.IsAccessibleToUser(context, node);
                }
                &lt;span style="color: blue"&gt;else
                &lt;/span&gt;{
                    rc = &lt;span style="color: blue"&gt;false&lt;/span&gt;;
                }
            }
            &lt;span style="color: blue"&gt;else
            &lt;/span&gt;{
                rc = &lt;span style="color: blue"&gt;base&lt;/span&gt;.IsAccessibleToUser(context, node);
            }

            &lt;span style="color: blue"&gt;return &lt;/span&gt;rc;
        }        
    }
}&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;This is all we need to complete our site map provider. Just add this to your web application by inserting the following into your web.config. Just keep in mind that the value of type is &amp;quot;&amp;lt;namespace&amp;gt;.&amp;lt;type name&amp;gt;, &amp;lt;assembly&amp;gt;&amp;quot;. In this example, I also turned on security trimming. This is a good example of why we call down to the base class in our custom site map provider. If we returned true without calling the base class, then the base class would not have a chance to apply security trimming and possibly limit visibility to this node.&lt;/p&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;siteMap &lt;/span&gt;&lt;span style="color: red"&gt;defaultProvider&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;NavSiteMapProvider&lt;/span&gt;&amp;quot; &lt;span style="color: red"&gt;enabled&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;true&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;&amp;gt;
    &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;providers&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
        &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;add &lt;/span&gt;&lt;span style="color: red"&gt;name&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;NavSiteMapProvider&lt;/span&gt;&amp;quot;
             &lt;span style="color: red"&gt;description&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;Custom SiteMap provider.&lt;/span&gt;&amp;quot;
             &lt;span style="color: red"&gt;type&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;MyNavigation.MySiteMapProvider, MyNavigation&lt;/span&gt;&amp;quot;
             &lt;span style="color: red"&gt;siteMapFile&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;Web.sitemap&lt;/span&gt;&amp;quot;
             &lt;span style="color: red"&gt;securityTrimmingEnabled&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;true&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;/&amp;gt;
    &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;providers&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;siteMap&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;Now that our site map provider is in place, we want to take advantage of this new functionality. We can now navigate and perform Redirects by navigatorId by searching the site map provider for the correct node and building our URL. This is very useful, but still repetitive. We can improve this by removing manual string manipulation and wrapping the code that performs the URL Encoding. &lt;/p&gt;

&lt;p&gt;To begin, create a new class. I named my class Navigator. First, I gave Navigator a single private static method.&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;static string &lt;/span&gt;GetUrlFromKey(&lt;span style="color: blue"&gt;string &lt;/span&gt;navigatorId)&lt;/pre&gt;

&lt;p&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;This method takes as a parameter a navigatorId string. Using this id, we can search all nodes in the site map provider until we find a node that matches and return that node's URL. We can search the nodes using a foreach loop like the following:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;foreach &lt;/span&gt;(&lt;span style="color: #2b91af"&gt;SiteMapNode &lt;/span&gt;node &lt;span style="color: blue"&gt;in &lt;/span&gt;&lt;span style="color: #2b91af"&gt;SiteMap&lt;/span&gt;.Providers[&lt;span style="color: #a31515"&gt;&amp;quot;AspNetXmlSiteMapProvider&amp;quot;&lt;/span&gt;].RootNode.GetAllNodes())&lt;/pre&gt;

&lt;p&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;This loop statement uses the AspNetXmlSiteMapProvider. In the XML I provider for the web.conig I did not clear the provider list before adding our custom provider. There are reasons why we are not searching our own custom site map provider. First,since the name of the site map provider is specified in the web.config, I can't know at compile time what that name is. But I do know what the default name of the XmlSiteMapProvider is. Secondly, I want to be able to call IsAccessibleToUser() to check whether we should return this URL. If I call our custom provider, it will check the 'visible' flag which we don't want, since we want to be able to navigate to nodes that aren't visible on a menu. The solution is to use a provider that doesn't check the 'visible' flag when it evaluates accessibility. So in your loop, if the navigatorId matches and the node is accessible, then retrieve the URL from the node and return it.&lt;/p&gt;

&lt;p&gt;We can improve this by adding to our configuration file a list of the site map providers that we wish to search. This give us the flexibility to search any and as many providers as we wish and only the providers that we wish. &lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;static string &lt;/span&gt;GetUrlFromKey(&lt;span style="color: blue"&gt;string &lt;/span&gt;navigatorId)
{
    &lt;span style="color: #2b91af"&gt;SiteMapNode &lt;/span&gt;rcNode = &lt;span style="color: blue"&gt;null&lt;/span&gt;;
    &lt;span style="color: blue"&gt;string &lt;/span&gt;rc = &lt;span style="color: blue"&gt;string&lt;/span&gt;.Empty;

    &lt;span style="color: #2b91af"&gt;NavigatorSection &lt;/span&gt;ns = &lt;span style="color: #2b91af"&gt;ConfigurationManager&lt;/span&gt;.GetSection(&lt;span style="color: #a31515"&gt;&amp;quot;ZacksFiasco.Web.Navigation&amp;quot;&lt;/span&gt;) &lt;span style="color: blue"&gt;as &lt;/span&gt;&lt;span style="color: #2b91af"&gt;NavigatorSection&lt;/span&gt;;

    &lt;span style="color: blue"&gt;if &lt;/span&gt;(ns != &lt;span style="color: blue"&gt;null&lt;/span&gt;)
    {
        &lt;span style="color: blue"&gt;foreach &lt;/span&gt;(&lt;span style="color: #2b91af"&gt;ProviderElement &lt;/span&gt;pe &lt;span style="color: blue"&gt;in &lt;/span&gt;ns.SiteMapProvidersToSearch)
        {
&lt;span style="color: green"&gt;            &lt;/span&gt;&lt;span style="color: blue"&gt;foreach &lt;/span&gt;(&lt;span style="color: #2b91af"&gt;SiteMapNode &lt;/span&gt;node &lt;span style="color: blue"&gt;in &lt;/span&gt;&lt;span style="color: #2b91af"&gt;SiteMap&lt;/span&gt;.Providers[pe.SiteMapProviderName].RootNode.GetAllNodes())
            {
                &lt;span style="color: blue"&gt;if &lt;/span&gt;(node.IsAccessibleToUser(&lt;span style="color: #2b91af"&gt;HttpContext&lt;/span&gt;.Current) &amp;amp;&amp;amp; node[&lt;span style="color: #a31515"&gt;&amp;quot;navigatorId&amp;quot;&lt;/span&gt;] == navigatorId)
                {
                    rcNode = node;
                    &lt;span style="color: blue"&gt;break&lt;/span&gt;;
                }
            }

            &lt;span style="color: blue"&gt;if &lt;/span&gt;(rcNode != &lt;span style="color: blue"&gt;null&lt;/span&gt;)
            {
                &lt;span style="color: blue"&gt;break&lt;/span&gt;;
            }
        }
    }
    &lt;span style="color: blue"&gt;else
    &lt;/span&gt;{
        &lt;span style="color: blue"&gt;foreach &lt;/span&gt;(&lt;span style="color: #2b91af"&gt;SiteMapNode &lt;/span&gt;node &lt;span style="color: blue"&gt;in &lt;/span&gt;&lt;span style="color: #2b91af"&gt;SiteMap&lt;/span&gt;.Providers[&lt;span style="color: #a31515"&gt;&amp;quot;AspNetXmlSiteMapProvider&amp;quot;&lt;/span&gt;].RootNode.GetAllNodes())
        {
            &lt;span style="color: blue"&gt;if &lt;/span&gt;(node.IsAccessibleToUser(&lt;span style="color: #2b91af"&gt;HttpContext&lt;/span&gt;.Current) &amp;amp;&amp;amp; node[&lt;span style="color: #a31515"&gt;&amp;quot;navigatorId&amp;quot;&lt;/span&gt;] == navigatorId)
            {
                rcNode = node;
                &lt;span style="color: blue"&gt;break&lt;/span&gt;;
            }
        }
    }

    &lt;span style="color: blue"&gt;if &lt;/span&gt;(rcNode != &lt;span style="color: blue"&gt;null&lt;/span&gt;)
    {
        rc = rcNode.Url;
    }

    &lt;span style="color: blue"&gt;return &lt;/span&gt;rc;
}&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;Implementing this configuration is outside the scope of this article, but the resulting web.config ends up looking like this.&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;configuration&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
    &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;configSections&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
        &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;section &lt;/span&gt;&lt;span style="color: red"&gt;name&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;ZacksFiasco.Web.Navigation&lt;/span&gt;&amp;quot;
                 &lt;span style="color: red"&gt;type&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;ZacksFiasco.Web.Navigation.Configuration.NavigatorSection, ZacksFiasco.Web.Navigation&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;/&amp;gt;
    &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;configSections&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
    &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;ZacksFiasco.Web.Navigation&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
        &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;siteMapProvidersToSearch&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt; 
            &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;add &lt;/span&gt;&lt;span style="color: red"&gt;siteMapProviderName&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;AspNetXmlSiteMapProvider&lt;/span&gt;&amp;quot; &lt;span style="color: blue"&gt;/&amp;gt;          
        &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;siteMapProvidersToSearch&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;       
    &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;ZacksFiasco.Web.Navigation&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
    &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;system.web&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: blue"&gt;
        &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;siteMap &lt;/span&gt;&lt;span style="color: red"&gt;defaultProvider&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;NavSiteMapProvider&lt;/span&gt;&amp;quot; &lt;span style="color: red"&gt;enabled&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;true&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;&amp;gt;
            &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;providers&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
                &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;add &lt;/span&gt;&lt;span style="color: red"&gt;name&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;NavSiteMapProvider&lt;/span&gt;&amp;quot;
                     &lt;span style="color: red"&gt;description&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;Custom SiteMap provider.&lt;/span&gt;&amp;quot;
                     &lt;span style="color: red"&gt;type&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;ZacksFiasco.Web.Navigation.NavigatorSiteMapProvider, ZacksFiasco.Web.Navigation&lt;/span&gt;&amp;quot;
                     &lt;span style="color: red"&gt;siteMapFile&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;Web.sitemap&lt;/span&gt;&amp;quot;
                     &lt;span style="color: red"&gt;securityTrimmingEnabled&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;true&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;/&amp;gt;
            &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;providers&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
        &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;siteMap&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
    &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;system.web&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;configuration&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;Next, add to your class a member dictionary that takes a string as the key and a string as the value. Add a property get that wraps this dictionary. I called my property Parameters.&lt;/p&gt;

&lt;p&gt;Now add a string member named navigatorId and add a property with a get and set that wraps this member. &lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;string &lt;/span&gt;navigatorId;

&lt;span style="color: blue"&gt;public string &lt;/span&gt;NavigatorId
{
    &lt;span style="color: blue"&gt;get &lt;/span&gt;{ &lt;span style="color: blue"&gt;return &lt;/span&gt;navigatorId; }
    &lt;span style="color: blue"&gt;set &lt;/span&gt;{ navigatorId = &lt;span style="color: blue"&gt;value&lt;/span&gt;; }
}

&lt;span style="color: #2b91af"&gt;Dictionary&lt;/span&gt;&amp;lt;&lt;span style="color: blue"&gt;string&lt;/span&gt;, &lt;span style="color: blue"&gt;string&lt;/span&gt;&amp;gt; parameters;

&lt;span style="color: blue"&gt;public &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Dictionary&lt;/span&gt;&amp;lt;&lt;span style="color: blue"&gt;string&lt;/span&gt;, &lt;span style="color: blue"&gt;string&lt;/span&gt;&amp;gt; Parameters
{
    &lt;span style="color: blue"&gt;get &lt;/span&gt;{ &lt;span style="color: blue"&gt;return &lt;/span&gt;parameters; }
}&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;Override the ToString() member. In ToString(), perform the string concatenation necessary to build the URL. To retrieve the base URL, call the static method GetUrlFromKey() and pass the navigatorId member. To add the querystring parameters, perform a loop on the parameters dictionary and URL Encode each parameter. &lt;/p&gt;

&lt;p&gt;Now add two final methods. Redirect() and Transfer(). Redirect() performs a Response Redirect() and Transfer performs a server-side Transfer. To implement each of these, just get the current HttpContext and call to the appropriate context object. Use the ToString() method to build your URL and that is all you need. &lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;public void &lt;/span&gt;Transfer()
{
    &lt;span style="color: #2b91af"&gt;HttpContext&lt;/span&gt;.Current.Server.Transfer(ToString());
}

&lt;span style="color: blue"&gt;public void &lt;/span&gt;Redirect()
{
    &lt;span style="color: #2b91af"&gt;HttpContext&lt;/span&gt;.Current.Response.Redirect(ToString());
}&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;To use what you have written, the code to perform a programmatic navigation looks like the following:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;protected void &lt;/span&gt;btHidden1_Click(&lt;span style="color: blue"&gt;object &lt;/span&gt;sender, &lt;span style="color: #2b91af"&gt;EventArgs &lt;/span&gt;e)
{
    &lt;span style="color: #2b91af"&gt;Navigator &lt;/span&gt;n = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Navigator&lt;/span&gt;(&lt;span style="color: #a31515"&gt;&amp;quot;HiddenOne&amp;quot;&lt;/span&gt;);
    n.Parameters[&lt;span style="color: #a31515"&gt;&amp;quot;text&amp;quot;&lt;/span&gt;] = txParam.Text;
    n.Parameters[&lt;span style="color: #a31515"&gt;&amp;quot;time&amp;quot;&lt;/span&gt;] = &lt;span style="color: #2b91af"&gt;DateTime&lt;/span&gt;.Now.ToLongTimeString();

    n.Redirect();
}&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;Visit the &lt;a href="http://www.codeplex.com/ZFWebNavigation" target="_blank"&gt;ZacksFiasco.Web.Navigation Codeplex&lt;/a&gt; site to download the source code or download the assembly and begin using it in your projects right away.&lt;/p&gt;
&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fblog.zacksfiasco.com%2f2007%2f11%2fmake-programmatic-navigation-easier-in.html"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fblog.zacksfiasco.com%2f2007%2f11%2fmake-programmatic-navigation-easier-in.html" border="0" alt="kick it on DotNetKicks.com" /&gt;&lt;/a&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6782310453584500629-2261597845339412091?l=zacksfiasco.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zacksfiasco.blogspot.com/feeds/2261597845339412091/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=6782310453584500629&amp;postID=2261597845339412091' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6782310453584500629/posts/default/2261597845339412091'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6782310453584500629/posts/default/2261597845339412091'/><link rel='alternate' type='text/html' href='http://zacksfiasco.blogspot.com/2007/11/make-programmatic-navigation-easier-in.html' title='Make programmatic navigation easier in ASP.NET 2.0'/><author><name>Zack</name><uri>http://www.blogger.com/profile/16452669760064159733</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='02342781909266978719'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6782310453584500629.post-331274530654660448</id><published>2007-08-16T10:58:00.000-04:00</published><updated>2007-11-28T17:44:07.257-05:00</updated><title type='text'>First post</title><content type='html'>Hi, this is Zack. I thought I would give this blogging thing a try.

"Why?" you ask. Aren't there enough blogs already.

You are probably correct, but I thought I would add my voice to the cacophony.

So who am I and why would you care about what I have to say?

I live in Middle Georgia with my wife. I am a software developer so I plan to post some articles on technology that I'm interested in (ASP.NET, C#) and can share with other people.

I also participate in a few outdoor activities that I might write about. I love running. I do on and off road foot races every now and again. My favorite is the &lt;a href="http://www.danceswithdirt.com/"&gt;Dances With Dirt&lt;/a&gt;. I mountain bike some also, but I kindof suck at it. I did my first adventure race this year at the &lt;a href="http://www.ocmulgeear.org/"&gt;Ocmulgee Adventure race&lt;/a&gt; and that was a lot of fun.

Thats a good start. If any of this sounds interesting check back or keep reading.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6782310453584500629-331274530654660448?l=zacksfiasco.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zacksfiasco.blogspot.com/feeds/331274530654660448/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=6782310453584500629&amp;postID=331274530654660448' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6782310453584500629/posts/default/331274530654660448'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6782310453584500629/posts/default/331274530654660448'/><link rel='alternate' type='text/html' href='http://zacksfiasco.blogspot.com/2007/08/first-post.html' title='First post'/><author><name>Zack</name><uri>http://www.blogger.com/profile/16452669760064159733</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='02342781909266978719'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry></feed>