Avoid code duplication when reading/serializing from DbDataReader?

138 Views Asked by At

Consider the FetchData method below. It is designed to avoid duplicating the database query code every time you want to fetch some data from the database.

List<MyData> myData = new List<MyData();
FetchData((IDataReader reader) =>
   {
       myData.Add(new MyData(reader.GetString(0), reader.GetInt32(1)));
   }, "usp_get_my_data");

It works, but it would be nice if this object creation could somehow live inside the FetchData method.

Is there a better approach?

Perhaps FetchData can be modified to return a list of some type X directly?

protected void FetchData(Action<IDataReader> processor, String query)
{
    using (var connection = CreateConnection())
    {
        connection.ConnectionString = ConnectionString;
        connection.Open();

        using (var command = connection.CreateCommand())
        {
            command.CommandType = CommandType.StoredProcedure;
            command.CommandText = query;

            using (IDataReader reader = command.ExecuteReader())
            {
                while (reader.read())
                {
                    processor(reader);
                }
            }
        }
    }
}
2

There are 2 best solutions below

1
On BEST ANSWER

Using generics maybe?

protected IEnumerable<T> FetchData<T>(Func<IDataReader, T> processor, String query)
{
    using (var connection = CreateConnection())
    {
        connection.ConnectionString = ConnectionString;
        connection.Open();

        using (var command = connection.CreateCommand())
        {
            command.CommandType = CommandType.StoredProcedure;
            command.CommandText = query;

            using (IDataReader reader = command.ExecuteReader())
            {
                while (reader.read())
                {
                    yield return processor(reader);
                }
            }
        }
    }
}

Then you can use the enumeration however you want:

var myData = FetchData<MyData>(reader => new MyData(reader.GetString(0), reader.GetInt32(1)), "usp_get_my_data").ToList();
1
On

You might take a look at Dapper.Net which is single file ORM with three different helpers:

  1. Execute a query and map the results to a strongly typed List
  2. Execute a query and map it to a list of dynamic objects
  3. Execute a Command that returns no results

Design patterns used to build this miro-ORM are so helpful. Dapper.Net is currently being used in StackOverflow.