Friday, August 14, 2009

C# 3.0 - Lambda expressions in charge of DataReader operations

After a long-time usage of generics-based method to read data from SqlCommand, using IDataReader, now it seems that I'm gonna love the lambda expressions approach.

What I've used:

public delegate void RowReaderHandler<T>(IDataReader reader, T obj);

public static void RowSetReader<T>(IDataReader reader, RowReaderHandler<T> handle, T obj)
{
while (reader.Read())
{
handle(reader, obj);
}
reader.Close();
}

as a base functionalllity in an abstract class, then calling this from every implementation, as follows:

public MyClass LoadMyClassByID (int ID){
MyClass myClass = new MyClass();
SetCommandNameAndParams(SP_LOAD_BY_ID, ID);
IDataReader reader = base.GetDataReader();
RowSetReader<MyClass>(reader, FillMyClassDetails, myClass);
}

public void FillMyClassDetails (IDataReader reader, MyClass myClass){
myClass.ID = reader.GetInt32(0);
myClass.Name = reader.GetString(1);
}


There is a better approach, using Action<T> delegates and lambda expressions. This is the method in the base, abstract class:


public void SingleRowReader(Action<IDataReader> processor)
{
IDataReader reader = Execute();
while (reader.Read())
{
processor(reader);
}
reader.Close();
}

As it's seen, here we are passing only each reader row, instead of passing the item and the reader.
The implementation therefore may seem like:
public MyClass LoadMyClassByID (int ID){
MyClass myClass = new MyClass();
SetCommandNameAndParams(SP_LOAD_BY_ID, ID);
RowSetReader(readerRow => this.FillMyClassDetails(myClass, readerRow));
}

public void FillMyClassDetails (MyClass myClass, IDataReader reader){
myClass.ID = reader.GetInt32(0);
myClass.Name = reader.GetString(1);
}

At first sight, the differences are just syntactic, and less parameters passed in the 'lambda' example. But, digging deep, you may see that that lambdas will give us more freedom to call processing methods with variable parameters, contrary to the limitation of matching the processing method to the predefined delegate above.
Just a sample - imagine you have to pass additional parameter to the FillMyClassDetails method :

public void FillMyClassDetails (IDataReader reader, MyClass myClass, bool loadAge){
myClass.ID = reader.GetInt32(0);
myClass.Name = reader.GetString(1);
if (loadAge)
myClass.Age = reader.GetInt32(2);
}

While, in the first approach you will have to modify or add new delegate with 'params[]' parameters, in the second one you have nothing to do with the base functionallity. The only difference will be :

{
...
RowSetReader<(readerRow => this.FillMyClassDetails(myClass, readerRow, loadAge));
...
}

As lambda expression evaluates just the 'readerRow' parameter, it is irrelevant to the other part of the method parameters.
Handy, huh...

Starting MVC project - initialization

As the easiest way to start a new MVC project is to attach a SQL Express database file. But if you don't want to get through the whole process with Visual Studio, inspired by this awesome article: Creating a SQLEXPRESS database file from code from "Where's Lou" blog, you can download the compiled db creation utility from here. Usage is pretty simple:

sqlexpressdbcreator C:\mypath\mydb.mdf

Full path is required.

The utility is generated with the dynamic C# compiler tool, I am using for years. It is very useful for fast tests of code parts: