CSharp and Datalayers

One thing that has become very important in my recent work is datalayers. I’ve seen a few difference approaches to filling objects after the data has been retrieved. All methods appear very similar in theory, but the implementations and restrictions are slightly different.

I’ll start with the simplest example which is right here is “Single User Blog”. I like the theory behind this, basically there is a root object in the application that all other objects inherit from, in this case “ApplicationDataObject”. This root object contains a Fill() function which can in simplest terms, populate itself from an input datasource. So in the SUB implementation, you instantiate a new object and call Fill(datasource). The Fill() function in this case uses Property = Value to populate everything. When more properties are required in subclasses, the Fill() method (marked as virtual) is just simply overridden and the new properties taken care of.

One of the more complex datalayers I’ve come across uses a static function in the datalayer that not only dynamically fills the object (using reflection to find the properties), but also takes care of instantiating it and setting properties that are missing in the datasource to a null value. So if I wanted an array of posts it might look like this:

DataReader reader = DL.ListGetPostsByAll();
ArrayList array = DL.FillCollection(typeof(Post), reader);

All to easy, however it’s not very flexible, especially if it’s an object with complex properties that are not primitive types.

So by using these two already clever techniques the approach I’ve used is a combination of the two. I’ve still kept the static function in the datalayer, but it will fill a previously instantiated object. The properties on the object are dynamically found with TypeDescriptor, instead of GetType().GetProperties(). There are example articles on CodeProject on how to implement ICustomTypeDescriptor, so you can even trick TypeDescriptor into fetching your own dynamic properties. The properties that are missing from the datasource are not set to null or blank, this is because I think all that should be done in the class’s own constructor.
So to get an array of posts (looks nearly the same as how SUB already does it) the code might look something like this:

PostCollection list = new PostCollection();
using (_SqlDL = new SQLiteDataHandler())
{
IDataReader dr = _SqlDL.ListPostsByAll();
while (dr.Read())
{
Post obj = new Post();
Fill(dr, obj);
list.Add(obj);
}
dr.Close();
}

It’s a little more work then the previous example, but allows for more flexibility in how the objects are instantiated, and so forth…

Conclusion:

As explained above, here is my example Fill() method from the Sqlite datalayer I’ve used in this blog. Notice in this case it handles DateTime properties differenty because they need to be converted from a UDT to a Local DateTime.
public static virtual void Fill(IDataReader reader, object obj)
{
  int curOrdinal;
  foreach (PropertyDescriptor prop in TypeDescriptor.GetProperties(obj))
  {
    curOrdinal = reader.GetOrdinal(prop.Name);
    if (curOrdinal > -1)
    {
      try
      {
        if(prop.PropertyType == typeof(DateTime))
        {
          TimeZoneInformation info = 
  TimeZoneInformation.FromName(BlogConfigurationSettings.TimeZoneName);
          prop.SetValue(obj, info.FromUniversalTime((DateTime)
   Convert.ChangeType(reader.GetValue(curOrdinal), prop.PropertyType)));
        }
        else
        {
          prop.SetValue(obj, Convert.ChangeType(reader.GetValue
            (curOrdinal), prop.PropertyType));
        }
      }
      catch (Exception err)
      {
      //throw err;
     }
   }
   else 
   {
     //does not exist in datareader
   }
  }
}
.NET Code Snippets
Posted by: Brendan Kowitz
Last revised: 21 Sep 2013 12:15PM

Comments

3/21/2006 3:01:11 PM
Found an interesting article where Tin Lam has done a similar thing with reflection, but using XML:
http://www.c-sharpcorner.com/Code/2002/Mar/ReflectingXMLDataTLam.asp

No new comments are allowed on this post.