Click here to Skip to main content
Click here to Skip to main content

A generic data reader with ILGenerator

By , 1 Mar 2007
 

Introduction

When doing a data access layer, have you ever wondered if it was be possible to receive a list of objects instead of a DataReader. This is possible with refection and code generation. This saves a lot of time and if you think that this method is slower that the traditional one, it's false. The performance is somewhat equal to the traditional method.

Background

The last time I worked on a data access layer, I found myself repeating the same lines of code over and over. I executed a DataReader and read each column in a while statement. This method leads to many runtime errors. We have to remember the index of each column. What if we add a column at the beginning without changing the indexes? So I developed a method that binds a class to a query. By analysing the class though reflection, we are able to auto generate the code that uses the data reader.

I have made a little project to test the performance of the GenericReader. To do so, I implemented a IDataReader that is working only in memory in order to have the most reliable benchmarks.

Using the code

In order to do this, we can use the reflection. The idea is to bind a field to a column of a select statement.

As an example, I declare a class with 4 fields. Each field has an attribute with a column name. We can see that the fields are read only; this is possible with the code IL. Furthermore, we can see that I use a double? in order to tell that a value type can be null. The verification is made with the DBNull and the program sets the value to null. This is easier to use.

public struct TestClass
{
    [ReaderName("Field1")]
    public readonly long Field1;
    [ReaderName("Field2")]
    public readonly string Field2;
    [ReaderName("Field3")]
    public readonly double? Field3;
    [ReaderName("Field4")]
    public readonly bool Field4;
}

The last thing we have to do is to use the GenericReader. The following method lets us see how easy it is.

GenericReader genericReader = new GenericReader();
private List<testclass /> ReaderExample(SqlConnection connection)
{
   SqlCommand command = new SqlCommand("SELECT Field1, Field2, Field3, Field4 " +
                                       "FROM AnyTable");
   return genericReader.ReadReader<testclass />(command.ExecuteReader());
}

The GenericReader is using the codeIL to generate a delegate the first time we use a Type. This delegate is use over an over to read the DataReader.

Points of Interest

The most useful thing is that the code is somewhat easier to maintain. Especially when we need to add an information in a select statement. In this case, it's very easy to make mistakes with the indexed of the DataReader.

History

At first, I use reflection to read the data instead of creating a delegate with codeIL. The need came quickly to have a faster way. So I change it a bit. CodeIL is a lot harder to implement, but it was worth it. The people that used the GenericReader told me that they saved a lot of time coding there data access layer.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Henri G Demers
Canada Canada
Member
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralMy vote of 3memberBeyMelamed7 Jan '13 - 18:15 
Scope can be wider - for example, generalize also the connection type (why only SQL Server?)
QuestionProperties instead of fieldsmemberhhilzinger28 Sep '11 - 1:11 
I have tried converting this code to use properties instead of fields. There does appear to be an issue with the il.Emit method in that it is expecting Field info and not property info. There are also no overload methods. I unfortunately dont really understand what this does
il.Emit( OpCodes.Stfld, fi );
and this
il.Emit( OpCodes.Ldsfld, dbNull );
and am not therefore able to change it.
 
It would be really great if you could alter the code to work with properties instead of Fields.
GeneralA generic data reader with ILGeneratormemberMember 412624020 Oct '09 - 3:30 
A generic writer would be nice. Otherwise, good article =)
GeneralI love it !!!!!!!!!!!!!!!!!!!!!!!!!!!!!memberewds28 Feb '09 - 19:31 
It makes the DataReader so easy to use, and it save dirty work. it can save me tons of time.
I hope you will you will improve it and add new functionality needed. I will report if I will fund any defects. at the moment looks great.
Questiontype.GetFields() bug?memberpsykoptic4 Mar '08 - 13:17 
Hi,
 
this is great code and could save me a load of time. But...
 
When I run and debug your example, the InitDelegate method passs the first condition
(_delegateList.ContainsKey(fullName)
 
When I use it in my own code using a DataReader with data from a database,
(_delegateList.ContainsKey(fullName)) is false and the code tries to use
foreach (FieldInfo info in type.GetFields())
 
For some reason it doesn't return any field info, and the List is returned as a list of empty objects.
 
any idea why this might be happening?
Generalvery cool - but not so well advertisedmemberchristoph braendle2 Mar '07 - 1:21 
surely a very nice example of dynamic methods,
you got my 5Smile | :) ,
not for the presentationFrown | :(
but for sharing this nice code.Cool | :cool:

GeneralRe: very cool - but not so well advertisedmemberrashack30 Apr '07 - 9:09 
I must agree. The code behind this article is really cool.
 
Maybe detailed insight into the code would be good.

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web03 | 2.6.130523.1 | Last Updated 1 Mar 2007
Article Copyright 2007 by Henri G Demers
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid