Blue Theme Orange Theme Green Theme Red Theme
 
Team Foundation Server Hosting
Home | Forums | Videos | Advertise | Certifications | Downloads | Blogs | Interviews | Jobs | Beginners | Training
 | Consulting  
Submit an Article Submit a Blog 
 Jump to
Skip Navigation Links
TechnologyExpand Technology
WebsiteExpand Website
Discover the top 5 tips for understanding .NET Interop
Search :       Advanced Search »
Home » Design & Architecture » An Elegant C# Data Access Layer using the Template Pattern and Generics

An Elegant C# Data Access Layer using the Template Pattern and Generics

The GOF Template pattern coupled with .NET 2.0 Framework generics provides an awesome synergistic alliance. This article demonstrates how to drastically reduce the amount of code required in building a data access layer. Less code to debug... less code to break... less code to maintain... what could be better?

Author Rank :
Page Views : 168863
Downloads : 4535
Rating :
 Rate it
Level : Intermediate
   Print Read/Post comments Post a comment  Similar Articles  
   Email to a friend  Bookmark  Author's other articles  
Download Files:
TemplateArticle.zip
 
 
Team Foundation Server Hosting
Become a Sponsor
Team Foundation Server Hosting
Become a Sponsor
 Tag Cloud
 Latest Jobs
More ... 
 Latest Interview Questions
More ... 

The GOF Template pattern coupled with .NET 2.0 Framework generics provides an awesome synergistic alliance.  This article demonstrates how to drastically reduce the amount of code required  in building a data access layer.  Less code to debug... less code to break... less code to maintain... what could be better?

Part I: Introduction to the Template Pattern

To get started, let's talk about the GOF Template pattern.  As with all GOF patterns, its primary purpose is to separate out what changes in your code from what does not change. The Template pattern deals with repetitive coding within a class.  If you find yourself coding the same thing over-and-over (and over), you can get rid of the repetition of code using the Template pattern.

Here is an example.  A perfect opportunity is if you have a ton of classes where you are doing similar logic as in GetTheFancyNumber() below

public class DoSomething

{

    private int m_number;

    public int GetTheFancyNumber()

    {

        int theNumber = m_number;

        // DO LOTS OF CRAZY STUFF TO theNumber HERE.

        return theNumber;

    }

}

public class DoSomethingElse

{

    private int m_number;

    public int GetTheFancyNumber()

    {

        int theNumber = m_number;

        // DO LOTS OF CRAZY STUFF TO theNumber HERE.

        return theNumber;

    }

}

If the logic is similar in the classes and you can identify what changes, you can encapsulate it.  You take the code shared by the classes and put it in a base class and make the parent class responsible for what changes.  In this example we would pub the "GetTheFancyNumber()" method in a base class and encapsulate setting the "theNumber" variable (the first line of the method), forcing the parent classes to take care of it.

This would be our Template:

public abstract class DoSometingBase

{

    protected abstract int GetTheNumber();

    public int GetTheFancyNumber()

    {

        int theNumber = GetTheNumber();

        // LOTS LOTS OF CRAZY STUFF TO theNumber HERE.

        return theNumber;

    }

}

Then when we create the parent classes, we use the logic encapsulated by the template and implement the things that change (getting the number):

public class DoSomethingElse : DoSometingBase

{

    private int m_number;

    protected override int GetTheNumber()

    {

        return m_number;

    }

}

 

public class DoSomething : DoSometingBase

{

    private int m_number;

    protected override int GetTheNumber()

    {

        return m_number;

    }

}


So, that's the Template pattern in a nut-shell.  Where it really shines is when we couple it with generics.

Part II. Template Pattern + Generics = Mapping Synergy

Where is the one place where we all do the same thing over-and-over (and over) again?  You guess it! – accessing a database and getting objects built from the data.  This is where we'll implement the Template pattern to create an elegant DAL (Data Access Layer).

First, let's build a simple table to use in this example that will hold some data for a person.

CREATE TABLE [tblPerson] (
 [PersonID] [int] IDENTITY (1, 1) NOT NULL ,
 [FirstName] [nvarchar] (50),
 [LastName] [nvarchar] (50),
 [Email] [nvarchar] (50) ,
 CONSTRAINT [PK_tblPerson] PRIMARY KEY  CLUSTERED
 (
  [PersonID]
 )  ON [PRIMARY]
) ON [PRIMARY]

So now we have this exciting table to hold our data. :

 

Now, we will build a class to hold the data (the code is in the project files – I won't bore you with it here).

 

There are two things we do repeatedly when accessing data.  First we have to access the database, issue a command, and get the results.  Second, we have to map those results to our objects.  Both of these steps are candidates for templatizing (templatizing(?)... that's a real word, right?).

Let's look at the mapping part first because it's the easier one of the two.  (The mapper pattern is an awesome enterprise pattern introduced in a book by Fowler.)

In this example we'll be coding to the IDataReader and IDataRecord interfaces in order to map our data to objects (IDataReader basically inherits from and iterates through IDataRecords).

I would always recommend coding to existing framework interfaces wherever possible so your code is more flexible (check out my article on interface based development here:

http://www.c-sharpcorner.com/UploadFile/rmcochran/csharp_interrfaces03052006095933AM/csharp_interrfaces.aspx?ArticleID=cd6a6952-530a-4250-a6d7-54717ef3b345 ). 

By coding to these interfaces, we are only tightly coupled to the database where we actually create the connection.  This makes our code easily portable to any database so when someone says "Hey, this is great! Let's move it to MySQL!" you don't have to pull your hair out.

So anyways... back to the subject. Here is our mapper base object.  The parent class will take care of the mapping specifics.  The base class will take care of taking each mapped object and putting it in a collection.  Because generics allow us to specify logic for any type the template can be used for all of our objects pulled from the DAL, not just the Person.

abstract class MapperBase<T>

{

    protected abstract T Map(IDataRecord record);

 

    public Collection<T> MapAll(IDataReader reader)

    {

        Collection<T> collection = new Collection<T>();

 

        while (reader.Read())

        {

            try

            {

                collection.Add(Map(reader));

            }

            catch

            {

                throw;

 

                // NOTE:

                // consider handling exeption here instead of re-throwing

                // if graceful recovery can be accomplished

            }

        }

 

        return collection;

    }

}

When we inherit the MapperBase to actually map to a Person object we only have to implement the specifics of creating an object and mapping the data from the IDataRecord to the object's properties. 

class PersonMapper: MapperBase<Person>

{

    protected override Person Map(IDataRecord record)

    {

        try

        {

            Person p = new Person();

 

            p.Id = (DBNull.Value == record["PersonID"]) ?

                0 : (int)record["PersonID"];

 

            p.FirstName = (DBNull.Value == record["FirstName"]) ?

                string.Empty : (string)record["FirstName"];

 

            p.LastName = (DBNull.Value == record["LastName"]) ?

                string.Empty : (string)record["LastName"];

 

            p.Email = (DBNull.Value == record["Email"]) ?

                string.Empty : (string)record["Email"];

 

            return p;

        }

        catch

        {

            throw;

 

            // NOTE:

            // consider handling exeption here instead of re-throwing

            // if graceful recovery can be accomplished

        }

    }

}

Can you see how easy it would be to create a new mapper for any class we have defined that pulls data from a table?  If you see the possibilities, I imagine you are getting a bit excited right about now.  Hold on though, we aren't even to the good part yet.

Part III. Template Pattern + Generics = DataAccess Synergy

The other thing we have to do is actually hit the database with a request and get the IDataReader back. 

Here is what changes for each table we are hitting and each object we are creating:

  1. Getting the connection.
  2. Getting the Sql Command
  3. Getting the Sql Command Type
  4. Getting the mapper (from part II)

IDbConnection GetConnection();

string CommandText { get; }

CommandType CommandType { get; }

Collection<IDataParameter> GetParameters(IDbCommand command);

MapperBase<T> GetMapper();

Here is what stays the same which we'll encapsulate in an Execute() method that will return a collection of our objects.

public Collection<T> Execute()

{

    Collection<T> collection = new Collection<T>();

 

    using (IDbConnection connection = GetConnection())

    {

        IDbCommand command = connection.CreateCommand();

        command.Connection = connection;

        command.CommandText = this.CommandText;

        command.CommandType = this.CommandType;

 

        foreach(IDataParameter param in this.GetParameters(command))

            command.Parameters.Add(param);

 

        try

        {

            connection.Open();

 

            using (IDataReader reader = command.ExecuteReader())

            {

                try

                {

                    MapperBase<T> mapper = GetMapper();

                    collection = mapper.MapAll(reader);

                    return collection;

                }

                catch

                {

                    throw;

 

                    // NOTE:

                    // consider handling exeption here

                    // instead of re-throwing

                    // if graceful recovery can be accomplished

                }

                finally

                {

                    reader.Close();

                }

            }

        }

        catch

        {

            throw;

 

            // NOTE:

            // consider handling exeption here instead of re-throwing

            // if graceful recovery can be accomplished

        }

        finally

        {

            connection.Close();

        }

    }

}

So, here is the class we end up with:


 

One of the things that will be the same for all of the objects inheriting from ObjectReaderBase is getting the connection: "GetConnection()". We'll put this in an abstract object implementing the ObjectReaderBase<T>.

abstract class ObjectReaderWithConnection<T> : ObjectReaderBase<T>

{

    private static string m_connectionString =
         @"Data Source=DATA_SOURCE_NAME;Initial Catalog=Test;Integrated Security=True";

   

        protected override System.Data.IDbConnection GetConnection()

    {

        // update to get your connection here

 

        IDbConnection connection = new SqlConnection(m_connectionString);

        return connection;

    }

}

So we have:

 

Here is the implementation of a PersonReader which handles things specific to reading a person from the database and building a collection of Person objects.

class PersonReader: ObjectReaderWithConnection<Person>

{

    protected override string CommandText

    {

        get { return "SELECT PersonID, FirstName, LastName, Email FROM tblPerson"; }

    }

 

    protected override CommandType CommandType

    {

        get { return System.Data.CommandType.Text; }

    }

 

    protected override Collection<IDataParameter> GetParameters(IDbCommand command)

    {

        Collection<IDataParameter> collection = new Collection<IDataParameter>();

        return collection;

 

        //// USE THIS IF YOU ACTUALLY HAVE PARAMETERS

        //IDataParameter param1 = command.CreateParameter();

        //param1.ParameterName = "paramName 1"; // put parameter name here

        //param1.Value = 5; // put value here;

 

        //collection.Add(param1);

 

        //return collection;  

    }

 

    protected override MapperBase<Person> GetMapper()

    {

        MapperBase<Person> mapper = new PersonMapper();

        return mapper;

    }

}

So now we have:

Once you have the general concept, you will probably have many ideas on how you can tweak this base reader object for improvements or to fit your specific projects needs. 

Also, you will have to create a different base object for each "type" of data access you'll be performing.  For example you may need other abstract base classes for when you will be executing IDbCommand.ExecuteNonQuery() or IDbCommand.ExecuteScalar() requests against the database.

Part IV. Mapping Synergy + DataAccess Synergy = Elegant Code

The important thing to realize is that we have completely separated out normally repetitive code which will make for much easier maintenance because of a smaller code base.  For each new table-class relationship you have in your project you only have to specify the things that are different.  So, while this approach may look like more classes and complexity upfront, once you understand and implement this approach you'll actually save a lot of time as the number of  "data holding" classes in your project grows and you'll have fewer places to look when debugging because of all the shared-code-synergy.

This is how we'll use our framework to retrieve everyone from the database and print them to the console:

static void Main(string[] args)

{

    PersonReader reader = new PersonReader();

    Collection<Person> people = reader.Execute();

 

    foreach (Person p in people)

        Console.WriteLine(string.Format("{0}, {1}: {2}",
            p.LastName, p.FirstName, p.Email));

 

    Console.ReadLine();

 

}

Part V. Conclusion.

So now you have the general idea you can use it as a base to build a DAL. There are many places to improve upon this approach such as using an identity map (yet another awesome Fowler pattern) to avoid unnecessary database hits or a better way to get the IDbConnection, such as using the strategy pattern and maybe using a factory,  or how about a facade pattern to expose all of this functionality through one object....  anyways the possibilities are (almost) endless depending on your project.

You will most likely have to make changes to have this approach work for any specific project, but as you can see, it is possible to have less code to debug... less code to break... less code to maintain... what could be better?  We can synergize our code by combining the Template Pattern with generics.

Until next time,

Happy coding

Comment Request!
Thank you for reading this post. Please post your feedback, question, or comments about this post Here.
Login to add your contents and source code to this article
 [Top] Rate this article
 
 About the author
 
Matthew Cochran
Looking for C# Consulting?
C# Consulting is founded in 2002 by the founders of C# Corner. Unlike a traditional consulting company, our consultants are well-known experts in .NET and many of them are MVPs, authors, and trainers. We specialize in Microsoft .NET development and utilize Agile Development and Extreme Programming practices to provide fast pace quick turnaround results. Our software development model is a mix of Agile Development, traditional SDLC, and Waterfall models.
Click here to learn more about C# Consulting.
 
Introducing MaxV - one click. infinite control. Hyper-V Hosting from MaximumASP.
Finally – a virtual platform that delivers next-generation Windows Server 2008 Hyper-V virtualization technology from a managed hosting partner you can truly depend on. Visit www.maximumasp.com/max for a FREE 30 day trial. Hurry offer ends soon. Climb aboard the MaxV platform and take advantage of High Availability, Intelligent Monitoring, Recurrent Backups, and Scalability – with no hassle or hidden fees. As a managed hosting partner focused solely on Microsoft technologies since 2000, MaximumASP is uniquely qualified to provide the superior support that our business is built on. Unparalleled expertise with Microsoft technologies lead to working directly with Microsoft as first to offer IIS 7 and SQL 2008 betas in a hosted environment; partnering in the Go Live Program for Hyper-V; and product co-launches built on WS 2008 with Hyper-V technology.
Dynamic PDF
ceTE software specializes in components for dynamic PDF generation and manipulation. The DynamicPDF™ product line allows you to dynamically generate PDF documents, merge PDF documents and new content to existing PDF documents from within your applications.
Discover the top 5 tips for understanding .NET
Ricky Leeks presents the top 5 tips for understanding .NET Interoperability. Learn more.
Nevron Chart for .NET 2010.1 Now Available
The leading .NET charting control now features PDF, Flash and Silverlight export, visualization of large datasets and more. Deliver true charting functionality to your BI, Scorecard, Presentation or Scientific apps. Download evaluation now.
ASP.NET 4 Hosting
Get 2 Months Free of ASP.NET Hosting for Only $4.95/month! Receive FREE MS SQL and MySQL Databases Including ASP.NET 4/3.5, MVC 3.0, Silverlight 4, Windows 2008/IIS 7.0 Plus FREE IIS 7 Modules. Host UNLIMITED ASP.NET Web Sites – Click Here!
 
 Post a Feedback, Comment, or Question about this article
Subject:
Comment:
Team Foundation Server Hosting
Become a Sponsor
 Comments
MySQL by psycho_tx On May 29, 2006

Hi there,

First I have to say, great article !!

could you give me an example how to let this example communicate with MySQL

And what would you have to do if you want to use stored procedures.

thanks already

Greets

Reply | Email | Modify 
Good article... thoughts about updating and inserting? by Christoffer On July 26, 2006

I have implemented your approach for reading data, and it works like a charm.

But I have som thougts about updating and inserting (where you don't need generics)

Does this look like a reasonable approach?:

---------- CODE -----------

class CustomerUpdater : DataUpdaterBase

{

private Customer _customer;

private string _commandText;

public CustomerUpdater(Customer customer)

{

_customer = customer;

}

protected override string CommandText

{

set

{

_commandText = value;

}

get

{

return _commandText;

}

}

protected override System.Data.CommandType CommandType

{

get

{

return System.Data.CommandType.StoredProcedure;

}

}

protected override Collection<IDataParameter> GetParameters(IDbCommand command)

{

Collection<IDataParameter> collection = new Collection<IDataParameter>();

IDataParameter custGuid = command.CreateParameter();

custGuid.ParameterName = "GUID";

custGuid.DbType = DbType.Guid;

custGuid.Direction = ParameterDirection.Input;

custGuid.Value = _customer.GUID;

collection.Add(custGuid);

return collection;

}

}

Reply | Email | Modify 
Re: Good article... thoughts about updating and inserting? by Matthew On August 1, 2006

Yeah,  it seems like a reasonable approach to me. 

Sometimes I like using an IPersisted interface approach to keep things more abstract/flexible.

this way you can pass any of your objects into a utility method (implementing the the IPersister interface below) and it will know whether to insert, update, delete, or ignore the object. 

Here is a rough example (very rough -- hopefully it makes sense)...

IPersisted
{

  bool IsSaved { get; set; }
  bool IsDeleted { get; set; }
  bool IsDirty { get; set; }
  bool IsNew { get; set; }

}

IPersister
{
  bool Persist(IPersisted item);
}

public class Book: IPersisted
{

  // define book here
}

public class Person: IPersisted
{
   // define person here
}


public static class  Persister: IPersister
{

  public bool Persist(IPersisted item)
  {
    if(item is Person)
    {

        // call save method here and update/persist person data

   }
    else if (item is Book)
    {

        // call save method here and update/persist book object data
    }

 }
}

Reply | Email | Modify 
Re: Re: Good article... thoughts about updating and inserting? by Christoffer On August 3, 2006

Thanks for the reply

I kind a see what your getting at, but a static class cannot implement an interface or inherit from an abstract class as far as I know.

What are your thoughts about this article:

http://www.codeproject.com/useritems/BusinessObjectHelper.asp

 

Kind regards

 

Christoffer

Reply | Email | Modify 
Re: Re: Re: Good article... thoughts about updating and inserting? by Matthew On August 3, 2006

Nice article.  I could see that approach being perfect for some situations, maybe overkill for others. 

You may want to look into combining either approach with code generation and see what you can come up with.  Check out CodeSmith, it is a nice tool: http://codesmithtools.com/.  Once you have your basic code base down, code generation can really expedite the creation of the data access layer and it makes it easy to quickly adapt your core classes to minor data structure changes.

and.. you are 100% correct.  We can't implement interfaces with static classes (my fault for madly typing away without thinking).  You can achive this result with a singleton (or just abandon all interest in playing nice with the memory and have a ton of instances lying about).

 

Reply | Email | Modify 
Re: Re: Re: Re: Good article... thoughts about updating and inserting? by Christoffer On August 3, 2006

Yes a singleton would of course solve it :).

Anyways, great article, you left me greatly inspired. Keep up the good flow of articles

Kind regards

Christoffer

Reply | Email | Modify 
BindingList? by Stephen On August 7, 2006
Wouldn't it make sense to use a BindingList collection so that you can throw the events for when items are added/deleted/changed?
Reply | Email | Modify 
Re: BindingList? by Matthew On August 7, 2006
Yeah, especially if you need to monitor the list.  I guess it would depend on how you are monitoring the state of the objects.  If they are self-monitoring, you may not want the extra overhead, if they are being monitored by another state-management object, the BindingList would certainly make life easier. 
Reply | Email | Modify 
MapperBase by csharpcorner On November 13, 2006

If the names of your data class properties are the same as the data table column names, you can use the following implementation of the Map method in the MapperBase class to avoid having to write manual mapping code for each data class.

using System.Reflection;
public abstract class MapperBase<T> where T : new()

protected T Map(IDataRecord record)
{
 T instance = new T();

 string fieldName;
 PropertyInfo[] properties = typeof(T).GetProperties();

 for (int i = 0; i < record.FieldCount; i++)
 {
  fieldName = record.GetName(i);

  foreach (PropertyInfo property in properties)
  {
   if (property.Name == fieldName)
   {
    property.SetValue(instance, record[i], null);
   }
  }
 }

 return instance;
}

Reply | Email | Modify 
Re: MapperBase by Matthew On November 13, 2006
Nice.  Thanks.
Reply | Email | Modify 
Re: MapperBase by Rodrigo On March 17, 2007

Hi,

when I use "where T : new" in my code I've not gotten compile it.

the compiler error focus is Line: "protected abstract MapperBase<T> GetMapper();" on class ObjectReaderBase.

the error message is: "The type 'T' must have a public parameterless constructor in order to use it as parameter 'T' in the generic type or method"

I dont know what's my class need.

Thanks.

Reply | Email | Modify 
Re: Re: MapperBase by Dennis On May 23, 2007

Hi rodrigod,

Check that your class has a parameterless contructor:

new() constraint - The type argument must expose a public, parameterless (default) constructor

It works fine for me.

D

Reply | Email | Modify 
Re: Re: MapperBase by Ashok On June 27, 2007

To get compile your code please add constructor constriant ( where T: new()) to other base classes also.

to ObjectReaderWithConnection and to ObjectReaderBase

like

class ObjectReaderBase<T> where T : new()

class ObjectReaderWithConnection<T> : ObjectReaderBase<T> where T : new()

 

hope this helps

Regards

Ashok

 

Reply | Email | Modify 
how about parameters? by Tom On August 7, 2007
Hello, I find this piece of code indeed an elegant but it lacks of usability or am I missing something? I need to parametrise Readers. Lets take PersonReader. I need to make method like: Person person = personReaderInstance.getPerson(personId); And I wish to have couple of methods like this per reader with different parameters. What then? I'm trying to walk around this issue but my conceptions violate the elegancy :/
Reply | Email | Modify 
Re: how about parameters? by shirkdaddy On March 15, 2008
Did anyone ever find a solution for parametrized readers? I'm running into the same issue. Every path I go down seems to contradict the elegance of this solution. I thought about providing another Execute method like: public T Execute(int objectId) { ... map here ...} but that doesn't seem right either (CommandText and parameters are set in the PersonReader). I suppose some flag could be set in ObjectReaderBase and some logic added to PersonReader to handle this, but bleck! Makes the elegance in the rest of the code seem pointless. Not to mention we'd have to create Execute methods for every combination of parameters needed to return a single object ref of any possible type...
Reply | Email | Modify 
Re: Re: how about parameters? by Lorenzo On May 6, 2010
Hi i've just been reading this article:-

http://www.c-sharpcorner.com/UploadFile/rmcochran/elegant_dal05212006130957PM/elegant_dal.aspx

I was wondering if you ever found an answer to your question or not? I've noticed the same thing regarding the lack of getPerson(int Id) method etc... just wondering if you ever came up with anything. 

Thanks
Reply | Email | Modify 
Example to Insert,Update... by Nivitha On January 15, 2008
Hi, This article has been very useful to me. Can you please give an example to perform Insert, Update, Delete operations?
Reply | Email | Modify 
Prashant by Prashant On August 20, 2008
Hi, I like this article. Taking basic ideas from the DataAccess, I have created a simple framework. I might be posting the framework soon. Pras
Reply | Email | Modify 
Prashant by Prashant On August 20, 2008
Hi, I like this article. Taking basic ideas from the DataAccess, I have created a simple framework. I might be posting the framework soon. Pras
Reply | Email | Modify 
Layers structure by Giorgio On October 13, 2008
Hi there, Nice article! Suppose I'm separating Dal and business logic layers on two different assemblies and let both depend on on a third assembly containing interfaces for abstracting dependencies. Where would the PersonMapper class be? It seems to me that the business logic layer would be the correct place but how would the class PersonMapper be instantiated by the dal class without breaking separation of the layers?
Reply | Email | Modify 
Question on Part III of your article by Biplab On July 1, 2010

Hi Matthew,

First of all thank you for writing such a wonderful article. I have considered using your approach for the DAL but I have a question.
In section III at the bottom of the section you wrote "Also, you will have to create a different base object for each "type" of data access you'll be performing.  For example you may need other abstract base classes for when you will be executing IDbCommand.ExecuteNonQuery() or IDbCommand.ExecuteScalar() requests against the database."
Now if I create other abstract base classes for different type of data access, how will the reader (e.g. PersonReader) inherit from all of them - I mean they can't inherit from multiple abstract base. Do we end up creating different classes on the reader instead of a single PersonReader?
Appreciate your response on my query.

Thanks,
Biplab banerjee

Reply | Email | Modify 
Only returning one record? by Shaun On August 8, 2010
I am currently trying this example out, but I have an issue where I am only getting one record back from the database where I know there is two, (I have debugged the command.CommandText attribute and put that into a SQL statement within SQL Server, and it does return the two records).  Now I have attempted to debug the Reader.Execute, however at the point it attempts to do a MapAll, if I am debugging, the reader object returns zero records.  However if I let it run its course, without debugging, at the end it returns one record. Being the first in the table.  Thanks very much.
Reply | Email | Modify 
Query returning multiple record set by Christophe On August 25, 2010
Hello Mathew,

Can you tell me how to implement when i want return multiple record set in one Stored procedure....


-Thanks and regards
Chris
Reply | Email | Modify 
Great Article! by Jon On October 29, 2010
Hi Matt,
This is an excellent article, well done!  It's such a common scenario in any application, and I can't tell you the number of times I've written a complete ExecuteReader() method for different domain objects.  This solution really takes advantage of generics and the end result is indeed elegant.

Good job!
Jon
Reply | Email | Modify 
Create Article ***** by Joe On February 11, 2011
Problem Solved: <?xml version="1.0" encoding="utf-8" ?> <configuration> <startup useLegacyV2RuntimeActivationPolicy="true"> <supportedRuntime version="v4.0"/> </startup> </configuration> Original Problem: I've created an application that generates my table classes using your approach by reading the sql I use to create all of my database tables in CreateDatabase.sql. Your framework works great in .net 2.0!!! But when I try to build my application in .Net 4 Client Profile it get this exception in the "public abstract class ObjectReaderBase<T>" in "using (IDbConnection connection = GetConnection())" "Mixed mode assembly is built against version 'v2.0.50727' of the runtime and cannot be loaded in the 4.0 runtime without additional configuration information." What am I missing? Thanks, Joe
Reply | Email | Modify 
Object Writer by Joe On August 10, 2011
The ObjectReader and associated files work great. Is there any chance there is an ObjectWriterBase, ObjectWriterWithConnection similar to the object reader classes?
Reply | Email | Modify 
Mindcracker MVP Summit 2012
 © 2012  contents copyright of their authors. Rest everything copyright Mindcracker. All rights reserved.