this.Blog.Find(entry => entry.IsHelpful);
 Sunday, April 06, 2008
Miado is out on CodePlex

I have been refining some data access code that I have used on a bunch of my projects to the point where I've made it fairly generic.  I decided to publish it as a project on CodePlex.  I just put the initial release out today.  If you are interested, please take a moment to check it out and give me any feedback.  Keep in mind, I wrote this specifically for those people who have (or want) to use straight SQL and ADO.Net in their data access layer.  So if you want to use LINQ, Nhibernate, Subsonic, etc... they are absolutely great tools, but they try to hide/remove the SQL from your code, whereas this project just makes it much easier for those who use SQL.

Here is an example of how to use it to create a collection of custom business objects:

// ideally this declaration would be buried in your base DAO class
// or injected via an IoC container
IDbConfigurable dbConfig = new DbConfiguration(SqlClientFactory.Instance, connString);
IDbStatement dbStmt = new DbStatement(dbConfig);

ICollection<Address> addresses = 
    dbStmt.LoadSql("SELECT AddressId, Address1, Address2, City, State, ZipCode " + 
                   "FROM Address WHERE City = @City")
          .AddParameter("City", "Atlanta")
          .QueryForResults<Address>(
              row => new Address() 
                  {
                      AddressId = row.GetValue<int>("AddressId"), 
                      Address1 = row.GetValue<string>("Address1"),
                      Address2 = row.GetValue<string>("Address2"),
                      City = row.GetValue<string>("City"),
                      State = row.GetValue<string>("State"),
                      ZipCode = row.GetValue<string>("ZipCode")
                  });

Notice how it removes all the usual boiler plate code from a normal ADO.Net implementation.  The only things you really need to do are provide the SQL, set the parameters, and then map the result set to properties on your business object.  I'm using lambda expressions in these examples, but if you want to re-use the result set-to business object mappings, I normally create a method in my DAOs to use as a delegate:

ICollection<Address> addresses = 
dbStmt.LoadSql("SELECT AddressId, Address1, Address2, City, State, ZipCode " +
"FROM Address WHERE City = @City")
.AddParameter("City", "Atlanta")
.QueryForResults<Address>(CreateAddress);
...
private Address CreateAddress(IResultSetRow row)
{
// full details not provided
return new Address() { AddressId = row.AddressId };
}

If you embed the creation of the IDbStatement interface in a base class (or use the one provided in Miado.Integration), you can see how the code reads even more like a Domain-Specific-Language:

// CreateSqlStatment() method is provided in Miado.Integration.MiadoDao
ICollection<Product> products = 
    this.CreateSqlStatement("SELECT ProductId, Name, Description, Color, Quantity " +
                            "FROM Product WHERE Color = @Color and Quantity > @Qty")
        .AddParameter("Color", "Blue")
        .AddParameter("Qty", 20)
        .QueryForResults<Product>(
              row => new Product() 
                  {
                      ProductId = row.GetValue<int>("ProductId"), 
                      Name = row.GetValue<string>("Name"),
                      Description = row.GetValue<string>("Description"),
                      Color = row.GetValue<string>("Color"),
                      Quantity = row.GetValue<int>("Quantity")
                  });

There is also a SimpleSql object that can be used similar to IDbStatement but the syntax is a little more terse since you don't have to map the parameters - they are merely replaced in the order you provide them:

IDbConfigurable dbConfig = new DbConfiguration(SqlClientFactory.Instance, connString);
SimpleSql sql = new SimpleSql(dbConfig);
sql.ExecuteNonQuery("UPDATE Person SET FirstName = @FirstName, " + 
                    "LastName = @LastName " + 
                    "WHERE PersonId = @PersonId", 
                    "John", "Smith", 1001);
// again, I like to embed this in a base class so it reads:
// this.CreateSimpleSql().ExecuteNonQuery(sql, param1, param2);

For this first release, SimpleSql is not supported for ODBC SQL statements (since it uses pattern matching to substitute the SQL parameters).

Here's another example where you can see how easy it is to get a count:

int count = 
    this.CreateSimpleSql()
        .QueryForOne<int>("SELECT count(*) FROM Employee WHERE YearsOfService > @YearsOfSvc",
                           new object[] { 15 },
                           row => row.GetValue<int>(0));

And yes, it supports the creation of DataSets and DataTables:

DataSet ds = 
    this.CreateSimpleSql()
        .QueryForDataSet("SELECT * FROM ProductType WHERE Price > @Price", 10.0);

This is the first code drop, so treat it like a beta release.


Kick it on DotNetKicks.com
Sunday, April 06, 2008 9:35:57 AM (Eastern Standard Time, UTC-05:00)  #    Comments [1]  .Net | Miado

 Thursday, April 03, 2008
It's baseball season again, and you know what that means!

That's right!  It's time for every jackass with a cell phone to sit behind home plate waving his arms for 9 innings!


Kick it on DotNetKicks.com
Thursday, April 03, 2008 10:47:11 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0]  Humor | Sports

 Tuesday, April 01, 2008
Atlanta Code Camp Recap
Overall, it was a good time.  Most of the sessions I attended were very informative.  I went to an "Sharepoint for ASP.Net Developers" session and was reminded how much I enjoy working on stuff other than Sharepoint.  ;-)  Shawn Wildermuth gave a couple of great sessions (expectedly) on Silverlight and Expression Blend.  It's hard *not* to be excited about Silverlight.  I just hope it can deliver on its promises.

I am always amazed to find so many people who are willing to give up a full day on Saturday to gather together for a geekfest code camp.  A special thanks goes out to the sponsors and organizers for putting this all together.  I am sure it is an absolute labor of love, because I can't believe how much time they must put into this event to make it so successful.

As an added bonus, I won a free pass to the devscovery conference put on by the folks at Wintellect.  Hoo-ray for me.  The conference looks pretty cool, but since hotel and airfare are *not* included, I am reminded of the Seinfeld episode where Jerry offers George "free" Super Bowl tickets - "So in order to use these, I gotta spend like fifteen-hundred bucks.  This is a bill for fifteen-hundred dollars." :-)


Kick it on DotNetKicks.com
Tuesday, April 01, 2008 1:08:10 AM (Eastern Standard Time, UTC-05:00)  #    Comments [0]  .Net | ASP.Net | Conferences | Silverlight

 Friday, March 28, 2008
Handbrake 0.9.2 is out

I'm a little late on this one, but a new version of Handbrake was released last month with significant improvements.  One of the things I noticed right away is that the Windows GUI has drastically improved (the presets are no longer collapsed by default!).  Also, there is now a preset for the Xbox 360!!!

Handbrake

I am always trying to walk people through ripping their DVDs to play on their Xbox.  This is one less step I have to explain!


Kick it on DotNetKicks.com
Friday, March 28, 2008 6:36:04 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0]  Handbrake | Xbox | Tech Support

 Wednesday, March 26, 2008
Changing a control's CSS class name during validation

So I'm converting an ASP.Net prototype that was written entirely in VB Script (don't ask) to C#.  As part of the conversion, I am putting in ASP.Net validation controls on all the input fields in the application.  I was showing off my progress to the graphics designer, and he pointed out that he wanted to dynamically change the CSS class on the input field control that was being validated if it failed validation.  Hmm, I can set the CssClass attribute on the validation control, but I couldn't find anywhere to automatically change the CSS class name on the actual control being validated.

I *could* write custom validators for each input control and change the class name in the javascript validation function, but that seemed like too much work.  So I thought to myself, surely there is some way to add an event listener to the DOM on the validation control to see if it changed it's display attribute.  After some researching, I got it to work.

<head runat="server">
    <title>Test Page</title>
    <style type="text/css">
      .error
      {
        border: solid 1px red;
        background-color: Yellow;
      }
    </style>
</head>
<body>
    <form id="form1" runat="server">
        <asp:ScriptManager ID="ScriptManager1" runat="server" />
        <div>
            <asp:TextBox ID="txtBox" runat="server" />
            <asp:RequiredFieldValidator ID="reqField" runat="server" ControlToValidate="txtBox"
                Display="Dynamic" EnableClientScript="true" ErrorMessage="* Required"
SetFocusOnError="true" />
                <asp:Button ID="btnSubmit" runat="server" Text="Submit" />
        </div>
        <script type="text/javascript" language="javascript">
    function pageLoad() {
        $addHandlers($get('<%= this.reqField.ClientID %>'),
                     { 'DOMAttrModified' : changeTextBoxClass,
'propertychange' : changeTextBoxClass });
    }
    function changeTextBoxClass(eventName) {
        $get('<%= this.txtBox.ClientID %>').className =
            $get('<%= this.reqField.ClientID %>').style.display != 'none' ? 'error' : '';
    }
        </script>
    </form>
</body>
</html>

DOMAttrModified is not supported in IE (shocking!!!) - onpropertychange is the IE equivalent.  Basically, whenever the ASP.Net validators fire and change the "display" attribute on their enclosing <span> tags, I added an event handler that will dynamically set the CSS class on the corresponding input control.  Notice in the example above that I'm using the ASP.Net Ajax library to make my life easier.

Before validation:

image

 

And after the "Submit" button is clicked:

image


Kick it on DotNetKicks.com
Wednesday, March 26, 2008 9:14:38 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0]  .Net | Ajax | ASP.Net

 Saturday, March 22, 2008
Reminder! Atlanta Code Camp on 3/29

Just wanted to post a friendly reminder that the Atlanta Code Camp will be taking place at Devry Tech in Decatur next Saturday (3/29).  If you haven't done so already, register for the event to make sure you get a spot.

If you are going, the City of Decatur is sponsoring an electronics recycling event that very same day at Decatur High School.  The high school is just over a mile away from Devry.  I strongly encourage you to bring any outdated, left-over, unused, or otherwise useless old electronic equipment you have lying around for recycling.

Click on the map below for directions from Devry to Decatur HS.


View Larger Map
Kick it on DotNetKicks.com
Saturday, March 22, 2008 12:11:57 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0]  .Net | Conferences