Thursday, January 14, 2010

Linq2DataSet Introduction

Lately I’ve been working for a client that recently moved an existing application to VS 2008 / .NET 3.5. The app uses some DataSets, so I’ve been playing to what I call Linq2DataSet (or Linq to DataSet).

Getting Started

To use Linq2DataSet will need to use the .NET 3.5 runtime and, in addition to the usual ADO.NET assemblies you will need to add a reference to System.Data.DataSetExtensions.dll.

Quick comparison to Linq2Sql

// Linq To Sql
int Linq2SqlGetCount()
{
     BigTableSQLDataContext data = new BigTableSQLDataContext();
     return (from x in data.Big_Tables select x).Count();
}
// Linq to DataSet
int Linq2DataSetGetCount()
{
     BigTableDS data = new BigTableDS();
     Big_TableTableAdapter da = new Big_TableTableAdapter();
     da.Fill(data.Big_Table);

     return (from x in data.Big_Table select x).Count();
}

The code isn’t that much different. There is a little more code to setup the DataSet than the SQL DataContext. No big deal.

There is a big gotcha. I ran both functions against a table with 20,000 records. The DataSet is fully loaded before anything can happen. In the code above, the Linq2Sql function runs in < 1 second and the Linq2DataSet version takes about a minute and a half.

In Linq2DataSet, all 20,000 are loaded into the DataSet before the Linq code is executed. In Linq2Sql, the engine executes the Linq and generates the SQL to get the data (probably something like SELECT COUNT(*) FROM Big_Table).

Yes, this looks bad, however if you already have the DataSet hanging around, Linq2DataSet may be a Mega-Cool way to solve your problems. For the record, I would not recommend Linq2DataSet for new “Green Field” projects, however, if you already have the DataSet lying around, Linq can make it easy to get that little bit of extra info you need. Linq2DataSets is also a way to get into Linq quickly then you can learn about Linq2Sql or the Entity Framework.

More to come…

Sunday, December 13, 2009

Nullable Data Types Demo

The Problem

In several of the projects I’ve worked on, we used some token value to represent null for non-nullable types. These values would be extreme values (for int, we would use int.MinValue or int.MaxValue), or null token. Recently I’ve come across some controls that don’t like this scheme and prefer using nullable types (like int?).

The original code was written in C# 1.X, so nullable types didn’t exist; the code works, so I don’t want to convert the non-nullables to nullable and risk breaking the rest of the application.

In production, I’ve solved the problem by creating “shadow” nullable properties. The code in these properties would translate the null tokens to null. For the most part the translation code is inline.

Taking it to 11 with Generics

This weekend, I played with implementing this stuff with a generic helper class. So the code for a nullable property would look something like this:

public DateTime? DobNullable
{
     get { return NullableHelper.GetNullable<DateTime>(this.Dob); }
     set { this.Dob = NullableHelper.SetNullable<DateTime>(value); }
}

To do this I created a class called NullableHelper that contained translation functions: The to set you use this:

public static T SetNullable<T>(T? futureValue)
     where T : struct
{
     T rVal;
     if (futureValue != null)
          rVal = (T)futureValue;
     else
          rVal = NullForT<T>();
     return rVal;
}

This function echo back the value passed in UNLESS it is null; if it is null, it returns the null token. And to get, you use this:

public static T? GetNullable<T>(T presentValue)
     where T : struct, IComparable
{
     T? rVal = null;

     // I can't get the generic do == & !=, this works, so I'm 
     // going with it for now.
     IComparable ic = presentValue as IComparable;
     if (ic != null)
     {
          T CompareValue = NullForT<T>();
          if (ic.CompareTo(CompareValue) != 0)
               rVal = presentValue;
          // I already set rVal to null above.
          return rVal;
     }
     else
     {
         throw new ApplicationException(
             string.Format("NullableDataTypesDemo.NullableHelper.GetNullable<T>()" +
                  "\r\n'{0}' is can't be cast to IComparable",
                  typeof(T).ToString())
          );
     }
}

In this function I needed to cast T as IComparable to compare the value with the null token.

Both functions use a null token from the following function:

public static T NullForT<T>() 
     where T : struct
{
     T rVal;
     // Here you will need to have an if for each of the 
     // supported types, this function could be really big in production:
     if (typeof(T) == typeof(DateTime))
     {
          DateTime x = DateTime.MaxValue;
          object o = x;
          rVal = (T)o;
     }
     // Set other null tokens here
     else
     {
          throw new ApplicationException(
                 string.Format("NullableDataTypesDemo.NullableHelper.NullForT<T>()" +
                 "\r\n'{0}' is an unsupported Type", 
                 typeof(T).ToString())
          );
     }
     return rVal;
}

This function is probably the Achilles’ heel of this design. You will need an if (typeof(T) block for each type you want to support in this function. Most of the complexity points of this solution are borne by this function.

Conclusion

Over the weekend I came up with a cool way of translating from a non-nullable with null tokens to nullables. Will I implement this in production? Probably not, the code works and I don’t want to risk breaking it. If I need to do similar things in a future project, I may come back to this post.

The Whole Experiment

using System;

namespace NullableDataTypesDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            // Create an instance of the demo entity
            DemoEntityClass x1 = new DemoEntityClass(
                1, 
                100m,
                "Jill Stephens", 
                NullableHelper.NullForT<DateTime>(), 
                NullableHelper.NullForT<int>());

            // Do some querying
            if (x1.IdNullable != null)
            {
                Console.WriteLine(string.Format("ID = {0}", x1.IdNullable));
            }
            if (x1.NumOfChildren == NullableHelper.NullForT<int>())
            {
                Console.WriteLine("Children Unknown (classic)");
            }
            // Set a DOB
            x1.DobNullable = new DateTime(1776, 7, 4);
            Console.WriteLine(string.Format("{0:d}", x1.DobNullable));
            // Set # of children and display
            x1.NumOfChildrenNullable = 2;
            Console.WriteLine("value of Number of Children: {0}", x1.NumOfChildren);
            // Unset # of children
            x1.NumOfChildren = NullableHelper.NullForT<int>();
            if (x1.NumOfChildrenNullable == null)
            {
                Console.WriteLine("Children Unknown (new)");
            }
            // Won't comile, 
            // NullableHelper.NullForT<DemoEntityClass>();
            // Some NullForT that won't compile
            // (you can fix these by adding code to NullForT())
            try
            {
                NullableHelper.NullForT<DemoStruct>();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
            try
            {
                NullableHelper.NullForT<double>();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }

            // Force read line, so this won't go away in VS
            Console.ReadLine();
        }

    }
    /// <summary>
    /// My Demo Entity Class
    /// </summary>
    class DemoEntityClass
    {
        public DemoEntityClass(int id, decimal amount, string name, DateTime dob, 
            int numOfChildren)
        {
            this.Id = id;
            this.Amount = amount;
            this.Name = name;
            this.Dob = dob;
            this.NumOfChildren = numOfChildren;
        }
        public int Id { get; set; }
        public decimal Amount { get; set; }
        public string Name { get; set; }
        public DateTime Dob { get; set; }
        public int NumOfChildren { get; set; }

        public int? IdNullable
        {
            get { return NullableHelper.GetNullable<int>(this.Id); }
            set { this.Id = NullableHelper.SetNullable<int>(value); }
        }
        public decimal? AmountNullable
        {
            get { return NullableHelper.GetNullable<decimal>(this.Amount); }
            set { this.Amount = NullableHelper.SetNullable<decimal>(value); }
        }
        // string is nullable, so I am including this for completeness
        public string NameNullable
        {
            get { return this.Name; }
            set { this.Name = (string)value; }
        }
        public DateTime? DobNullable
        {
            get { return NullableHelper.GetNullable<DateTime>(this.Dob); }
            set { this.Dob = NullableHelper.SetNullable<DateTime>(value); }
        }
        public int? NumOfChildrenNullable
        {
            get { return NullableHelper.GetNullable<int>(this.NumOfChildren); }
            set { this.NumOfChildren = NullableHelper.SetNullable<int>(value); }
        }
    }
    /// <summary>
    /// My Demo struct
    /// </summary>
    struct DemoStruct
    {
        public int x;
        public int y;
        public int xy { get { return x * y; } }
    }
    static class NullableHelper
    {
        /// <summary>
        /// Gets the Null marker value for value types
        /// </summary>
        /// <remarks>
        /// In some old applications that date back to before nullable types
        /// maked fields as being null with extreme values (int.MaxValue for
        /// example).
        /// </remarks>
        /// <typeparam name="T">Tye value type being tested</typeparam>
        /// <returns>The Null marker value</returns>
        public static T NullForT<T>() 
            where T : struct
        {
            T rVal;
            // Here you will need to have an if for each of the 
            // supported types, this function could be really big in production:
            if (typeof(T) == typeof(int))
            {
                int x = int.MaxValue;
                object o = x;
                rVal = (T)o;
            }
            else if (typeof(T) == typeof(decimal))
            {
                decimal x = decimal.MaxValue;
                object o = x;
                rVal = (T)o;
            }
            else if (typeof(T) == typeof(string))
            {
                string x = string.Empty;
                object o = x;
                rVal = (T)o;
            }
            else if (typeof(T) == typeof(DateTime))
            {
                DateTime x = DateTime.MaxValue;
                object o = x;
                rVal = (T)o;
            }
            else
            {
                throw new ApplicationException(
                    string.Format("NullableDataTypesDemo.NullableHelper.NullForT<T>()" +
                      "\r\n'{0}' is an unsupported Type", 
                    typeof(T).ToString())
                );
            }
            return rVal;
        }
        /// <summary>
        /// Used in a set block to set a non-nullable
        /// field from a nullable value
        /// </summary>
        /// <remarks>
        /// Since the null values are gotten from NullForT, this function can be short
        /// </remarks>
        /// <see cref="NullForT"/>
        /// <typeparam name="T">Tye value type being set</typeparam>
        /// <param name="futureValue">nullable new value</param>
        /// <returns>non nullable value  with Null marker value to denote null</returns>
        public static T SetNullable<T>(T? futureValue)
            where T : struct
        {
            T rVal;
            if (futureValue != null)
                rVal = (T)futureValue;
            else
                rVal = NullForT<T>();
            return rVal;
        }
        /// <summary>
        /// Used in a get block to get a nullable field
        /// from the non-nullable value
        /// </summary>
        /// <remarks>
        /// This function is a little more complex because we need to cast
        /// presentValue to IComparable to compare it to the null token 
        /// </remarks>
        /// <see cref="NullForT"/>
        /// <typeparam name="T">Tye value type being set</typeparam>
        /// <param name="presentValue">
        /// non-nullable value with Null marker value to denote null
        /// </param>
        /// <returns>nullable value returned</returns>
        public static T? GetNullable<T>(T presentValue)
            where T : struct, IComparable
        {
            T? rVal = null;

            // I can't get the generic do == & !=, this works, so I'm 
            // going with it for now.
            IComparable ic = presentValue as IComparable;
            if (ic != null)
            {
                T CompareValue = NullForT<T>();
                if (ic.CompareTo(CompareValue) != 0)
                    rVal = presentValue;
                // I already set rVal to null above.
            }
            else
            {
               throw new ApplicationException(
                 string.Format("NullableDataTypesDemo.NullableHelper.GetNullable<T>()" +
                      "\r\n'{0}' is can't be cast to IComparable",
                 typeof(T).ToString())
               );
            }
            return rVal;
        }
    }
}

Thursday, November 26, 2009

The Gu Rickrolled no one

You may have heard about Scott Guthrie’s Rick Astley related stunt at the PDC in Los Angeles last week. I don’t think it qualifies as a rickroll. As a developer who uses Microsoft technologies, I have sworn to The Gu’s super-duper deluxe uber-geekiness.

IMO, to qualify as a rickroll, you must willfully click on a link expecting something juicy and end up on suffering through “Never Gonna Give You Up”. You make a bad decision that makes you worthy of such punishment.

If you clicked on a link for Paris Hilton’s latest video (wink, wink) and instead got Rick, you have been rickrolled! If you clicked on a link marked Rick Astley’s famous video, you haven’t been rickrolled, you are getting what you expected.

At the PDC, The Gu’s victims didn’t have the free will not to click the link or take the red pill. In this situation, The Gu launched the video.

If one of The Gu’s minions changed out the “real” video with Rick Astley without his knowledge, then he is the only rickrollee.

It could be argued that the attending a Scott Guthrie presentation is bad decision that qualifies one to be worthy of being rickrolled.

Thursday, November 12, 2009

Rant on XML Comments

The purpose of .NET XML comment is to help you generate outside documentation. When you tell Visual Studio to generate the XML file, you get tool tips when you hover over your method and you can use a tool like SandCastle to generate MSDN style help files based on your XML Comments. XML comments are really designed for Black Box documentation of Frameworks and API.

An XML comment is not the same as a development comment. When I am looking at a SandCastle generated help file, I care about how to use your class or method; I don’t care about why you chose to use a bubble sort over a quick sort.

I’ve seen comments like this:

///<summary>
/// DV
///</summary>

where DV is the initials of one of the developers. If you were actually use the XML comment feature, this comment would show up when you mouse over the class in Visual Studio or in the help file you created with SandCastle, same with this comment:

/// <summary>
/// This is the FooBar class!
/// I originally designed on a napkin after midnight after drinking 
/// a fifth of JD & eating 3 orders of hot wings.
/// I was inspired to write this class after Ellen, the goddess of 
/// the 327th Ave NE Pub down the street from my studio apartment,
/// who rejected me after I drank myself silly summoning up the 
/// courage  to ask her out.
/// </summary>

With the VS tooltip feature you lose all formatting, so if you have a comment like

/// <summary>
/// Foobar Class
///
/// Combines Bars with Foos and converts them from Metric to Imperial
///
/// 2005-04-13 – RN – Original implication 
/// 2005-05-03 – RF – Bug #12239 – g to # conversion issue
/// 2008-03-27 – VW – re-Implement Linq to Foo framework
/// </summary>

will appear on 1 or 2 lines without the linefeeds. The tags are ignored when VS creates tooltips.

I know that most of the projects I work on are not frameworks or API, but it still feel the need to avoid using XML comments for things other what I think they are designed for.

I am uptight about XML comments because I have used them, once. We created a help file for a client using SandCastle; the customer was impressed, though I bet they never used it.

Sunday, October 11, 2009

How bad is too bad?

I have been assigned the task of updating a program that isn’t terribly well designed.

How deep do I dive in trying to fix this program? Do I take all of the inappropriate code from the Form Classes and move them into Business Classes? Do I get rid of all the SQL queries in code? Do I tear the whole thing to shreds and start over with my brilliantly planned super object oriented design applying all 23 GoF design patterns? My inner geek screams yes, Yes, YES! But according to Joel Spolsky, rewriting software just to do it can be the biggest mistake “you” can make. (http://www.joelonsoftware.com/articles/fog0000000069.html).

I mean, the program basically works. If the world around the program wasn’t changing, it could probably go unchanged. But we’re replacing one system that this program talks to and replacing it with another one.

Looking at the code, I would date the program to around the 2003 timeframe with stuff added later as the program evolved. I see:


  • Int32 in place of int, String in place of string, etc. (I remember reading and hearing experts recommending that practice in the early days of .NET)

  • Long unstructured functions in the form class. Sort of like VB6 in C#, we know that a lot of that went on in the early 0's.

  • There is some object orientation grafted on to the edges of the program but the core is pretty old fashioned pre-OO .NET 1.0 code.

  • Uses finally in places where rational modern C# coders would use using.

So it isn’t wonderful code, but, for the most part, it works. But like any spoiled brat, I just wanna do it. Why: just because.

The program was written in the ancient times of yore (5 years ago). When .NET first came out, OO was just starting to catch on in the mainstream. Right now I am hearing rumors that the next big thing is going to be Functional programming; the justification is that it is easier to parallelize so elements of the Functional Fad will probably stick around for the long term. What will my elegant OO code look like to the Functional masters of the future?

Tuesday, September 22, 2009

SQL Funny Business

Today at work we were talking about mixing old (table, table where join criteria) and new (table join table on join criteria) style joins in the same query. So that got me to thinking about what ON really does. I ran the following queries against the infamous Northwind Database:

-- The modern style join:
SELECT *
FROM dbo.Orders o
 JOIN [Order Details] od ON od.OrderID = o.OrderID 
WHERE o.CustomerID = 'SUPRD'

-- The classic style join:
SELECT *
FROM dbo.Orders o, [Order Details] od
WHERE od.OrderID = o.OrderID
 AND o.CustomerID = 'SUPRD'

-- Inverted modern join (join criteria in WHERE, selection criteria in ON):
SELECT *
FROM dbo.Orders o
 JOIN [Order Details] od ON o.CustomerID = 'SUPRD'
WHERE od.OrderID = o.OrderID

All three queries gave me the same results set.

Is the ON clause just a different place to shove selection criteria (a phantom where). I like the modern style. You can put all the join information together. You could mix things up when you practice Job Security Based Programming.

I think it would be fun to have a obscure SQL programming competition, like the obscure C programming competitions in the days of yore.

Monday, August 31, 2009

Is it too late to wrap it into a function?

Today I was refactoring several properties in a Business Class from int to int?. I was in a hurry, so I was implementing the 10 properties using cut and paste inheritance (as if that is ever really faster).

After the 8th or 9th properties, the light went off in my mind: I should write a couple of functions to do the hard work and call the functions from the property get and set functions. Was it too late to to do it right?

I said NO.It did take me longer to write the functions than it would have taken to cut and past the 2 remaining properties. However, the code is easier to read, validate and change.

I guess I justify my earlier sloppy coding time as an opportunity to think of the right way. During the first go round I was planning to do the second one; I needed to do it wrong to see how to do it right.