views:

562

answers:

5

I have an application with my object types that inherit from a base class that contains the majority of properties for the application objects. All the object types are stored in one table in the database. The "ClassType" column determines what object type I cast the SqlDataReader row to.

Here is my current implementation:

SqlDataReader dr = SqlServerHelper.ExecuteReader("MyStoreProc", MySqlParmas);

if(dr.HasRows)
{
    while(dr.Read())
    {
        switch(dr["ClassType"].ToString())
        {
            case "ClassA":
                //cast sqldatareader a ClassA object
                ClassA a = new ClassFactory.CreateClassA(object p1, object p2);
            case "ClassB":
                //cast sqldatareader a ClassB object
                ClassB b = new ClassFactory.CreateClassB(object p1, object p2);
        //it continues for all objects with app....
        }
    }
}

dr.Close()

My question is is their a better implementation for this type of processing?

+4  A: 

I guess I would lean towards an Object-Relational Mapper for this. NHibernate is an example of an existing, free, mature ORM solution for the .NET platform.

Jim Burger
In the same vein: Linq to SQL maybe....
Terry Donaghe
Not sure why I got down voted for this answer, its a legitimate course of action is it not?
Jim Burger
Not sure why you did either. I upvoted both answers. In this case, he seems to have already rolled his objects, so theres not much that can be done.
FlySwat
Indeed, Oh well... Your reflection approach is an elegant alternative. +1 from me
Jim Burger
A: 

LINQ to SQL might be a legitimate option. However, It does not play very well with databases that are not properly constrained with Primary and Foreign keys. It will generate the class based on the tables.

Greg Ogle
+6  A: 

This approach is if you don't want to switch to a code generating ORM.

In your table of objects, include the fully qualified type name of the object.

Then, in you can do something like:

    private Dictionary<String, Type> _objectTypes = new Dictionary<String, Type>();

    public ObjectFactory()
    {
        // Preload the Object Types into a dictionary so we can look them up later
        foreach (Type type in typeof(ObjectFactory).Assembly.GetTypes())
        {
            if (type.IsSubclassOf(typeof(BaseEntity)))
            {
                _objectTypes[type.Name.ToLower()] = type;
            }
        }
    }

Now, with a mapper all preloaded, you can replace your code with:

    string objectName = dr["ClassType"].ToString().ToLower();
    Type objectType;

    if (_objectTypes.TryGetValue(objectName, out objectType))
    {
       return (BaseEntity)Activator.CreateInstance(objectType,reader);
    }

Pass the reader to the constructor of your object, so it can fully populate itself, that type of code doesn't belong in the factory.

FlySwat
I'd quibble with the passing of a reader to the ctor - but wouldn't mind a generic mapper from IDataReader fields to relection args. Otherwise, I'd much rather the IDataReader stuff stay in the DAL or ObjectFactory.
Mark Brackett
Why .ToLower() ?
configurator
Not really needed, but normalizes all the keys.
FlySwat
A: 

Thanks for all the feedback, but I do not want to implement a third party tool or new language because I do not have time right now to learn it right now.

@Jonathan Hollard:

My object module is current designed like this:

public class BaseClass
{
    public BaseClass() { }

    public object p1 { get; set;}

    public object p2 { get; set; }

    public virtual void ImplementLogic()  
    {
        //do some fun stuff....
    }
}

public class ClassA : BaseClass
{
    public ClassA { }

    public override void ImplementLogic()
    {
        //make it rain.....
    }
} 

public class ClassB : BaseClass
{
    public ClassB { }    

    public override void ImplementLogic()
    {
        //do some more fun stuff
    }
}

How would it work with this model?

Would I throw the first code sample in my BaseClassFactory constructor, because it would recognize all the classes that inherited from BaseClass?

Michael Kniskern
A: 

You could store the fully-qualified type name in your database, and then construct it with Activator.GetInstance. This would get rid of the ugly switch statement, but would call the type's constructor instead of a factory method. Will that do what you want?

Gabe Moothart