<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0"><channel><title>SubSonic: All Your Database Are Belong To Us</title><link>http://subsonicproject.com/</link><description /><generator>Graffiti CMS 1.0 (build 1.0.1.963)</generator><lastBuildDate>Thu, 21 Aug 2008 20:05:07 GMT</lastBuildDate><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" href="http://feeds.feedburner.com/Subsonic" type="application/rss+xml" /><feedburner:browserFriendly></feedburner:browserFriendly><item><title>SubSonic: Added Wildcard Methods</title><link>http://subsonicproject.com/querying/subsonic-added-wildcard-methods/</link><pubDate>Thu, 21 Aug 2008 20:05:07 GMT</pubDate><guid isPermaLink="true">http://subsonicproject.com/querying/subsonic-added-wildcard-methods/</guid><dc:creator>Rob Conery</dc:creator><slash:comments>0</slash:comments><category domain="http://subsonicproject.com/querying/">Querying</category><description>&lt;p&gt;With revision 482 I added in the ability to work with string values and "LIKE" queries a little more intuitively.&lt;/p&gt; &lt;p&gt;On a recent post, a commenter (liviu) left this comment:&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;&lt;em&gt;"...Because Subsonic generated code i found it unexplainable why i cannot write something like:&lt;/em&gt;&lt;/p&gt; &lt;p&gt;&lt;em&gt;Select&amp;lt;Product&amp;gt;().Where( Schema.Product.ProductName.StartsWith("a"))&lt;/em&gt;&lt;/p&gt; &lt;p&gt;&lt;em&gt;or &lt;/em&gt;&lt;/p&gt; &lt;p&gt;&lt;em&gt;Select&amp;lt;Product&amp;gt;().Where(Schema.Product.ProductType == "Cool Engine")."&lt;/em&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;The good news here is that in the second case it's a matter of me writing more complete samples. You can indeed do this query this way:&lt;/p&gt;&lt;pre class="csharpcode"&gt;IList&amp;lt;Product&amp;gt; products=&lt;span class="kwrd"&gt;new&lt;/span&gt; Select().From&amp;lt;Product&amp;gt;()
   .Where(Product.ProductTypeColum).IsEqualTo(&lt;span class="str"&gt;"Cool Engine"&lt;/span&gt;)
   .ExecuteTypedCollection&amp;lt;Product&amp;gt;();&lt;/pre&gt;
&lt;p&gt;However liviu is correct - you can't use "StartsWith" or "EndsWith" - until now. I just checked in changeset 481 which allows you to use StartsWith() and EndsWith() as well as ContainsString() - here's my Unit Tests:&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;pre class="csharpcode"&gt;        [Test]
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Select_Using_StartsWith_C_ShouldReturn_9_Records() {


            &lt;span class="kwrd"&gt;int&lt;/span&gt; records = &lt;span class="kwrd"&gt;new&lt;/span&gt; Select().From&amp;lt;Product&amp;gt;()
                .Where(Northwind.Product.ProductNameColumn).StartsWith(&lt;span class="str"&gt;"c"&lt;/span&gt;)
                .GetRecordCount();
            Assert.AreEqual(9, records);
        }

        [Test]
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Select_Using_EndsWith_S_ShouldReturn_9_Records() {


            &lt;span class="kwrd"&gt;int&lt;/span&gt; records = &lt;span class="kwrd"&gt;new&lt;/span&gt; Select().From&amp;lt;Product&amp;gt;()
                .Where(Northwind.Product.ProductNameColumn)
                .EndsWith(&lt;span class="str"&gt;"s"&lt;/span&gt;).GetRecordCount();
            Assert.AreEqual(9, records);
        }


        [Test]
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Select_Using_Contains_Ch_ShouldReturn_14_Records() {


            &lt;span class="kwrd"&gt;int&lt;/span&gt; records = &lt;span class="kwrd"&gt;new&lt;/span&gt; Select().From&amp;lt;Product&amp;gt;()
                .Where(Northwind.Product.ProductNameColumn)
                .ContainsString(&lt;span class="str"&gt;"ch"&lt;/span&gt;).GetRecordCount();

            Assert.AreEqual(14, records);
        }&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Many thanks to liviu for the suggestions!&lt;/p&gt;</description></item><item><title>Using SubStage</title><link>http://subsonicproject.com/2-1-pakala/using-substage/</link><pubDate>Fri, 11 Jul 2008 01:23:00 GMT</pubDate><guid isPermaLink="true">http://subsonicproject.com/2-1-pakala/using-substage/</guid><dc:creator>Rob Conery</dc:creator><slash:comments>8</slash:comments><category domain="http://subsonicproject.com/2-1-pakala/">2.1: Pakala</category><description>&lt;p&gt;Eric put together a really nice &amp;quot;IDE&amp;quot; for working with SubSonic 2.1. This is a walkthrough on what it is and how to use it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Making It Easy&lt;/strong&gt;&lt;br /&gt;
We're really trying to make it simple for people use SubSonic and yes, we know, our docs aren't up to speed. In this screencast I go into how you can use our new tool, SubStage, to see all the options available to you with our Providers, and also how you can generate your code precisely how you want to - all visually.&lt;/p&gt;
&lt;p&gt;Double-click the video to make it fullscreen - &lt;a href="http://silverlight.services.live.com/58326/Using%20SubStage/video.wmv"&gt;or you can download the WMV here&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;iframe frameborder="0" scrolling="no" src="http://silverlight.services.live.com/invoke/58326/Using%20SubStage/iframe.html" style="width: 700px; height: 700px;"&gt;&lt;/iframe&gt;&lt;/p&gt;</description></item><item><title>Select Queries</title><link>http://subsonicproject.com/querying/select-queries/</link><pubDate>Fri, 11 Jul 2008 01:22:00 GMT</pubDate><guid isPermaLink="true">http://subsonicproject.com/querying/select-queries/</guid><dc:creator>Rob Conery</dc:creator><slash:comments>12</slash:comments><category domain="http://subsonicproject.com/querying/">Querying</category><description>&lt;p&gt;Here are some sample Select queries using SubSonic 2.1. These come directly from our Unit tests, if you see an issue or a correction, please let us know!&lt;/p&gt; &lt;p&gt;All of these samples are made against the stock Northwind database.&lt;/p&gt; &lt;p&gt;Simple Select with string columns&lt;/p&gt;&lt;pre class="csharpcode"&gt;            &lt;span class="kwrd"&gt;int&lt;/span&gt; records = &lt;span class="kwrd"&gt;new&lt;/span&gt; Select(&lt;span class="str"&gt;"productID"&lt;/span&gt;).
                 From(&lt;span class="str"&gt;"Products"&lt;/span&gt;).GetRecordCount();

            Assert.IsTrue(records == 77);
&lt;/pre&gt;
&lt;p&gt;Simple Select with typed columns&lt;/p&gt;&lt;pre class="csharpcode"&gt;            &lt;span class="kwrd"&gt;int&lt;/span&gt; records = &lt;span class="kwrd"&gt;new&lt;/span&gt; Select(Product.ProductIDColumn, Product.ProductNameColumn).
                From&amp;lt;Product&amp;gt;().GetRecordCount();
            Assert.IsTrue(records == 77);
&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Returning a Single object&lt;/p&gt;&lt;pre class="csharpcode"&gt;            Product p = &lt;span class="kwrd"&gt;new&lt;/span&gt; Select().From&amp;lt;Product&amp;gt;().
               Where(&lt;span class="str"&gt;"ProductID"&lt;/span&gt;).IsEqualTo(1).ExecuteSingle&amp;lt;Product&amp;gt;();
            Assert.IsNotNull(p);
&lt;/pre&gt;
&lt;p&gt;Returning all columns&lt;/p&gt;&lt;pre class="csharpcode"&gt;            &lt;span class="kwrd"&gt;int&lt;/span&gt; records = &lt;span class="kwrd"&gt;new&lt;/span&gt; Select().From(&lt;span class="str"&gt;"Products"&lt;/span&gt;).GetRecordCount();
            Assert.IsTrue(records == 77);
&lt;/pre&gt;
&lt;p&gt;Simple Where&lt;/p&gt;&lt;pre class="csharpcode"&gt;            &lt;span class="kwrd"&gt;int&lt;/span&gt; records = &lt;span class="kwrd"&gt;new&lt;/span&gt; Select().From(&lt;span class="str"&gt;"Products"&lt;/span&gt;).
                Where(&lt;span class="str"&gt;"categoryID"&lt;/span&gt;).IsEqualTo(5).GetRecordCount();
            Assert.AreEqual(7, records);
&lt;/pre&gt;
&lt;p&gt;Simple Where with And (as Collection)&lt;/p&gt;&lt;pre class="csharpcode"&gt;            ProductCollection products =
                DB.Select().From(&lt;span class="str"&gt;"Products"&lt;/span&gt;)
                    .Where(&lt;span class="str"&gt;"categoryID"&lt;/span&gt;).IsEqualTo(5)
                    .And(&lt;span class="str"&gt;"productid"&lt;/span&gt;).IsGreaterThan(50)
                    .ExecuteAsCollection&amp;lt;ProductCollection&amp;gt;();
&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Simple Inner Join&lt;/p&gt;&lt;pre class="csharpcode"&gt;            SubSonic.SqlQuery q = &lt;span class="kwrd"&gt;new&lt;/span&gt; Select(&lt;span class="str"&gt;"productid"&lt;/span&gt;).From(OrderDetail.Schema)
                .InnerJoin(Product.Schema)
                .Where(&lt;span class="str"&gt;"CategoryID"&lt;/span&gt;).IsEqualTo(5);
&lt;/pre&gt;
&lt;p&gt;Simple Join With Table Enum&lt;/p&gt;&lt;pre class="csharpcode"&gt;            SubSonic.SqlQuery q = &lt;span class="kwrd"&gt;new&lt;/span&gt; Select().From(Tables.OrderDetail)
                .InnerJoin(Tables.Product)
                .Where(&lt;span class="str"&gt;"CategoryID"&lt;/span&gt;).IsEqualTo(5);
&lt;/pre&gt;
&lt;p&gt;Multiple Joins As Collection&lt;/p&gt;&lt;pre class="csharpcode"&gt;            CustomerCollection customersByCategory = &lt;span class="kwrd"&gt;new&lt;/span&gt; Select()
                .From(Customer.Schema)
                .InnerJoin(Order.Schema)
                .InnerJoin(OrderDetail.OrderIDColumn, Order.OrderIDColumn)
                .InnerJoin(Product.ProductIDColumn, OrderDetail.ProductIDColumn)
                .Where(&lt;span class="str"&gt;"CategoryID"&lt;/span&gt;).IsEqualTo(5)
                .ExecuteAsCollection&amp;lt;CustomerCollection&amp;gt;();

&lt;/pre&gt;
&lt;p&gt;Left Outer Join With Generics&lt;/p&gt;&lt;pre class="csharpcode"&gt;            SubSonic.SqlQuery query = DB.Select(Aggregate.GroupBy(&lt;span class="str"&gt;"CompanyName"&lt;/span&gt;))
                .From&amp;lt;Customer&amp;gt;()
                .LeftOuterJoin&amp;lt;Order&amp;gt;();
&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Left Outer Join With Schema&lt;/p&gt;&lt;pre class="csharpcode"&gt;            SubSonic.SqlQuery query = DB.Select(Aggregate.GroupBy(&lt;span class="str"&gt;"CompanyName"&lt;/span&gt;))
                .From(Customer.Schema)
                .LeftOuterJoin(Order.CustomerIDColumn, Customer.CustomerIDColumn);
&lt;/pre&gt;
&lt;p&gt;Left Outer Join With Magic Strings&lt;/p&gt;&lt;pre class="csharpcode"&gt;            SubSonic.SqlQuery query = DB.Select(Aggregate.GroupBy(&lt;span class="str"&gt;"CompanyName"&lt;/span&gt;))
                .From(&lt;span class="str"&gt;"Customers"&lt;/span&gt;)
                .LeftOuterJoin(&lt;span class="str"&gt;"Orders"&lt;/span&gt;);

&lt;/pre&gt;
&lt;p&gt;Simple Select With Collection Result&lt;/p&gt;&lt;pre class="csharpcode"&gt;            ProductCollection p = Select.AllColumnsFrom&amp;lt;Product&amp;gt;()
                .ExecuteAsCollection&amp;lt;ProductCollection&amp;gt;();
&lt;/pre&gt;
&lt;p&gt;Simple Select With LIKE&lt;/p&gt;&lt;pre class="csharpcode"&gt;            ProductCollection p = DB.Select()
                .From(Product.Schema)
                .InnerJoin(Category.Schema)
                .Where(&lt;span class="str"&gt;"CategoryName"&lt;/span&gt;).Like(&lt;span class="str"&gt;"c%"&lt;/span&gt;)
                .ExecuteAsCollection&amp;lt;ProductCollection&amp;gt;();
&lt;/pre&gt;
&lt;p&gt;Using Nested Where/And/Or&lt;/p&gt;&lt;pre class="csharpcode"&gt;            ProductCollection products = Select.AllColumnsFrom&amp;lt;Product&amp;gt;()
                .WhereExpression(&lt;span class="str"&gt;"categoryID"&lt;/span&gt;).IsEqualTo(5).And(&lt;span class="str"&gt;"productid"&lt;/span&gt;).IsGreaterThan(10)
                .OrExpression(&lt;span class="str"&gt;"categoryID"&lt;/span&gt;).IsEqualTo(2).And(&lt;span class="str"&gt;"productID"&lt;/span&gt;).IsBetweenAnd(2, 5)
                .ExecuteAsCollection&amp;lt;ProductCollection&amp;gt;();
&lt;/pre&gt;&lt;pre class="csharpcode"&gt;            ProductCollection products = Select.AllColumnsFrom&amp;lt;Product&amp;gt;()
                .WhereExpression(&lt;span class="str"&gt;"categoryID"&lt;/span&gt;).IsEqualTo(5).And(&lt;span class="str"&gt;"productid"&lt;/span&gt;).IsGreaterThan(10)
                .Or(&lt;span class="str"&gt;"categoryID"&lt;/span&gt;).IsEqualTo(2).AndExpression(&lt;span class="str"&gt;"productID"&lt;/span&gt;).IsBetweenAnd(2, 5)
                .ExecuteAsCollection&amp;lt;ProductCollection&amp;gt;();
&lt;/pre&gt;
&lt;p&gt;Simple Paged Query&lt;/p&gt;&lt;pre class="csharpcode"&gt;            SubSonic.SqlQuery q = Select.AllColumnsFrom&amp;lt;Product&amp;gt;().
               Paged(1, 20).Where(&lt;span class="str"&gt;"productid"&lt;/span&gt;).IsLessThan(100);
&lt;/pre&gt;
&lt;p&gt;Paged Query With Join&lt;/p&gt;&lt;pre class="csharpcode"&gt;            SubSonic.SqlQuery q = &lt;span class="kwrd"&gt;new&lt;/span&gt; Select(&lt;span class="str"&gt;"ProductId"&lt;/span&gt;, &lt;span class="str"&gt;"ProductName"&lt;/span&gt;, &lt;span class="str"&gt;"CategoryName"&lt;/span&gt;).
                From(&lt;span class="str"&gt;"Products"&lt;/span&gt;).InnerJoin(Category.Schema).Paged(1, 20);
&lt;/pre&gt;
&lt;p&gt;Paged View&lt;/p&gt;&lt;pre class="csharpcode"&gt;            SubSonic.SqlQuery q = &lt;span class="kwrd"&gt;new&lt;/span&gt; Select().From(Invoice.Schema).Paged(1, 20);
&lt;/pre&gt;
&lt;p&gt;Simple IN Query&lt;/p&gt;&lt;pre class="csharpcode"&gt;            &lt;span class="kwrd"&gt;int&lt;/span&gt; records = &lt;span class="kwrd"&gt;new&lt;/span&gt; Select().From(Product.Schema)
                .Where(&lt;span class="str"&gt;"productid"&lt;/span&gt;).In(1, 2, 3, 4, 5)
                .GetRecordCount();
            Assert.IsTrue(records == 5);
&lt;/pre&gt;
&lt;p&gt;Using IN With Nested Select&lt;/p&gt;&lt;pre class="csharpcode"&gt;            &lt;span class="kwrd"&gt;int&lt;/span&gt; records = Select.AllColumnsFrom&amp;lt;Product&amp;gt;()
                .Where(&lt;span class="str"&gt;"productid"&lt;/span&gt;)
                .In(
                &lt;span class="kwrd"&gt;new&lt;/span&gt; Select(&lt;span class="str"&gt;"productid"&lt;/span&gt;).From(Product.Schema)
                    .Where(&lt;span class="str"&gt;"categoryid"&lt;/span&gt;).IsEqualTo(5)
                )
                .GetRecordCount();&lt;/pre&gt;
&lt;p&gt;Using Multiple INs&lt;/p&gt;&lt;pre class="csharpcode"&gt;            SubSonic.SqlQuery query = &lt;span class="kwrd"&gt;new&lt;/span&gt; Select()
                .From(Product.Schema)
                .Where(Product.CategoryIDColumn).In(2)
                .And(Product.SupplierIDColumn).In(3);
&lt;/pre&gt;</description></item><item><title>Aggregate Queries</title><link>http://subsonicproject.com/querying/aggregate-queries/</link><pubDate>Fri, 11 Jul 2008 01:01:00 GMT</pubDate><guid isPermaLink="true">http://subsonicproject.com/querying/aggregate-queries/</guid><dc:creator>Rob Conery</dc:creator><slash:comments>1</slash:comments><category domain="http://subsonicproject.com/querying/">Querying</category><description>&lt;p&gt;Writing an aggregate query (SUM, COUNT, AVG) shouldn't be painful. We've tried to take the pain out of this for you.&lt;/p&gt;&lt;p&gt;Rather than drone on, I thought it would be helpful to see our Unit tests. In this way, if you find an issue you can patch us with a Unit test of your own!&lt;/p&gt;
&lt;p&gt;At their core, Aggregates are just special Select() queries - and you can use all the same Where/Or/And constraints that you normally would.&lt;/p&gt;
&lt;p&gt;All of these queries are using stock Northwind database.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Summing&lt;/strong&gt;&lt;/p&gt;
&lt;pre class="csharpcode"&gt;
    &lt;span class="kwrd"&gt;double&lt;/span&gt; result = &lt;span class="kwrd"&gt;new&lt;/span&gt;
        Select(Aggregate.Sum(&lt;span class="str"&gt;&amp;quot;UnitPrice*Quantity&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;ProductSales&amp;quot;&lt;/span&gt;))
        .From(OrderDetail.Schema)
        .ExecuteScalar&amp;lt;&lt;span class="kwrd"&gt;double&lt;/span&gt;&amp;gt;();

    result = Math.Round(result, 2);
    Assert.IsTrue(result == 1354458.59);
&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Averages&lt;/strong&gt;&lt;/p&gt;
&lt;pre class="csharpcode"&gt;
    &lt;span class="kwrd"&gt;const&lt;/span&gt; &lt;span class="kwrd"&gt;double&lt;/span&gt; expected = 55.5922;

    &lt;span class="rem"&gt;// overload #1&lt;/span&gt;
    &lt;span class="kwrd"&gt;double&lt;/span&gt; result = &lt;span class="kwrd"&gt;new&lt;/span&gt;
        Select(Aggregate.Avg(&lt;span class="str"&gt;&amp;quot;UnitPrice&amp;quot;&lt;/span&gt;))
        .From(Product.Schema)
        .ExecuteScalar&amp;lt;&lt;span class="kwrd"&gt;double&lt;/span&gt;&amp;gt;();
    Assert.AreEqual(expected, result);

    &lt;span class="rem"&gt;// overload #2&lt;/span&gt;
    result = &lt;span class="kwrd"&gt;new&lt;/span&gt;
        Select(Aggregate.Avg(Product.UnitPriceColumn))
        .From(Product.Schema)
        .ExecuteScalar&amp;lt;&lt;span class="kwrd"&gt;double&lt;/span&gt;&amp;gt;();
    Assert.AreEqual(expected, result);

    &lt;span class="rem"&gt;// overload #3&lt;/span&gt;
    result = &lt;span class="kwrd"&gt;new&lt;/span&gt;
        Select(Aggregate.Avg(&lt;span class="str"&gt;&amp;quot;UnitPrice&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;AverageUnitPrice&amp;quot;&lt;/span&gt;))
        .From(Product.Schema)
        .ExecuteScalar&amp;lt;&lt;span class="kwrd"&gt;double&lt;/span&gt;&amp;gt;();
    Assert.AreEqual(expected, result);

    &lt;span class="rem"&gt;// overload #4&lt;/span&gt;
    result = &lt;span class="kwrd"&gt;new&lt;/span&gt;
        Select(Aggregate.Avg(Product.UnitPriceColumn, &lt;span class="str"&gt;&amp;quot;AverageUnitPrice&amp;quot;&lt;/span&gt;))
        .From(Product.Schema)
        .ExecuteScalar&amp;lt;&lt;span class="kwrd"&gt;double&lt;/span&gt;&amp;gt;();
    Assert.AreEqual(expected, result);&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Max&lt;/strong&gt;&lt;/p&gt;
&lt;pre class="csharpcode"&gt;
    &lt;span class="kwrd"&gt;const&lt;/span&gt; &lt;span class="kwrd"&gt;double&lt;/span&gt; expected = 100.00;

    &lt;span class="rem"&gt;// overload #1&lt;/span&gt;
    &lt;span class="kwrd"&gt;double&lt;/span&gt; result = &lt;span class="kwrd"&gt;new&lt;/span&gt;
        Select(Aggregate.Max(&lt;span class="str"&gt;&amp;quot;UnitPrice&amp;quot;&lt;/span&gt;))
        .From(Product.Schema)
        .ExecuteScalar&amp;lt;&lt;span class="kwrd"&gt;double&lt;/span&gt;&amp;gt;();
    Assert.AreEqual(expected, result);

    &lt;span class="rem"&gt;// overload #2&lt;/span&gt;
    result = &lt;span class="kwrd"&gt;new&lt;/span&gt;
        Select(Aggregate.Max(Product.UnitPriceColumn))
        .From(Product.Schema)
        .ExecuteScalar&amp;lt;&lt;span class="kwrd"&gt;double&lt;/span&gt;&amp;gt;();
    Assert.AreEqual(expected, result);

    &lt;span class="rem"&gt;// overload #3&lt;/span&gt;
    result = &lt;span class="kwrd"&gt;new&lt;/span&gt;
        Select(Aggregate.Max(&lt;span class="str"&gt;&amp;quot;UnitPrice&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;MostExpensive&amp;quot;&lt;/span&gt;))
        .From(Product.Schema)
        .ExecuteScalar&amp;lt;&lt;span class="kwrd"&gt;double&lt;/span&gt;&amp;gt;();
    Assert.AreEqual(expected, result);

    &lt;span class="rem"&gt;// overload #4&lt;/span&gt;
    result = &lt;span class="kwrd"&gt;new&lt;/span&gt;
        Select(Aggregate.Max(Product.UnitPriceColumn, &lt;span class="str"&gt;&amp;quot;MostExpensive&amp;quot;&lt;/span&gt;))
        .From(Product.Schema)
        .ExecuteScalar&amp;lt;&lt;span class="kwrd"&gt;double&lt;/span&gt;&amp;gt;();
    Assert.AreEqual(expected, result);&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Min&lt;/strong&gt;&lt;/p&gt;
&lt;pre class="csharpcode"&gt;
    &lt;span class="kwrd"&gt;const&lt;/span&gt; &lt;span class="kwrd"&gt;double&lt;/span&gt; expected = 2.50;

    &lt;span class="rem"&gt;// overload #1&lt;/span&gt;
    &lt;span class="kwrd"&gt;double&lt;/span&gt; result = &lt;span class="kwrd"&gt;new&lt;/span&gt;
        Select(Aggregate.Min(&lt;span class="str"&gt;&amp;quot;UnitPrice&amp;quot;&lt;/span&gt;))
        .From(Product.Schema)
        .ExecuteScalar&amp;lt;&lt;span class="kwrd"&gt;double&lt;/span&gt;&amp;gt;();
    Assert.AreEqual(expected, result);

    &lt;span class="rem"&gt;// overload #2&lt;/span&gt;
    result = &lt;span class="kwrd"&gt;new&lt;/span&gt;
        Select(Aggregate.Min(Product.UnitPriceColumn))
        .From(Product.Schema)
        .ExecuteScalar&amp;lt;&lt;span class="kwrd"&gt;double&lt;/span&gt;&amp;gt;();
    Assert.AreEqual(expected, result);

    &lt;span class="rem"&gt;// overload #3&lt;/span&gt;
    result = &lt;span class="kwrd"&gt;new&lt;/span&gt;
        Select(Aggregate.Min(&lt;span class="str"&gt;&amp;quot;UnitPrice&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;CheapestProduct&amp;quot;&lt;/span&gt;))
        .From(Product.Schema)
        .ExecuteScalar&amp;lt;&lt;span class="kwrd"&gt;double&lt;/span&gt;&amp;gt;();
    Assert.AreEqual(expected, result);

    &lt;span class="rem"&gt;// overload #4&lt;/span&gt;
    result = &lt;span class="kwrd"&gt;new&lt;/span&gt;
        Select(Aggregate.Min(Product.UnitPriceColumn, &lt;span class="str"&gt;&amp;quot;CheapestProduct&amp;quot;&lt;/span&gt;))
        .From(Product.Schema)
        .ExecuteScalar&amp;lt;&lt;span class="kwrd"&gt;double&lt;/span&gt;&amp;gt;();
    Assert.AreEqual(expected, result);&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Standard Deviation&lt;/strong&gt;&lt;/p&gt;
&lt;pre class="csharpcode"&gt;
    &lt;span class="kwrd"&gt;const&lt;/span&gt; &lt;span class="kwrd"&gt;double&lt;/span&gt; expected = 42.7698669325723;

    &lt;span class="rem"&gt;// overload #1&lt;/span&gt;
    &lt;span class="kwrd"&gt;double&lt;/span&gt; result = &lt;span class="kwrd"&gt;new&lt;/span&gt;
        Select(Aggregate.StandardDeviation(&lt;span class="str"&gt;&amp;quot;UnitPrice&amp;quot;&lt;/span&gt;))
        .From(Product.Schema)
        .ExecuteScalar&amp;lt;&lt;span class="kwrd"&gt;double&lt;/span&gt;&amp;gt;();
    Assert.AreEqual(expected, result);

    &lt;span class="rem"&gt;// overload #2&lt;/span&gt;
    result = &lt;span class="kwrd"&gt;new&lt;/span&gt;
        Select(Aggregate.StandardDeviation(Product.UnitPriceColumn))
        .From(Product.Schema)
        .ExecuteScalar&amp;lt;&lt;span class="kwrd"&gt;double&lt;/span&gt;&amp;gt;();
    Assert.AreEqual(expected, result);

    &lt;span class="rem"&gt;// overload #3&lt;/span&gt;
    result = &lt;span class="kwrd"&gt;new&lt;/span&gt;
        Select(Aggregate.StandardDeviation(&lt;span class="str"&gt;&amp;quot;UnitPrice&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;CheapestProduct&amp;quot;&lt;/span&gt;))
        .From(Product.Schema)
        .ExecuteScalar&amp;lt;&lt;span class="kwrd"&gt;double&lt;/span&gt;&amp;gt;();
    Assert.AreEqual(expected, result);

    &lt;span class="rem"&gt;// overload #4&lt;/span&gt;
    result = &lt;span class="kwrd"&gt;new&lt;/span&gt;
        Select(Aggregate.StandardDeviation(Product.UnitPriceColumn, &lt;span class="str"&gt;&amp;quot;CheapestProduct&amp;quot;&lt;/span&gt;))
        .From(Product.Schema)
        .ExecuteScalar&amp;lt;&lt;span class="kwrd"&gt;double&lt;/span&gt;&amp;gt;();
    Assert.AreEqual(expected, result);&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Average With GroupBy&lt;/strong&gt;&lt;/p&gt;
&lt;pre class="csharpcode"&gt;
    &lt;span class="kwrd"&gt;int&lt;/span&gt; records = &lt;span class="kwrd"&gt;new&lt;/span&gt;
        Select(Aggregate.GroupBy(&lt;span class="str"&gt;&amp;quot;ProductID&amp;quot;&lt;/span&gt;), Aggregate.Avg(&lt;span class="str"&gt;&amp;quot;UnitPrice&amp;quot;&lt;/span&gt;))
        .From(&lt;span class="str"&gt;&amp;quot;Order Details&amp;quot;&lt;/span&gt;)
        .Where(&lt;span class="str"&gt;&amp;quot;Quantity&amp;quot;&lt;/span&gt;).IsEqualTo(120)
        .Where(Aggregate.Avg(&lt;span class="str"&gt;&amp;quot;UnitPrice&amp;quot;&lt;/span&gt;))
        .IsGreaterThan(10)
        .GetRecordCount();

    Assert.AreEqual(5, records);&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Average With Simple Where&lt;/strong&gt;&lt;/p&gt;
&lt;pre class="csharpcode"&gt;
    &lt;span class="kwrd"&gt;int&lt;/span&gt; records = &lt;span class="kwrd"&gt;new&lt;/span&gt;
        Select(Aggregate.GroupBy(&lt;span class="str"&gt;&amp;quot;ProductID&amp;quot;&lt;/span&gt;), Aggregate.Avg(&lt;span class="str"&gt;&amp;quot;UnitPrice&amp;quot;&lt;/span&gt;))
        .From(&lt;span class="str"&gt;&amp;quot;Order Details&amp;quot;&lt;/span&gt;)
        .Where(Aggregate.Avg(&lt;span class="str"&gt;&amp;quot;UnitPrice&amp;quot;&lt;/span&gt;))
        .IsGreaterThan(50)
        .GetRecordCount();

    Assert.AreEqual(7, records);&lt;/pre&gt;</description></item><item><title>SubSonic: Writing Decoupled, Testable Code With SubSonic 2.1</title><link>http://subsonicproject.com/2-1-pakala/subsonic-writing-decoupled-testable-code-with-subsonic-2-1/</link><pubDate>Wed, 18 Jun 2008 21:04:51 GMT</pubDate><guid isPermaLink="true">http://subsonicproject.com/2-1-pakala/subsonic-writing-decoupled-testable-code-with-subsonic-2-1/</guid><dc:creator>Rob Conery</dc:creator><slash:comments>3</slash:comments><category domain="http://subsonicproject.com/2-1-pakala/">2.1: Pakala</category><description>&lt;p&gt;I've heard/read rumblings over the last few months that "SubSonic is tightly coupled" and therefore you have to "drag it around" with you in your project. I can see why people might think this - ActiveRecord is not the most testable thing in the world :). I've really tried to push SubSonic into the TDD realm and thought it might be a good idea to show how you can structure up a highly testable, decoupled application using SubSonic as your Data Access tool.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;The Repository Pattern&lt;/strong&gt;&lt;br&gt;This is usually the first choice in Data Access patterns when it comes to writing testable, decoupled code. So I'm going to use that today. If you arent' familiar with it, you may want to &lt;a href="http://martinfowler.com/eaaCatalog/repository.html" target="_blank"&gt;read more here&lt;/a&gt;. Essentially, the idea here is that you want to abstract your data access/query bits as much as possible from the rest of your application - including your model. I go into this a lot in the &lt;a href="http://blog.wekeroad.com/mvc-storefront/" target="_blank"&gt;MVC Storefront series&lt;/a&gt;.&lt;/p&gt; &lt;p&gt;Rather than dive into explanations here, I'll just show the code :).&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Solution Setup&lt;/strong&gt;&lt;br&gt;I'm using ASP.NET MVC - but you don't have to use this. You can use whatever application setup you like. I'm dividing out the data access and test projects as well, so that I have 4 total in my application:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;ASP.NET MVC Website  &lt;li&gt;Data Access Project (Class Library)  &lt;li&gt;Business Logice (Class Library)  &lt;li&gt;Test Project (using MS Test)&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;&lt;a href="http://subsonicproject.com/files/media/image/WindowsLiveWriter/SubSonicWritingDecoupledTestableCodeWi.1_90D9/solution_4.jpg"&gt;&lt;img style="margin: 10px" height="206" alt="solution" src="http://subsonicproject.com/files/media/image/WindowsLiveWriter/SubSonicWritingDecoupledTestableCodeWi.1_90D9/solution_thumb_1.jpg" width="248" border="0"&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;&lt;strong&gt;Data Access&lt;/strong&gt;&lt;br&gt;Let's assume, for now, that I'm writing tests for everything I do. And my tests tell me that I need to setup a Catalog Repository that talks to my DB (for today it will be Northwind). My tests tell me I need to have a Product so the first thing I do is setup a class to represent a Product:&lt;/p&gt;&lt;pre class="csharpcode"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; Product {

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; ProductID { get; set; }
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; ProductName { get; set; }
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;decimal&lt;/span&gt; UnitPrice { get; set; }

    }&lt;/pre&gt;
&lt;p&gt;Next, I need to have a method on my Repository that will retrieve products from the DB. For those of you following along with the MVC Storefront, I'm going to use the classic Repository Pattern here, without using IQueryable.&lt;/p&gt;
&lt;p&gt;I define an interface that will abstract the implementation of the Repository:&lt;/p&gt;&lt;pre class="csharpcode"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;interface&lt;/span&gt; ICatalogRepository {

        IList&amp;lt;Product&amp;gt; GetProducts();

    }&lt;/pre&gt;
&lt;p&gt;Finally, I need to setup an implementation of this interface, and it will use SubSonic. I reference and setup SubSonic in the Data Access class, and then &lt;a href="http://subsonicproject.com/subcommander/using-the-command-line-tool-subcommander/" target="_blank"&gt;generate all the good stuff&lt;/a&gt; SubSonic will create for me here. Note that I can use ActiveRecord or RepositoryRecord - it doesn't matter, and that's just how I want it. All I'm going to use is &lt;a href="http://subsonicproject.com/2-1-pakala/subsonic-version-2-1-pakala-preview-the-new-query-tool/" target="_blank"&gt;the new Query tool&lt;/a&gt; - none of the base objects that are created (except for the Repository querying).&lt;/p&gt;
&lt;p&gt;After generating the code, my project looks like this:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://subsonicproject.com/files/media/image/WindowsLiveWriter/SubSonicWritingDecoupledTestableCodeWi.1_90D9/dataaccess_2.jpg"&gt;&lt;img style="margin: 10px" height="234" alt="dataaccess" src="http://subsonicproject.com/files/media/image/WindowsLiveWriter/SubSonicWritingDecoupledTestableCodeWi.1_90D9/dataaccess_thumb.jpg" width="264" border="0"&gt;&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Note&lt;/strong&gt;: you'll notice an App.config in the project. This is ONLY to tell SubCommander how/where to run the generation. &lt;a href="http://subsonicproject.com/subcommander/make-a-dos-batch-file-to-build-your-dal-files-with-subsonic-exe/" target="_blank"&gt;You don't need to do this&lt;/a&gt; (you can send everything in to SubCommander by command line)- I just find it handy.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;In the "Generated" folder are all the classes SubSonic generates for you to use and include a full schema look at your DB. This will allow us to query as we need to.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Mapping&lt;/strong&gt;&lt;br&gt;If you're not use to using ORM tool (Object-Relational Mappers), you may not know why I want to "duplicate" the classes that SubSonic generates, versus the one I created here in my "Model" folder.&lt;/p&gt;
&lt;p&gt;The reason comes down to what's known as "&lt;a href="http://en.wikipedia.org/wiki/Object-Relational_impedance_mismatch" target="_blank"&gt;impedance mismatch&lt;/a&gt;" - the idea that my DB structure will not follow my application structure (and therefore OO principles). Moreover, if you tie your DB structure to your application, eventually you will end up with some pain points as your DB grows - and to mitigate these you compromise good DB practices. The opposite is true as well - you "bend" your application to allow for easier use of the DB. I'll end this discussion here :).&lt;/p&gt;
&lt;p&gt;What I need to do now is implement ICatalogRepository using SubSonic, and map the Northwind Products to my Model. This is easy to do with SubSonic, using "ExecuteTypedList&amp;lt;&amp;gt;":&lt;/p&gt;&lt;pre class="csharpcode"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; SubSonicCatalogRepository:ICatalogRepository {

        &lt;span class="kwrd"&gt;public&lt;/span&gt; IList&amp;lt;Product&amp;gt; GetProducts() {

            &lt;span class="kwrd"&gt;return&lt;/span&gt; Northwind.DB.Select(&lt;span class="str"&gt;"ProductID"&lt;/span&gt;, &lt;span class="str"&gt;"ProductName"&lt;/span&gt;, &lt;span class="str"&gt;"UnitPrice"&lt;/span&gt;)
                .From&amp;lt;Northwind.Product&amp;gt;().ExecuteTypedList&amp;lt;Product&amp;gt;();


        }
    }&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;ExecuteTypedList&lt;/strong&gt;&amp;lt;&amp;gt; tries to match the names of the returned columns to the names of the properties of the passed-in type. In this example they match exactly - and that's not completely real world. You can get around this by aliasing the columns - in the same way you'd alias a SQL call:&lt;/p&gt;&lt;pre class="csharpcode"&gt;            &lt;span class="kwrd"&gt;return&lt;/span&gt; Northwind.DB.Select(&lt;span class="str"&gt;"ProductID as 'ID'"&lt;/span&gt;, &lt;span class="str"&gt;"ProductName as 'Name'"&lt;/span&gt;, &lt;span class="str"&gt;"UnitPrice as 'Price'"&lt;/span&gt;)
                .From&amp;lt;Northwind.Product&amp;gt;().ExecuteTypedList&amp;lt;Product&amp;gt;();
&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Note&lt;/strong&gt;: Using "as" is ANSI SQL, and will work with most DB providers - including MySQL 5.x and above.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;You can also Stored Procedures here, or Views - up to you.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Test&lt;/strong&gt;&lt;br&gt;In the Test Application, all you need to do is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Reference your Data Access project 
&lt;li&gt;Setup SubSonic's configuration (since this is an execution end point)&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;I'm looking into hard-coding the connection string info (like Linq To Sql does) so you can omit the config stuff - but I feel weird about that. Would love to hear some feedback...&lt;/p&gt;
&lt;p&gt;This is my Test Project:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://subsonicproject.com/files/media/image/WindowsLiveWriter/SubSonicWritingDecoupledTestableCodeWi.1_90D9/test_2.jpg"&gt;&lt;img style="margin: 10px" height="183" alt="test" src="http://subsonicproject.com/files/media/image/WindowsLiveWriter/SubSonicWritingDecoupledTestableCodeWi.1_90D9/test_thumb.jpg" width="273" border="0"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Note that I don't have any reference to SubSonic here :). I don't need it - it's abstracted nicely away. Now I can write my tests, stubbing out ICatalogRepository with a TestCatalogRepository, and use Dependency Injection to inject the SubSonicCatalogRepository as needed :).&lt;/p&gt;
&lt;p&gt;To make sure that SubSonic is playing nicely here, you can write an integration test:&lt;/p&gt;&lt;pre class="csharpcode"&gt;        [TestMethod]
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; SubSonic_Should_Return_Product_List() {

            ICatalogRepository rep = &lt;span class="kwrd"&gt;new&lt;/span&gt; SubSonicCatalogRepository();
            IList&amp;lt;Product&amp;gt; products = rep.GetProducts();
            Assert.AreEqual(77, products.Count);
        }&lt;/pre&gt;
&lt;p&gt;And here's the result:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://subsonicproject.com/files/media/image/WindowsLiveWriter/SubSonicWritingDecoupledTestableCodeWi.1_90D9/testresult_2.jpg"&gt;&lt;img style="margin: 10px" height="129" alt="testresult" src="http://subsonicproject.com/files/media/image/WindowsLiveWriter/SubSonicWritingDecoupledTestableCodeWi.1_90D9/testresult_thumb.jpg" width="404" border="0"&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;Yes, I know I shouldn't hard-code Count values, but this is a sample :).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Putting It All Together&lt;br&gt;&lt;/strong&gt;The one thing I haven't shown yet is my Business Logic bits. The one thing you don't want to do in your application is instantiate a Repository class directly - that's "coupling" and ties your application to the implementation. &lt;/p&gt;
&lt;p&gt;To get around this, you can use &lt;a href="http://en.wikipedia.org/wiki/Dependency_injection" target="_blank"&gt;Dependency Injection&lt;/a&gt; to "inject" the Repository into your business logic class at runtime. If you want to know more about "why" you'd do this, &lt;a href="http://blog.wekeroad.com/mvc-storefront/mvcstore-part-13/" target="_blank"&gt;&lt;strong&gt;I did a nice Dependency Injection screencast with Jeremy Miller&lt;/strong&gt;&lt;/a&gt; (creator of StructureMap) on the subject.&lt;/p&gt;
&lt;p&gt;Normally, your Service classes should implement your business logic so your Repository only concerns itself with getting the data you want. An example of this is that you may grab a list of Products and want to check inventory levels, whether the shopper is eligible for discounts - etc. You'll probably want to keep this type of logic in the application tier:&lt;/p&gt;&lt;pre class="csharpcode"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; CatalogService {

        ICatalogRepository _repository;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; CatalogService(ICatalogRepository repository) {
            _repository = repository;
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; IList&amp;lt;Product&amp;gt; GetProducts() {
            List&amp;lt;Product&amp;gt; products = _repository.GetProducts();
            
            &lt;span class="rem"&gt;//inventory checks&lt;/span&gt;

            &lt;span class="rem"&gt;//discount setups&lt;/span&gt;

            &lt;span class="rem"&gt;//cross-sell correlation&lt;/span&gt;

            &lt;span class="rem"&gt;//bundling...&lt;/span&gt;

        }

    }&lt;/pre&gt;
&lt;p&gt;The main thing about this setup is that the CatalogService class is FORCED to take a Repository in the constructor - this is exactly what we want in order to make our code more testable and decoupled.&lt;/p&gt;
&lt;p&gt;Normally you might put some Linq To Sql code in here, or perhaps straight-up ADO stuff with an IDataReader. That may be a great call with a smaller app, but with anything that you want to maintain over the next few years, you're better off trying to keep it cleanly separated like this.&lt;/p&gt;
&lt;p&gt;An example of why you might want this decoupling is you might decide to move your application to .NET 3.5 in the future and may want to use SubSonic 3.0, or Linq To Sql (or NHib... whatever). It's trivial to swap the parts out if you follow this architectural pattern.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Dependency Injection&lt;br&gt;&lt;/strong&gt;It may seem like a bummer to have to instantiate all these things just to get at a list of Products, but that's where DI comes in. If we plug in a DI tool (like StructureMap), we can rely on it to do the associations we need:&lt;/p&gt;&lt;pre class="csharpcode"&gt;            ForRequestedType&amp;lt;ICatalogRepository&amp;gt;()
                .TheDefaultIsConcreteType&amp;lt;SubSonicCatalogRepository&amp;gt;();&lt;/pre&gt;
&lt;p&gt;Setting this up is really, really easy and if you're interested in learning more about DI, &lt;a href="http://blog.wekeroad.com/mvc-storefront/mvcstore-part-13/" target="_blank"&gt;take a look at my screencast with Jeremy Miller&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I'm very interested to hear your comments. This setup is pretty tried and true, and if you'd like to see more about how to do this type of thing, I'd push you to check out the &lt;a href="http://blog.wekeroad.com/mvc-storefront/" target="_blank"&gt;MVC Storefront&lt;/a&gt;. I'm not using SubSonic there (yet) because it doesn't support IQueryable - but the ideas are pretty much the same.&lt;/p&gt;</description></item><item><title>SubSonic: Getting Started</title><link>http://subsonicproject.com/setup/gettingstarted/</link><pubDate>Fri, 06 Jun 2008 19:31:00 GMT</pubDate><guid isPermaLink="true">http://subsonicproject.com/setup/gettingstarted/</guid><dc:creator>Rob Conery</dc:creator><slash:comments>0</slash:comments><category domain="http://subsonicproject.com/setup/">Setup</category><description>&lt;p&gt;Code and Screencast to help you get SubSonic setup in your project.&lt;/p&gt;&lt;p&gt;

&lt;a href="http://www.wekeroad.com/webcasts/subsonicintro/intro.html" target=_blank&gt;&lt;h2&gt;Watch An Intro Screencast&lt;/h2&gt;&lt;/a&gt;

&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Open up the Web.config file - we need to do a little surgery. First, declare a config section for SubSonic, right under the &lt;span style="color: blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(163,21,21)"&gt;configuration &lt;/span&gt;tag:&lt;/p&gt;
&lt;div style="font-size: 9pt; background: rgb(248,248,248) 0% 50%; color: black; font-family: consolas; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial"&gt;
&lt;p style="margin: 0px"&gt;&lt;span style="color: blue"&gt;&amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color: rgb(163,21,21)"&gt;configSections&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style="margin: 0px"&gt;&lt;span style="color: blue"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color: rgb(163,21,21)"&gt;section&lt;/span&gt;&lt;span style="color: blue"&gt; &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;SubSonicService&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt; &lt;/span&gt;&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;SubSonic.SubSonicSection, SubSonic&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt; &lt;/span&gt;&lt;span style="color: red"&gt;requirePermission&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;&lt;/span&gt;&lt;/p&gt;
&lt;p style="margin: 0px"&gt;&lt;span style="color: blue"&gt;&amp;nbsp; &amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(163,21,21)"&gt;configSections&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Next, add a connection to your database (let's assume it's Northwind, located on the local SQLExpress instance):&lt;/p&gt;
&lt;div style="font-size: 9pt; background: rgb(248,248,248) 0% 50%; color: black; font-family: consolas; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial"&gt;
&lt;p style="margin: 0px"&gt;&lt;span style="color: blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(163,21,21)"&gt;connectionStrings&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style="margin: 0px"&gt;&lt;span style="color: blue"&gt;&amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color: rgb(163,21,21)"&gt;add&lt;/span&gt;&lt;span style="color: blue"&gt; &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;Northwind&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt; &lt;/span&gt;&lt;span style="color: red"&gt;connectionString&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;Data Source=localhost\SQLExpress; Database=Northwind; Integrated Security=true;&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;/&amp;gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style="margin: 0px"&gt;&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(163,21,21)"&gt;connectionStrings&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Next, we need to define our providers. Each SubSonic provider defines one database:&lt;/p&gt;
&lt;div style="font-size: 9pt; background: rgb(248,248,248) 0% 50%; color: black; font-family: consolas; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial"&gt;
&lt;p style="margin: 0px"&gt;&lt;span style="color: blue"&gt;&amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color: rgb(163,21,21)"&gt;SubSonicService&lt;/span&gt;&lt;span style="color: blue"&gt; &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;Northwind&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style="margin: 0px"&gt;&lt;span style="color: blue"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color: rgb(163,21,21)"&gt;providers&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style="margin: 0px"&gt;&lt;span style="color: blue"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color: rgb(163,21,21)"&gt;clear&lt;/span&gt;&lt;span style="color: blue"&gt;/&amp;gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style="margin: 0px"&gt;&lt;span style="color: blue"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color: rgb(163,21,21)"&gt;add&lt;/span&gt;&lt;span style="color: blue"&gt; &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;Northwind&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt; &lt;/span&gt;&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;SubSonic.SqlDataProvider, SubSonic&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt; &lt;/span&gt;&lt;span style="color: red"&gt;connectionStringName&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;Northwind&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt; &lt;/span&gt;&lt;span style="color: red"&gt;generatedNamespace&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;Northwind&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;/&amp;gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style="margin: 0px"&gt;&lt;span style="color: blue"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(163,21,21)"&gt;providers&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style="margin: 0px"&gt;&lt;span style="color: blue"&gt;&amp;nbsp; &amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(163,21,21)"&gt;SubSonicService&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Notice how here, we told the provider that it's generatedNamespace is &amp;quot;Northwind&amp;quot; - this means that in our code we'll be able to access all the generated bits using &amp;quot;Northwind.[TableName].Fetch()&amp;quot;&lt;/p&gt;
&lt;p&gt;Next, if you want SubSonic to generate the DAL &amp;quot;behind the scenes&amp;quot;, with no need for you to interfere, you'll need to declare a BuildProvider. A BuildProvider is a process the runs when Visual Studio compiles an application, or when a file is added to the App_Code folder. In our case we're going to define a BuildProvider that gets run for every file in the App_Code directory, having an extension of &amp;quot;.abp&amp;quot; (notice that this goes under the &amp;quot;&amp;lt;compilation&amp;quot; tag):&lt;/p&gt;
&lt;div style="font-size: 9pt; background: rgb(248,248,248) 0% 50%; color: black; font-family: consolas; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial"&gt;
&lt;p style="margin: 0px"&gt;&lt;span style="color: blue"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color: rgb(163,21,21)"&gt;compilation&lt;/span&gt;&lt;span style="color: blue"&gt; &lt;/span&gt;&lt;span style="color: red"&gt;debug&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; &lt;/span&gt;&lt;span style="color: red"&gt;defaultLanguage&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;C#&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style="margin: 0px"&gt;&lt;span style="color: blue"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;!--&lt;/span&gt;&lt;span style="color: green"&gt;########################## SubSonic Build Provider ###############################&lt;/span&gt;&lt;span style="color: blue"&gt;--&amp;gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style="margin: 0px"&gt;&lt;span style="color: blue"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;!--&lt;/span&gt;&lt;span style="color: green"&gt;This will NOT WORK in Medium Trust&lt;/span&gt;&lt;span style="color: blue"&gt;--&amp;gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style="margin: 0px"&gt;&lt;span style="color: blue"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color: rgb(163,21,21)"&gt;buildProviders&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style="margin: 0px"&gt;&lt;span style="color: blue"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color: rgb(163,21,21)"&gt;add&lt;/span&gt;&lt;span style="color: blue"&gt; &lt;/span&gt;&lt;span style="color: red"&gt;extension&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;.abp&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt; &lt;/span&gt;&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;SubSonic.BuildProvider, SubSonic&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;/&amp;gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style="margin: 0px"&gt;&lt;span style="color: blue"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(163,21,21)"&gt;buildProviders&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;If you will be deploying your application to an ISP that uses shared hosting, you probably won't be able to use the BuildProvider since it won't run in MediumTrust. If this is the case, you can use SubSonicCentral (the web site downloaded with SubSonic) to generate the code for you, or you can use the Command Line tool.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;Watch an intro here&lt;/h2&gt;</description></item><item><title>SubSonic: Using Migrations</title><link>http://subsonicproject.com/2-1-pakala/subsonic-using-migrations/</link><pubDate>Fri, 06 Jun 2008 03:48:49 GMT</pubDate><guid isPermaLink="true">http://subsonicproject.com/2-1-pakala/subsonic-using-migrations/</guid><dc:creator>Rob Conery</dc:creator><slash:comments>1</slash:comments><category domain="http://subsonicproject.com/2-1-pakala/">2.1: Pakala</category><description>&lt;p&gt;I've spent the passed few weeks polishing up some features for our 2.1 release (aka Pakala), and I've been paying particular attention to Migrations - something I promised would be ready to go a few months back. As of changeset 452 (made today, just now), Migrations are reasonably solid.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;As Always, There's a Video&lt;/strong&gt; &lt;br&gt;I like blogs with code, but singalongs are more fun. I made a quick video today (about 15 minutes) of how you can use Migrations in your project. &lt;/p&gt;&lt;a href="http://www.wekeroad.com/webcasts/subsonic_migrations.wmv"&gt;&lt;strong&gt;You can watch it here.&lt;/strong&gt;&lt;/a&gt;  &lt;p&gt;If you're more into the code and how they work - read on! All the code you will see below is viewable in the video.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Give Shawn Some Love&lt;/strong&gt; &lt;br&gt;I laid the groundwork for Migrations a while ago, but didn't have the bandwidth to give it the love it deserved. Frankly I don't know if I was smart enough.&amp;nbsp; I asked &lt;a href="http://blog.enginefour.com/"&gt;Shawn Oster&lt;/a&gt; to help out and he took his massive swingin geek smarts and put together a pretty cool set of functionality.&lt;/p&gt; &lt;p&gt;So if you see Shawn at the local Denver Gamer Shop, setting up for the Monday Night D&amp;amp;D Showdown (LARP-fest), give him a wizardly high-five!&lt;/p&gt; &lt;p&gt;&lt;strong&gt;The Code&amp;gt;&amp;gt;&amp;gt; &lt;br&gt;&lt;/strong&gt;The Migration system works by basically "sucking" out the Migration classes from your project, reading in the code, and then executing it in a virtual compiler. This may seem complex, but it's actually pretty simple and at it's core is what we do to generate the code files anyway.&lt;/p&gt; &lt;p&gt;To create a Migration, you have to follow our Conventional system and create a class file, something like&lt;/p&gt; &lt;p&gt;&lt;strong&gt;001_Initial.cs&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;... and place that class file into a folder called "Migrations" off the root of your project (you can override this directory convention - see below).&lt;/p&gt; &lt;p&gt;This class file must have one class (call it whatever you like), and it has to inherit from SubSonic.Migration:&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System;
&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Collections.Generic;
&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Text;
&lt;span class="kwrd"&gt;using&lt;/span&gt; SubSonic;

&lt;span class="kwrd"&gt;namespace&lt;/span&gt; MigrationSample.Migrations {

    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; Migration001:Migration {
    }
}&lt;/pre&gt;
&lt;p&gt;Each "Migration" consists of changing from one version to another, either up or down. The code, therefore, follows this logic and offers two methods for you to tell the DB what to look like.&lt;/p&gt;
&lt;p&gt;For the first example (001_Init), this is version one. The Up() method therefore is transitioning the DB from version 0 to version 1, so we need to put in some code to tell it what we want it to do:&lt;/p&gt;&lt;pre class="csharpcode"&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Up() {

            &lt;span class="rem"&gt;//Create the Records Table&lt;/span&gt;
            TableSchema.Table records = CreateTableWithKey(&lt;span class="str"&gt;"Records"&lt;/span&gt;);
            records.AddColumn(&lt;span class="str"&gt;"RecordName"&lt;/span&gt;);
            records.AddColumn(&lt;span class="str"&gt;"GroupID"&lt;/span&gt;, System.Data.DbType.Int32);
            records.AddColumn(&lt;span class="str"&gt;"LabelID"&lt;/span&gt;, System.Data.DbType.Int32);

            AddSubSonicStateColumns(records);

            &lt;span class="rem"&gt;//Create the Groups Table&lt;/span&gt;
            TableSchema.Table groups = CreateTableWithKey(&lt;span class="str"&gt;"Groups"&lt;/span&gt;);
            groups.AddColumn(&lt;span class="str"&gt;"GroupName"&lt;/span&gt;);
            AddSubSonicStateColumns(groups);

            &lt;span class="rem"&gt;//Link them&lt;/span&gt;
            CreateForeignKey(groups.GetColumn(&lt;span class="str"&gt;"id"&lt;/span&gt;), records.GetColumn(&lt;span class="str"&gt;"groupID"&lt;/span&gt;));


        }&lt;/pre&gt;
&lt;p&gt;For the Down() method, we need to reverse, exactly, everything we did with Up():&lt;/p&gt;&lt;pre class="csharpcode"&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Down() {
            TableSchema.Table records = GetTable(&lt;span class="str"&gt;"records"&lt;/span&gt;);
            TableSchema.Table groups = GetTable(&lt;span class="str"&gt;"groups"&lt;/span&gt;);

            &lt;span class="rem"&gt;//drop the FK&lt;/span&gt;
            DropForeignKey(groups.GetColumn(&lt;span class="str"&gt;"id"&lt;/span&gt;), records.GetColumn(&lt;span class="str"&gt;"groupID"&lt;/span&gt;));
            
            DropTable(&lt;span class="str"&gt;"Records"&lt;/span&gt;);
            DropTable(&lt;span class="str"&gt;"Groups"&lt;/span&gt;);
        }&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;*&lt;strong&gt;Note&lt;/strong&gt;: I'm working on the syntax to drop the FK constraint. I know it's heavy.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;If you needed to alter a column, you use:&lt;/p&gt;&lt;pre class="csharpcode"&gt;    AlterColumn(&lt;span class="str"&gt;"records"&lt;/span&gt;, &lt;span class="str"&gt;"RecordName"&lt;/span&gt;, System.Data.DbType.String, 800);&lt;/pre&gt;
&lt;p&gt;You can change the column's length, type, name, and nullability if you need to. You can also remove a column from a table:&lt;/p&gt;&lt;pre class="csharpcode"&gt;    RemoveColumn(&lt;span class="str"&gt;"records"&lt;/span&gt;, &lt;span class="str"&gt;"groupid"&lt;/span&gt;);&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Iterations&lt;/strong&gt; &lt;br&gt;If your client says to you "hey great, you made a Records table - but you forgot Labels! You have labelID, where's labels!" - it's time to write another Migration, and migrate from version 1 to version 2:&lt;/p&gt;
&lt;p&gt;Following our convention, add another class file to the Migrations folder:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;002_AddLabels&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Next up, add the code to Up/Down our migration:&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;namespace&lt;/span&gt; MigrationSample.Migrations {
    
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; Migration002:Migration {
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Up() {

            &lt;span class="rem"&gt;//add the labels table&lt;/span&gt;
            TableSchema.Table labels = CreateTableWithKey(&lt;span class="str"&gt;"Labels"&lt;/span&gt;, &lt;span class="str"&gt;"labelID"&lt;/span&gt;);
            labels.AddColumn(&lt;span class="str"&gt;"LabelName"&lt;/span&gt;);
            AddSubSonicStateColumns(labels);


            Execute(&lt;span class="str"&gt;"INSERT INTO Labels(labelname) VALUES('Capitol')"&lt;/span&gt;);
            Execute(&lt;span class="str"&gt;"INSERT INTO Labels(labelname) VALUES('Arista')"&lt;/span&gt;);
            Execute(&lt;span class="str"&gt;"INSERT INTO Labels(labelname) VALUES('Virgin')"&lt;/span&gt;);

            TableSchema.Table records = GetTable(&lt;span class="str"&gt;"records"&lt;/span&gt;);
            CreateForeignKey(labels.GetColumn(&lt;span class="str"&gt;"labelID"&lt;/span&gt;), records.GetColumn(&lt;span class="str"&gt;"id"&lt;/span&gt;));

        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Down() {
            TableSchema.Table records = GetTable(&lt;span class="str"&gt;"records"&lt;/span&gt;);
            TableSchema.Table labels = GetTable(&lt;span class="str"&gt;"labels"&lt;/span&gt;);

            &lt;span class="rem"&gt;//drop the FK&lt;/span&gt;
            DropForeignKey(labels.GetColumn(&lt;span class="str"&gt;"labelID"&lt;/span&gt;), records.GetColumn(&lt;span class="str"&gt;"id"&lt;/span&gt;));
            DropTable(&lt;span class="str"&gt;"labels"&lt;/span&gt;);
        }
    }
}&lt;/pre&gt;
&lt;p&gt;Yes! Migrations also allow you to add data! I know that inline script is probably not what you had in mind ;) - I'll have this worked out by the time we go final with 2.1 (allowing you to use our query tool) but for now - the ability is there.&lt;/p&gt;
&lt;p&gt;Now, to execute...&lt;/p&gt;
&lt;p&gt;&lt;font face="Lucida Console"&gt;&lt;strong&gt;sonic.exe /migrate&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;You can set this up like you do with other SubCommander commands - please see the video for how to make this happen!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Comparisons&lt;/strong&gt; &lt;br&gt;There are other things out there (like DB projects with VS) and I go into some of this in the video (nudge nudge). This isn't a versioning tool per se - it's a development tool. If you like scripts, more power to ya. Migrations take a little getting used to, that's for sure.&lt;/p&gt;
&lt;p&gt;Caveats &lt;br&gt;This stuff may still be a tad rough. We've tested it a lot, but whenever you talk about tweaking DB schema and code... well there's a reason there's not many Migration solutions in .NET land right now :). Please be patient and help us to get this up to par.&lt;/p&gt;</description></item><item><title>All About Rails</title><link>http://subsonicproject.com/active-record/all-about-rails/</link><pubDate>Thu, 17 Apr 2008 16:43:00 GMT</pubDate><guid isPermaLink="true">http://subsonicproject.com/active-record/all-about-rails/</guid><dc:creator>Rob Conery</dc:creator><slash:comments>0</slash:comments><category domain="http://subsonicproject.com/active-record/">Active Record</category><description>&lt;p&gt;This is a screencast I did last summer (2007) wherein I walked through some of the neat features of Rails - specifically the things that inspired SubSonic.&lt;/p&gt;&lt;embed menu="menu" quality="high" wmode="Window" loop="loop" scale="ShowAll" height="685" width="774" src="http://subsonicproject.com/media/soniccast_rails.swf" pluginspage="http://www.macromedia.com/shockwave/download/index.cgi?P1_Prod_Version=ShockwaveFlash"&gt;&lt;/embed&gt;</description></item><item><title>SubSonic 2.1 Beta 3 Now Available</title><link>http://subsonicproject.com/2-1-pakala/subsonic-2-1-beta-3-now-available/</link><pubDate>Thu, 10 Apr 2008 23:15:00 GMT</pubDate><guid isPermaLink="true">http://subsonicproject.com/2-1-pakala/subsonic-2-1-beta-3-now-available/</guid><dc:creator>Eric Kemp</dc:creator><slash:comments>4</slash:comments><category domain="http://subsonicproject.com/2-1-pakala/">2.1: Pakala</category><description>&lt;p&gt;Well, these days it looks like it takes a new SubSonic release to get me to actually write a blog post, so I guess I'll have to crank up the rate that we're putting out builds! In any event, I'm happy to announce the third beta of SubSonic 2.1 is &lt;a href="http://www.codeplex.com/Release/ProjectReleases.aspx?ProjectName=subsonic&amp;amp;ReleaseId=11591"&gt;now available on CodePlex&lt;/a&gt;. There are a ton of fixes in this release, and it's starting to look very solid, with core already faster and more solid that 2.0.3. The next milestone will be Release Candidate 1, which we will get to GA as fast we can, especially since we're very anxious to start taking advantage of the C# 3.0 language features.&lt;/p&gt;
&lt;p&gt;While we're not officially announcing it, so as to properly set initial expectations, this release features the first migration capabilities, which &lt;a href="http://blog.wekeroad.com/"&gt;Rob&lt;/a&gt; and &lt;a href="http://a-simian-mind.blogspot.com/"&gt;Shawn&lt;/a&gt; have poured a ton of work in to. But if you're brave, and feeling like diving into the code, have at it.&lt;/p&gt;
&lt;p&gt;I'd also like to extend a special thanks to &lt;a href="http://forums.subsonicproject.com/members/yitzchok.aspx"&gt;Yitzchok&lt;/a&gt; AKA &lt;a href="http://forums.subsonicproject.com/members/yitzchok.aspx"&gt;adminjew&lt;/a&gt; for his contributions to this release. Yitzchok not only contributed a really nice patch that allows providers to be loaded from external assemblies, he has truly embraced the often thankless job of moderating the forums, answering question after question while people like me get to do the fun stuff. Thank you Yitzchok!&lt;/p&gt;
&lt;h5&gt;&lt;strong&gt;&lt;font size="4"&gt;Beta 3 Fix/Feature List&lt;/font&gt;&lt;/strong&gt;&lt;/h5&gt;
&lt;p&gt;&lt;a href="http://www.codeplex.com/subsonic/WorkItem/View.aspx?WorkItemId=11714"&gt;Work Item 11714&lt;/a&gt; - DataReader Exceptions Can Cause Memory Leaks&lt;br /&gt;
&lt;a href="http://www.codeplex.com/subsonic/WorkItem/View.aspx?WorkItemId=11740"&gt;Work Item 11740&lt;/a&gt; - Scripting May Fail With Large Schemas/Data Sets&lt;br /&gt;
&lt;a href="http://www.codeplex.com/subsonic/WorkItem/View.aspx?WorkItemId=11933"&gt;Work Item 11933&lt;/a&gt; - Views Are Not Properly Paged Under Sql Server 2000&lt;br /&gt;
&lt;a href="http://www.codeplex.com/subsonic/WorkItem/View.aspx?WorkItemId=12375"&gt;Work Item 12375&lt;/a&gt; - WriteTrace Throws Security Exception with Medium Trust&lt;br /&gt;
&lt;a href="http://www.codeplex.com/subsonic/WorkItem/View.aspx?WorkItemId=12786"&gt;Work Item 12786&lt;/a&gt; - WriteTrace Throws Security Exception with Medium Trust (Duplicate)&lt;br /&gt;
&lt;a href="http://www.codeplex.com/subsonic/WorkItem/View.aspx?WorkItemId=14660"&gt;Work Item 14660&lt;/a&gt; - LoadFromPost() Doesn't Fill DirtyColumn Collection&lt;br /&gt;
&lt;a href="http://www.codeplex.com/subsonic/WorkItem/View.aspx?WorkItemId=15015"&gt;Work Item 15015&lt;/a&gt; - SubStage Generates Controller Classes when RepositoryRecord is Used&lt;br /&gt;
&lt;a href="http://www.codeplex.com/subsonic/WorkItem/View.aspx?WorkItemId=15469"&gt;Work Item 15469&lt;/a&gt; - SqlQuery Doesn't Perform Type Conversion on Constraint Values&lt;br /&gt;
&lt;a href="http://www.codeplex.com/subsonic/WorkItem/View.aspx?WorkItemId=15590"&gt;Work Item 15590&lt;/a&gt; - SqlDataProvider.ExecuteTr&lt;wbr&gt;&lt;/wbr&gt;ansaction must not close the DB connection&lt;br /&gt;
&lt;a href="http://www.codeplex.com/subsonic/WorkItem/View.aspx?WorkItemId=15594"&gt;Work Item 15594&lt;/a&gt; - SqlQuery: Aggregates/Tables not aliased properly when using OracleDataProvider&lt;br /&gt;
&lt;a href="http://www.codeplex.com/subsonic/WorkItem/View.aspx?WorkItemId=15596"&gt;Work Item 15596&lt;/a&gt; - SubSonic.Sugar.Dates Incorrectly Identifies Weekends/Weekdays&lt;br /&gt;
&lt;a href="http://www.codeplex.com/subsonic/WorkItem/View.aspx?WorkItemId=15605"&gt;Work Item 15605&lt;/a&gt; - RepositoryRecord not Tagged as [Serializable]&lt;br /&gt;
&lt;a href="http://www.codeplex.com/subsonic/WorkItem/View.aspx?WorkItemId=15649"&gt;Work Item 15649&lt;/a&gt; - ExecuteJoinedDataSet Throws Exception When Sorting on Joined Column&lt;br /&gt;
&lt;a href="http://www.codeplex.com/subsonic/WorkItem/View.aspx?WorkItemId=15652"&gt;Work Item 15652&lt;/a&gt; - SqlQuery.CloseExpression(&lt;wbr&gt;&lt;/wbr&gt;) Causes &amp;quot;Index was Outside the Bounds of the Array&amp;quot; Error&lt;br /&gt;
&lt;a href="http://www.codeplex.com/subsonic/WorkItem/View.aspx?WorkItemId=15660"&gt;Work Item 15660&lt;/a&gt; - Many-to-Many Save[ClassName]Map Delete Methods Do Not Specify Data Type When Adding Parameters&lt;br /&gt;
&lt;a href="http://www.codeplex.com/subsonic/WorkItem/View.aspx?WorkItemId=15661"&gt;Work Item 15661&lt;/a&gt; - Many-to-Many Save[ClassName]Map Methods Use Incorrect Data Type for Foreign Primary Key&lt;br /&gt;
&lt;a href="http://www.codeplex.com/subsonic/WorkItem/View.aspx?WorkItemId=15688"&gt;Work Item 15688&lt;/a&gt; - ANSISqlGenerator.Generate&lt;wbr&gt;&lt;/wbr&gt;Constraints() Does Not Set DbType&lt;br /&gt;
&lt;a href="http://www.codeplex.com/subsonic/WorkItem/View.aspx?WorkItemId=15689"&gt;Work Item 15689&lt;/a&gt; - SqlQuery.SetConstraintPar&lt;wbr&gt;&lt;/wbr&gt;ams() Loses Parameters When Building &amp;quot;NotIn&amp;quot; Queries&lt;br /&gt;
&lt;a href="http://www.codeplex.com/subsonic/WorkItem/View.aspx?WorkItemId=15696"&gt;Work Item 15696&lt;/a&gt; - Sql2005Generator.BuildPag&lt;wbr&gt;&lt;/wbr&gt;edSelectStatement() Sets Incorrect Paging Boundaries&lt;br /&gt;
&lt;a href="http://www.codeplex.com/subsonic/WorkItem/View.aspx?WorkItemId=15725"&gt;Work Item 15725&lt;/a&gt; - AndExpression/OrExpressio&lt;wbr&gt;&lt;/wbr&gt;n Improperly Identify a Closed Expression as Open&lt;br /&gt;
&lt;a href="http://www.codeplex.com/subsonic/WorkItem/View.aspx?WorkItemId=15747"&gt;Work Item 15747&lt;/a&gt; - Object Names in the Form &amp;quot;[Name]TypeCode&amp;quot; are Inexplicably Changed to &amp;quot;[Name]Type&amp;quot;&lt;br /&gt;
&lt;a href="http://www.codeplex.com/subsonic/WorkItem/View.aspx?WorkItemId=15753"&gt;Work Item 15753&lt;/a&gt; - SqlCE Provider Incorrectly Set CommandTimeout Value&lt;br /&gt;
&lt;a href="http://www.codeplex.com/subsonic/WorkItem/View.aspx?WorkItemId=15771"&gt;Work Item 15771&lt;/a&gt; - ExecuteJoinedDataSet Incorrectly Inserts &amp;quot;PK&amp;quot; Column When First Ordinal Column Is a Foreign Key&lt;br /&gt;
&lt;a href="http://www.codeplex.com/subsonic/WorkItem/View.aspx?WorkItemId=15779"&gt;Work Item 15779&lt;/a&gt; - SqlQuery: INNER JOIN with WHERE Clause Can Result in 'Ambiguous column name' Error&lt;br /&gt;
&lt;a href="http://www.codeplex.com/subsonic/WorkItem/View.aspx?WorkItemId=15795"&gt;Work Item 15795&lt;/a&gt; - Repository Get[ObjectName] Methods Leave Open Data Readers&lt;br /&gt;
&lt;a href="http://www.codeplex.com/subsonic/WorkItem/View.aspx?WorkItemId=15796"&gt;Work Item 15796&lt;/a&gt; - SubStage Doesn't Fully Refresh Database Schema&lt;br /&gt;
&lt;a href="http://www.codeplex.com/subsonic/WorkItem/View.aspx?WorkItemId=15799"&gt;Work Item 15799&lt;/a&gt; - SqlQuery: INNER JOIN with WHERE Clause Can Result in 'Ambiguous column name' Error (Duplicate)&lt;br /&gt;
&lt;a href="http://www.codeplex.com/subsonic/WorkItem/View.aspx?WorkItemId=15823"&gt;Work Item 15823&lt;/a&gt; - SqlQuery.SetConstraintPar&lt;wbr&gt;&lt;/wbr&gt;ams() Loses Parameters When Building &amp;quot;NotIn&amp;quot; Queries (Duplicate)&lt;br /&gt;
&lt;a href="http://www.codeplex.com/subsonic/WorkItem/View.aspx?WorkItemId=15841"&gt;Work Item 15841&lt;/a&gt; - ANSISqlGenerator.Generate&lt;wbr&gt;&lt;/wbr&gt;CommandLine() Does Not Properly Comma-Delimit Select List When Passing Literal Values&lt;br /&gt;
&lt;a href="http://www.codeplex.com/subsonic/WorkItem/View.aspx?WorkItemId=15939"&gt;Work Item 15939&lt;/a&gt; - GetValue&amp;lt;T&amp;gt;(string columnName) in TableSchema May Fail with Non-Nullable GUIDs&lt;br /&gt;
&lt;a href="http://www.codeplex.com/subsonic/WorkItem/View.aspx?WorkItemId=16012"&gt;Work Item 16012&lt;/a&gt; - SqlQuery.ExecuteScalar() Does Not Properly Handle/Cast DBNull Return Values&lt;br /&gt;
&lt;a href="http://www.codeplex.com/subsonic/WorkItem/View.aspx?WorkItemId=15616"&gt;Work Item 15616&lt;/a&gt; - Option to Use UTC Format for Managed DateTime Fields&lt;br /&gt;
&lt;a href="http://www.codeplex.com/subsonic/WorkItem/View.aspx?WorkItemId=15978"&gt;Work Item 15978&lt;/a&gt; - Patch to Support DataProviders in External Assemblies&lt;br /&gt;
&lt;a href="http://www.codeplex.com/subsonic/WorkItem/View.aspx?WorkItemId=15996"&gt;Work Item 15996&lt;/a&gt; - DataProvider.GetSPList() Should Return Stored Procedures in Alphabetical Order&lt;/p&gt;
&lt;p&gt;Thanks again to everyone who contributed to this release. Keep the feedback and &lt;a href="http://www.codeplex.com/subsonic/WorkItem/List.aspx"&gt;Work Items&lt;/a&gt; coming!&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;&lt;a href="http://www.codeplex.com/Release/ProjectReleases.aspx?ProjectName=subsonic&amp;amp;ReleaseId=11591"&gt;Download SubSonic 2.1 Beta 3&lt;/a&gt;&lt;/strong&gt;&lt;/h2&gt;</description></item><item><title>Debug Visualizer for SubSonic Collections</title><link>http://subsonicproject.com/utility/debug-visualizer-for-subsonic-collections/</link><pubDate>Thu, 03 Apr 2008 13:16:00 GMT</pubDate><guid isPermaLink="true">http://subsonicproject.com/utility/debug-visualizer-for-subsonic-collections/</guid><dc:creator>Etienne Tremblay</dc:creator><slash:comments>0</slash:comments><category domain="http://subsonicproject.com/utility/">Utility</category><description>&lt;p&gt;&lt;em&gt;This article comes from &lt;a href="http://blog.lavablast.com/post/2007/12/Debug-Visualizer-for-SubSonic-Collections.aspx"&gt;LavaBlast Software Blog&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://subsonicproject.com/files/media/image/WindowsLiveWriter/DebugVisualizerforSubSonicCollections_827C/image_4.png"&gt;&lt;img width="536" height="48" border="0" src="http://subsonicproject.com/files/media/image/WindowsLiveWriter/DebugVisualizerforSubSonicCollections_827C/image_thumb_1.png" alt="image" style="border: 0px none ;" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://subsonicproject.com/files/media/image/WindowsLiveWriter/DebugVisualizerforSubSonicCollections_827C/image_2.png"&gt;&lt;img width="392" height="196" border="0" align="right" src="http://subsonicproject.com/files/media/image/WindowsLiveWriter/DebugVisualizerforSubSonicCollections_827C/image_thumb.png" alt="image" style="border: 0px none ; margin: 0px 0px 10px 10px;" /&gt;&lt;/a&gt; Wouldn't it be nice to be able to see a &lt;a href="http://www.subsonicproject.com/"&gt;SubSonic&lt;/a&gt; collections while you are debugging, just like the DataSet debug visualizer? Because we often need such a tool to debug our SubSonic collections here at &lt;a href="http://www.lavablast.com"&gt;LavaBlast&lt;/a&gt;, I've created a small Visual Studio Debug Visualizer that you can use to see what your SubSonic collections contain.&amp;nbsp; How does it work?&amp;nbsp; While you are debugging, put a breakpoint somewhere and simply hover your mouse over a SubSonic collection variable.&amp;nbsp; You should see something similar to the screenshot shown above.&lt;/p&gt;
&lt;p&gt;Once the tooltip has appeared, you can click on the small magnifier to open the debug visualizer.&amp;nbsp; You'll see a DataGridView similar to the picture on the right. This will show all your SubSonic objects in a easy to navigate list.&amp;nbsp; Basically my code takes the SubSonic list and transform it in a DataTable.&amp;nbsp; I can't use the method ToDataTable() from the SubSonic AbstractList because this requires access to the provider's configuration, and the JIT executing the debug visualizer doesn't have access to it.&lt;/p&gt;
&lt;p&gt;To use this simple tool, download this file &lt;a rel="enclosure" href="http://blog.lavablast.com/file.axd?file=SubSonicVisualizer.dll"&gt;SubSonicVisualizer.dll (8.00 kb)&lt;/a&gt; and put it in your [My Documents]\Visual Studio 2008\Visualizers\ folder, creating the directory if it doesn't already exist. (You might want to double check your file system permissions on this folder, as well.) I compiled this for Visual Studio 2008.&amp;nbsp; I have also included the source code here (Visual Studio 2008) in case anyone wants to enhance it.&lt;/p&gt;
&lt;p&gt;&lt;a rel="enclosure" href="http://blog.lavablast.com/file.axd?file=SubSonicVisualizer.zip"&gt;SubSonicVisualizer.zip (386.36 kb)&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;If you are using Visual Studio 2005, I think this file will work for you, but I have not tested it: &lt;a rel="enclosure" href="http://blog.lavablast.com/file.axd?file=SubSonicVisualizer2005.dll"&gt;SubSonicVisualizer2005.dll (8.00 kb)&lt;/a&gt;. I simply changed the reference from Microsoft.VisualStudio.DebuggerVisualizers.dll version 9.0 to 8.0 and, from what I have read, it should work in VS.NET 2005.&lt;/p&gt;</description></item></channel></rss>
