<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://weblogs.asp.net/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Ryan Whitaker</title><link>http://weblogs.asp.net/ryanw/default.aspx</link><description>Dishes of Ryan</description><dc:language>en</dc:language><generator>CommunityServer 2007 SP1 (Build: 20510.895)</generator><item><title>Transactions with TableAdapters, a lazy man's approach</title><link>http://weblogs.asp.net/ryanw/archive/2006/03/30/441529.aspx</link><pubDate>Thu, 30 Mar 2006 20:14:00 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:441529</guid><dc:creator>RyanW</dc:creator><slash:comments>21</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/ryanw/rsscomments.aspx?PostID=441529</wfw:commentRss><comments>http://weblogs.asp.net/ryanw/archive/2006/03/30/441529.aspx#comments</comments><description>&lt;p&gt;If you've used TableAdapters, you'll know that their ability to deal with transactions leaves a little to be desired.&amp;nbsp; Little?&amp;nbsp; Did I say "little"?&amp;nbsp; I mean "a lot".&lt;/p&gt; &lt;p&gt;&lt;a href="http://codebetter.com/blogs/sahil.malik/archive/2005/10/19/133309.aspx"&gt;Sahil Malik has a good slew of advice for people wanting to use transactions with TableAdapters.&lt;/a&gt;&amp;nbsp; Most people will probably just wrap everything up in a TransactionScope and be done with it, which is fine if you're not running a high-traffic site.&amp;nbsp; In doing this, you'll run into the annoyance of the transaction being promoted to the DTC, which is an expensive bit of "bling" to tango with.&lt;/p&gt; &lt;p&gt;For the people that don't like the whole promotion to DTC thing, they'll probably extend their TableAdapter's partial class and add a BeginTransaction method similar to what Sahil proposes.&lt;/p&gt; &lt;p&gt;For me, who's looking at a bajillion TableAdapters, with quite a few of those needing to operate within the scope of a transaction, I instead choose to play the Hacky card and just set the transaction on the TableAdapter's commands through a little bit of reflection.&amp;nbsp; Some may throw your hands up in the air on this.&amp;nbsp; I, however, love it, as it fits my purposes like a latex glove.&lt;/p&gt; &lt;p&gt;The code follows for my so-called TableAdapterHelper.&lt;/p&gt; &lt;p&gt;&lt;code&gt;using System;&lt;br /&gt;using System.Data;&lt;br /&gt;using System.Data.SqlClient;&lt;br /&gt;using System.Reflection;&lt;br /&gt;&lt;/code&gt;&lt;code&gt;&lt;br /&gt;public class TableAdapterHelper&lt;br /&gt;{&lt;br /&gt;public static SqlTransaction BeginTransaction(object tableAdapter)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return BeginTransaction(tableAdapter, IsolationLevel.ReadUncommitted);&lt;br /&gt;}&lt;/code&gt;&lt;/p&gt; &lt;p&gt;&lt;code&gt;public static SqlTransaction BeginTransaction(object tableAdapter, IsolationLevel isolationLevel)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; // get the table adapter's type&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Type type = tableAdapter.GetType();&lt;/code&gt;&lt;/p&gt; &lt;p&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; // get the connection on the adapter&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; SqlConnection connection = GetConnection(tableAdapter);&lt;/code&gt;&lt;/p&gt; &lt;p&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; // make sure connection is open to start the transaction&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (connection.State == ConnectionState.Closed)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/code&gt;&lt;code&gt;connection.Open();&lt;/code&gt;&lt;/p&gt; &lt;p&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; // start a transaction on the connection&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; SqlTransaction transaction = connection.BeginTransaction(isolationLevel);&lt;/code&gt;&lt;/p&gt; &lt;p&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; // set the transaction on the table adapter&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; SetTransaction(tableAdapter, transaction);&lt;/code&gt;&lt;/p&gt; &lt;p&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return transaction;&lt;br /&gt;}&lt;/code&gt;&lt;/p&gt; &lt;p&gt;&lt;code&gt;/// &amp;lt;summary&amp;gt;&lt;br /&gt;/// Gets the connection from the specified table adapter.&lt;br /&gt;/// &amp;lt;/summary&amp;gt;&lt;br /&gt;private static SqlConnection GetConnection(object tableAdapter)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Type type = tableAdapter.GetType();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; PropertyInfo connectionProperty = type.GetProperty("Connection", BindingFlags.NonPublic | BindingFlags.Instance);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; SqlConnection connection = (SqlConnection)connectionProperty.GetValue(tableAdapter, null);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return connection;&lt;br /&gt;}&lt;/code&gt;&lt;/p&gt; &lt;p&gt;&lt;code&gt;/// &amp;lt;summary&amp;gt;&lt;br /&gt;/// Sets the connection on the specified table adapter.&lt;br /&gt;/// &amp;lt;/summary&amp;gt;&lt;br /&gt;private static void SetConnection(object tableAdapter, SqlConnection connection)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Type type = tableAdapter.GetType();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; PropertyInfo connectionProperty = type.GetProperty("Connection", BindingFlags.NonPublic | BindingFlags.Instance);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; connectionProperty.SetValue(tableAdapter, connection, null);&lt;br /&gt;}&lt;/code&gt;&lt;/p&gt; &lt;p&gt;&lt;code&gt;/// &amp;lt;summary&amp;gt;&lt;br /&gt;/// Enlists the table adapter in a transaction.&lt;br /&gt;/// &amp;lt;/summary&amp;gt;&lt;br /&gt;public static void SetTransaction(object tableAdapter, SqlTransaction transaction)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; // get the table adapter's type&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Type type = tableAdapter.GetType();&lt;/code&gt;&lt;/p&gt; &lt;p&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; // set the transaction on each command in the adapter&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; PropertyInfo commandsProperty = type.GetProperty("CommandCollection", BindingFlags.NonPublic | BindingFlags.Instance);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; SqlCommand[] commands = (SqlCommand[])commandsProperty.GetValue(tableAdapter, null);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; foreach (SqlCommand command in commands)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; command.Transaction = transaction;&lt;/code&gt;&lt;/p&gt; &lt;p&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; // set the connection on the table adapter&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; SetConnection(tableAdapter, transaction.Connection);&lt;br /&gt;}&lt;br /&gt;}&lt;/code&gt;&lt;/p&gt; &lt;p&gt;Here's some example usage of the helper methods above.&amp;nbsp; In this example, we have some work that spans two different adapters that we need to enclose in a transaction.&lt;/p&gt; &lt;p&gt;&lt;code&gt;SqlTransaction transaction = null;&lt;br /&gt;&lt;br /&gt;try&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; using (FooTableAdapter fooAdapter = new FooTableAdapter())&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; transaction = TableAdapterHelper.BeginTransaction(fooAdapter);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; fooAdapter.DoSomething();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; using (BarTableAdapter barAdapter = new BarTableAdapter())&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;TableAdapterHelper.SetTransaction(barAdapter, transaction);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; barAdapter.DoSomething();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; transaction.Commit();&lt;br /&gt;}&lt;br /&gt;catch&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; transaction.Rollback();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; throw;&lt;br /&gt;}&lt;br /&gt;finally&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; transaction.Dispose();&lt;br /&gt;}&lt;/code&gt;&lt;/p&gt; &lt;p&gt;So, what are the disadvantages here?&amp;nbsp; We're using reflection so there's no compile-time checking nor is there any strong-typing action going on.&amp;nbsp; Using reflection is obviously slower execution-wise&amp;nbsp;than extending your TableAdapter's class.&amp;nbsp; Also, the code-gen implementation of your TableAdapter class could theoretically change if VS2005 gets patched in the future and would therefore cause your TableAdapterHelper to break.&lt;/p&gt; &lt;p&gt;What are the advantages?&amp;nbsp; Compile-time checking, schmompile-schmime checking.&amp;nbsp; Reflection is eons faster than a promotion to DTC, and this approach is certainly faster than extending your TableAdapter classes by hand.&amp;nbsp; And, the code-gen implementation of your TableAdapter class is unlikely to change.&lt;/p&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=441529" width="1" height="1"&gt;</description><category domain="http://weblogs.asp.net/ryanw/archive/tags/Programming/default.aspx">Programming</category></item><item><title>Modify data before it's inserted in SQL Server 2000/2005</title><link>http://weblogs.asp.net/ryanw/archive/2006/02/02/437242.aspx</link><pubDate>Fri, 03 Feb 2006 05:48:00 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:437242</guid><dc:creator>RyanW</dc:creator><slash:comments>1</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/ryanw/rsscomments.aspx?PostID=437242</wfw:commentRss><comments>http://weblogs.asp.net/ryanw/archive/2006/02/02/437242.aspx#comments</comments><description>&lt;p&gt;I had a scenario where I needed to massage some data in this one particular column before it got inserted into the database.&lt;/p&gt; &lt;p&gt;I usually like to implement this kind of logic alongside its business brethren, leaving as much business brouhaha out of the raw database as possible, but in this case I was straddling two apps.&amp;nbsp; One old one, one new one, both using the same database.&amp;nbsp; Problem was, I didn't want to pull down the old code from the Vault, recompile, and post a newish-old version.&amp;nbsp; Long story short, I implemented an INSTEAD OF trigger on the table to massage the data before it got inserted.&amp;nbsp; Boom, data massage for both apps.&lt;/p&gt; &lt;p&gt;&lt;code&gt;/* This trigger makes sure that the data being inserted into&lt;br /&gt;&amp;nbsp;&amp;nbsp; the BarColumn column starts with a dash.&amp;nbsp; If it doesn't, it &lt;br /&gt;&amp;nbsp;&amp;nbsp; &lt;/code&gt;&lt;code&gt;will prepend one.&amp;nbsp;*/&lt;/code&gt;&lt;/p&gt; &lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;CREATE TRIGGER FooTable_Insert ON dbo.FooTable&lt;br /&gt;INSTEAD OF INSERT&lt;br /&gt;AS&lt;br /&gt;DECLARE @BarColumn varchar(50)&lt;br /&gt;SET @BarColumn = (SELECT BarColumn FROM INSERTED)&lt;br /&gt;IF (LEFT(@BarColumn, 1) &amp;lt;&amp;gt; '-')&lt;br /&gt;BEGIN&lt;/code&gt;&lt;code&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; SET @BarColumn = '-' + @BarColumn&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; SELECT *&amp;nbsp;INTO #Inserted FROM Inserted&lt;br /&gt;&lt;/code&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; UPDATE #Inserted SET BarColumn = @BarColumn&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; INSERT INTO FooTable SELECT * FROM #Inserted&lt;br /&gt;END&lt;br /&gt;ELSE&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; INSERT INTO FooTable SELECT * FROM Inserted&lt;/code&gt;&lt;/p&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=437242" width="1" height="1"&gt;</description><category domain="http://weblogs.asp.net/ryanw/archive/tags/Programming/default.aspx">Programming</category></item><item><title>Highly performant, caching image resizer?</title><link>http://weblogs.asp.net/ryanw/archive/2004/10/21/245822.aspx</link><pubDate>Thu, 21 Oct 2004 18:03:00 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:245822</guid><dc:creator>RyanW</dc:creator><slash:comments>6</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/ryanw/rsscomments.aspx?PostID=245822</wfw:commentRss><comments>http://weblogs.asp.net/ryanw/archive/2004/10/21/245822.aspx#comments</comments><description>&lt;p&gt;I'm in the ocean in a life ring, somebody please pull me out!&lt;/p&gt; &lt;p&gt;We have a client whose website gets a &lt;em&gt;lot&lt;/em&gt; of traffic.&amp;nbsp; Lots of product images.&amp;nbsp; Lots of image resizing going on.&lt;/p&gt; &lt;p&gt;What I need is a highly performant, .NET-based image resizer.&amp;nbsp; It needs to cache the resized images to disk so it doesn't have to resize every time the page loads.&amp;nbsp; Optionally, it'd be ideal if it supported varying image resizing algorithms.&amp;nbsp; And it'd be great if I could adjust the quality level.&lt;/p&gt; &lt;p&gt;For the past three years, I've used &lt;a href="http://www.unitedbinary.com"&gt;United Binary&lt;/a&gt;'s &lt;a href="http://www.unitedbinary.com/AutoImageSize.aspx"&gt;AutoImageSize&lt;/a&gt; component.&amp;nbsp; When it works, it's fantastic.&amp;nbsp; But, it crashes like nobody's business.&amp;nbsp; And nothing hurts &lt;em&gt;my&lt;/em&gt; business like a component that crashes like nobody's business.&lt;/p&gt; &lt;p&gt;Anyone have any ideas?&amp;nbsp; &lt;/p&gt; &lt;p&gt;(Besides rolling my own using the uber-easy .NET framework.&amp;nbsp; I don't have time.)&lt;/p&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=245822" width="1" height="1"&gt;</description><category domain="http://weblogs.asp.net/ryanw/archive/tags/Programming/default.aspx">Programming</category></item></channel></rss>