Sponsored By Aspose - File Format APIs for .NET

Aspose are the market leader of .NET APIs for file business formats – natively work with DOCX, XLSX, PPT, PDF, MSG, MPP, images formats and many more!

Data Access Application Block Revealed – Factory Methods and Reflection

The other day I talked about the Data Access Application Block and how you can use it in your applications to assist you with ADO.NET.


In particular, I briefly discussed this piece of code:


 


Data Access Application Block
Database db = DatabaseFactory.CreateDatabase();

string query = Select * from Customers Where CustomerID = @CustomerID;

DBCommandWrapper command = db.GetSqlStringCommandWrapper(query);

command.AddInParameter(@CustomerID, DbType.String, id);

using (IDataReader reader = db.ExecuteReader(command))
{
// Do Something…
}


 


One of the statements worth understanding a bit better is


 


Factory Method
Database db = DatabaseFactory.CreateDatabase();

Defers the decision of which class to instantiate.


 


If you take a peek at the DAAB source code, that statement is fairly involved on the surface.  It tosses you around to a number of classes and overloaded methods that could be difficult to figure out if you are new to .NET and object-oriented programming.  There is some pretty cool stuff going on there, so I thought I would mimic this statement with an example that is easier to understand.


In the DAAB, Database is an abstract class.  As any abstract class, you cannot create an instance of it.  You can only create concrete classes that derive from Database.  The DAAB currently has 2 such concrete classes: SqlDatabase and OracleDatabase.


So given this piece of knowledge, we can infer that the DatabaseFactory.CreateDatabase() static method will probably return an object of SqlDatabase or OracleDatabase which will be assigned to db.  The actual concrete class will probably be created on-the-fly based on some logic (in this case the settings in the DAAB configuration file).  This type of method is called a Factory Method as it defers the decision of which class to instantiate.


Let’s mimic this concept by building our own classes and factory method using an example that is closely related.  First our database classes.  Although they are on a much simpler scale, the classes below follow the same pattern as in the DAAB.  We have an abstract class, called Database, and two concrete classes, called SqlServer and Oracle, which derive from our base class of Database.  I have one simple abstract method in Database, called GetManufacturer().  As an abstract method, all derived classes are required to implement this method and has been done so accordingly.


 


Database Classes
public abstract class Database
{
public abstract string GetManufacturer();
}

public class SqlServer : Database
{
public SqlServer() {}

public override string GetManufacturer()
{
return Microsoft;
}
}

public class Oracle : Database
{
public Oracle() {}

public override string GetManufacturer()
{
return Oracle;
}
}


 


Now we need to create a Factory Method on a class that creates an instance of SqlServer or Oracle on the fly.  Let’s do it similar to the DAAB, but with only one class for simplicity.


 


Class Factory
public sealed class DatabaseFactory
{
private DatabaseFactory () {}

public static Database CreateDatabase()
{
return CreateDatabase(SqlServer);
}

public static Database CreateDatabase(string databaseName)
{
if (databaseName.Equals(SqlServer) || databaseName.Equals(Oracle))
{
// Find the class
Type database = Type.GetType(databaseName);

// Get its constructor
ConstructorInfo constructor = database.GetConstructor(new Type[] {});

// Invoke its constructor, which returns and instance.
Object createdObject = constructor.Invoke(null);

// Pass back the instance as a Database
return createdObject as Database;
}
else
throw new ArgumentException(Never heard of the database + databaseName);
}
}


 


The class is sealed so nobody derives from it and has a private constructor so nobody can create an instance of it.  This is pretty common for these types of classes.


We have essentially two static factory methods on this class, CreateDatabase() and CreateDatabase(string databaseName), both of which return an object of type Database. If you don’t specify a database, you get the default database, which is “SqlServer”.  This is sort of like the DAAB, but the DAAB looks in the configuration file to find the default database.  In this case, I just hardcoded it for simplicity.


Now the cool stuff is in the second method, CreateDatabase(string databaseName).  The databaseName parameter is the name of the class type we want to create on-the-fly.  In our case, it either has to be SqlServer or Oracle, the two concrete classes we created that derive from Database.


The rest is simple reflection similar to how it is done in the DAAB.  The comments above really tell it all.  We find the type requested in databaseName (SqlServer or Oracle), get its default constructor, and then invoke its default constructor which passes back an instance of the type.  We then just cast the object to type Database and return it back to the calling program.


Here is code you can run to test all our classes:


 


Testing Our Classes
using System;
using System.Reflection;

public abstract class Database
{
public abstract string GetManufacturer();
}

public class SqlServer : Database
{
public SqlServer() {}

public override string GetManufacturer()
{
return Microsoft;
}
}

public class Oracle : Database
{
public Oracle() {}

public override string GetManufacturer()
{
return Oracle;
}
}

public sealed class DatabaseFactory
{
private DatabaseFactory () {}

public static Database CreateDatabase()
{
return CreateDatabase(SqlServer);
}

public static Database CreateDatabase(string databaseName)
{
if (databaseName.Equals(SqlServer) || databaseName.Equals(Oracle))
{
// Find the class
Type database = Type.GetType(databaseName);

// Get it’s constructor
ConstructorInfo constructor = database.GetConstructor(new Type[] {});

// Invoke it’s constructor, which returns and instance.
Object createdObject = constructor.Invoke(null);

// Pass back the instance as a Database
return createdObject as Database;
}
else
throw new ArgumentException(Never heard of the database + databaseName);
}
}

public class TestClass
{
public static void Main()
{
// Default is Sql Server
Database defaultDatabase = DatabaseFactory.CreateDatabase();
Console.WriteLine(defaultDatabase.GetManufacturer());
Console.ReadLine();

// Asking explicitly for Oracle
Database oracle = DatabaseFactory.CreateDatabase(Oracle);
Console.WriteLine(oracle.GetManufacturer());
Console.ReadLine();
}
}


 


Hopefully the above code will illuminate what is going on in the DAAB when you make a call to DatabaseFactory.CreateDatabase().  Although we are doing it on a much simpler scale, it is the same technique and one you can use in your applications.

This entry was posted in Application Blocks, C#. Bookmark the permalink. Follow any comments here with the RSS feed for this post.

4 Responses to Data Access Application Block Revealed – Factory Methods and Reflection

  1. David Hayden says:

    I am not sure how they can dynamically create an instance of a class they don’t know until runtime without using reflection.

    You’re right that they don’t need reflection if they are only ever going to have two database providers: SqlDatabase and OracleDatabase.

    However, I think the PAG wanted to leave the opportunity for others to either override the existing classes or create their own and be able to plug them in. Since these would probably exist in another assembly in the bin directory, the only way to access those types to my knowledge is via reflection.

    There is a performance hit to using reflection, but I think the idea here is that the gain in extensibility more than outweighs any performance hit. Rocky Lhotka (of CSLA fame) would also try to convince you that the delay in using reflection is insignificant compared to the actual delay in the database call and is hence a moot point.

    I am right with you though. Reflection is often overused and if not done properly can impact the usability and scalability of your applications.

  2. Mark Bonafe says:

    A good explanation of the DAAB. I never liked all the reflection, though. Why not just create methods to create what is need without the reflection? Sure, it’s a little more code, but it’s much more effecient than using reflection.

  3. David Hayden says:

    Those are the Fieldset and Legend HTML Tags.

    I don’t think I can shown the tags well via this comment area so check here for an example:

    http://www.w3.org/TR/REC-html40/interact/forms.html#edef-LEGEND

  4. Jeff Lynch says:

    Dave,

    How do you get the cool little "boxes" around your sample code man?

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>