Home  /  Questions  /  Question



89   96.5
Mar 25, 2011


Abstract Factory - How to break down a large factory?

In the Patterns in Action solution of the Design Pattern Framework (v3.5) the data access layer uses the Abstrat Factory pattern to shield creation of data access objects from the client.  With a small number of data access objects this seems to be OK, however when modelling a database with hundreds of tables, the number of data access objects quickly grows and in turn results in large factories which each have to be updated when a table/data access object is added.

Is there a way to break down a large factory in some way to make it more maintainable and to adhere to the open closed principle?

One possible idea I can think of is to have a generic method as follows (where T would be a DAO Interface):

public T CreateInstance<T>()
{
    // Use reflection here to lookup a concrete type in the DataAccess assembly that implements T
}

then the business logic classes would have a private instance e.g.:

private static ICustomersDao _customerDao = DataAccess.CreateInstance<ICustomersDao>();


I think each DAO interface would need to inherit from a marker interface so that a generic constraint could be placed on the method to limit the types that could be returned.

Assuming the data access layer supports SQL, Oracle, etc, then the CreateInstance<T>() method would have to only lookup concreate classes in the relevant namespace, so if the DB provider was set to 'System.Data.SqlClient' in the config then we would only want to find a concrete class in the SqlServer DAO namespace.

Would this work?  Any other suggestions?




1,364   100.0
Mar 25, 2011
Generics approach will work.  I have implemented my own custom DAL 5 years back and it is still going smooth (no exaggeration here).

The approach is similar to what is in EF , but with a twist.  Just to outline how it works (there are no class clutters)..

Assume there is a Customer table in the DB.  The entity is modelled as below

[Table ("ebCustomerMaster")]
public class Customer
{
    [Column()]
     public Guid Id {
             get { return id; }
             set { id = value; }
     }

    [Column()]
     public string Name{
             get { return name; }
             set { name = value; }
     }
}

I am just displaying a subset of properties.  Note this class is auto generated by a custom utility.

Now we have a SmartData<T> class which is responsible for generating the SQL based on xml file (as this was our requirement).

A sample insert function in the SmartData is displayed below.


    public class SmartData<T>
    {

        public int Insert(T obj, string spName)
        {
            DataRow queryRow = dsSQL.Tables["Query"].Select("Id = '" + spName + "'")[0];

            string commandText = queryRow["CommandText"].ToString();
            string commandType = queryRow["CommandType"].ToString();

            Request request = new Request();
            request.CommandText = commandText;

            request.CommandType = (CommandType)Enum.Parse(typeof(CommandType), commandType);
            ProcessParameter(obj, request);

            return dbEngine.Insert(request);
        }
       
         // MORE functions goes here....
        
}

NOTE : Here there is no scope for SQL injection attach as the actual sql is not built here....

Then there's a DB engine which is responsible for talking with the underlying dtabase.

The DBEngine's Insert function is shown below...

        public int Insert(Request request)
        {
            using (DbCommand command = factory.CreateCommand())
            {
                int ret = 0;
                //if (null == connection || connection.State != ConnectionState.Open)
                OpenConnection();

                command.Connection = connection;
                if (request.Parameters.Count > 0)
                {
                    foreach (Parameter para in request.Parameters)
                    {
                        DbParameter p1;
                        switch (dataProvider)
                        {
                            case "System.Data.OleDb":
                                p1 = new System.Data.OleDb.OleDbParameter(para.ParameterName, para.Value);
                                p1.DbType = GetDbTypeFromString(para.DataType);
                                command.Parameters.Add(p1);
                                break;
                            case "System.Data.SqlClient":
                                p1 = new System.Data.SqlClient.SqlParameter(para.ParameterName, para.Value);
                                p1.DbType = GetDbTypeFromString(para.DataType);
                                command.Parameters.Add(p1);
                                break;
                            default:
                                command.Parameters.Add(para);
                                break;
                        }
                    }
                }

                command.CommandText = request.CommandText;
                command.CommandType = request.CommandType;
                command.CommandTimeout = 0;

                ret = command.ExecuteNonQuery();
           
                return ret;
            }

The actual code may differ than what is shown here....

The good thing is there are no sub classes or any other helpers apart from the usual Service layer....
The DBEngine abstracts away the providers.  The query details in the XML gives us the flexibility to switch to stored procedures
or plain SQL queries at will.

Switching providers is as easy as creating a new xml file and updating only specifics which changes (in most cases
sql server, mysql, and oracle, most of the things are same)......


NOTE and suggestion:  I had taken this approach when EF was not available (or was in early stages) and data access  block
was also in  a very early stage.

I will recommend you also have a look at the MS Enterprise Library Data access blocks as well.  But don't be afraid to roll out your own if need arises.

This custom solution has provided me with a lot of flexibility in  a real enterprise application handling about 400 tables of data entry and about 1000 reports.... So, you can imagine the magnitude of usage of this library.. The only thing is it is not opensource, but there are various similar implementations available, and if you need to roll out, you can quickly do so... It's not that complex.

Hope this helps !




 2 comments
 
Hi Rajesh. Thanks for the reply. I have already written the DAL based on the patterns used in the design pattern framework. I started the DAL over a year ago, around the time when Linq-to-SQL was kind of being dropped by MS and they started to focus on EF. I rolled my own due to previous painful experience with strongly typed data sets and decided I wanted to stay away from GUI based data designers like those used in Linq-to-SQL and EF (although EF supports code first approach now). The issue I have now is that the abstract factory that is used to instantiate the Data Access Objects is very large as there is a property per data access object. Also, with each new DB table that we model, we have to also update the abstract factory which really breaks the open closed principle. --- Matt Fothergill  Mar 25, 2011
 
:).. I just got carried away as this was very close to my heart.. Yes, what you are thinking is a good idea (generic factory). The Dofactory implementation IDaoFactory is very limited and breaks the OCP as well (but I guess that was for representation purpose) as any new data access would result in changes to this interface. Additionally you will find the static DataAccess class also very limited as each new entry will demand changes to this class. In fact DataAccess and DaoFactory if made generic, then you can solve the problem which you have stated. Do share your findings if you are moving in the direction which you have highlighted. That will be useful to the community members as well. --- Rajesh Pillai  Mar 25, 2011