Creating an ORM in C# - Part 1

5/8/2009

Just as a warning, this is a long post. And before you groan and start running for the hills because someone mentioned building ANOTHER ORM (as if we need another one), note that this isn't meant to be something you would use in your own project. I've been working on this in my spare time as a side project to learn various features of C# 3.0 and .Net that I've never really gotten into before. And since this is a learning exercise, I decided to share my adventure with everyone else that's out there. Also keep in mind that this is not the best way to create an ORM. I'm certain that people who have successfully created one will read this and laugh at my poor attempt, but once again this is for learning purposes... Also, if you don't know what an ORM is, read this.

Anyway, I might as well tell you my motivation. I mean I could pick any project under the sun to learn some of these concepts, classes, etc. in the framework. So why did I pick an ORM? The main reason was that I've yet to find an ORM that works the way that I want it to. NHibernate is close (and I do like the Fluent version), but it's still not quite what I want. That's it really. I just want something where I don't have to design my objects around it and it plugs in without too much of an issue (oh and no XML or Attributes littering my business objects).

Anyway, I've divided the ORM into four sections that I'll need to create:

  1. Reflection - I need to figure out what properties exist in an object, etc. And like I said above, I don't want to use attributes or XML. That leaves me using reflection and writing a couple classes to help get the information that I need and store it for later use.
  2. SQL Builder - This will actually create the tables, create the queries, etc. In this setup, I'm only dealing with SQL Server, but I'm going to build it using a provider model so that could be swapped out.
  3. Cache - To be honest, calling a database is a bit slow sometimes. So I need to create a mechanism to cache the information. I'm designing this only for web sites, but once again I'm going to try to build it in such a way that it could be swapped out.
  4. Settings - I need an easy way to configure this thing. So I need something simple to store that information.

So really it's only 3 sections but I'm still going to count the settings... Anyway, in this post I'm going to talk about the reflection portion. And actually I'm not going to cover it completely in this post, just how to get the property information.

So I need some basic information from the properties of the business objects. Namely the name of the property, the base type, and the type of mapping that we want to use. So I'm using this class to hold that information

   1: public class Attribute
   2: {
   3:     public Attribute()
   4:     {
   5:     }
   6:  
   7:     private string _Name = "";
   8:     private Type _Type = null;
   9:     private AttributeType _AttributeType = AttributeType.ID;
  10:  
  11:     public string Name
  12:     {
  13:         get { return _Name; }
  14:         set { _Name = value; }
  15:     }
  16:  
  17:     public Type Type
  18:     {
  19:         get { return _Type; }
  20:         set { _Type = value; }
  21:     }
  22:  
  23:     public AttributeType AttributeType
  24:     {
  25:         get { return _AttributeType; }
  26:         set { _AttributeType = value; }
  27:     }
  28: }
  29:  
  30: public enum AttributeType
  31: {
  32:     ID = 0,
  33:     Reference
  34: }
Note that the attribute type defines only properties that are either the ID for the object or a reference (think simple types like string, int, etc. I'll add in classes, many to many mappings later). But so far this is pretty basic. On top of this, I'm not hard coding the business objects nor am I forcing them to inherit from an interface/base class. So I need a class so they can define the mapping with:

   1: public interface IAttributeMap
   2: {
   3:     List<Attribute> Properties { get; set; }
   4: }
   5:  
   6: public interface IClassMap<T>
   7: {
   8:     void ID(Expression<Func<T, object>> expression);
   9:     void Reference(Expression<Func<T, object>> expression);
  10: }
  11:  
  12: public class ClassMapping<T> : IClassMap<T>, IAttributeMap
  13: {
  14:     private void AddAttribute(Attribute Property, Expression<Func<T, object>> expression)
  15:     {
  16:         Property.Name = expression.Body.ToString();
  17:         string[] Splitter = { "." };
  18:         string[] SplitName = Property.Name.Split(Splitter, StringSplitOptions.None);
  19:         Property.Name = SplitName[SplitName.Length - 1];
  20:         Property.Type = expression.Body.Type;
  21:         Properties.Add(Property);
  22:     }
  23:  
  24:     #region IClassMap Members
  25:  
  26:     public void ID(Expression<Func<T, object>> expression)
  27:     {
  28:         Attribute _ID = new Attribute();
  29:         _ID.AttributeType = AttributeType.ID;
  30:         AddAttribute(_ID, expression);
  31:     }
  32:  
  33:     public void Reference(Expression<Func<T, object>> expression)
  34:     {
  35:         Attribute _ID = new Attribute();
  36:         _ID.AttributeType = AttributeType.Reference;
  37:         AddAttribute(_ID, expression);
  38:     }
  39:  
  40:     #endregion
  41:  
  42:     #region IAttributeMap Members
  43:  
  44:     private List<Attribute> _Properties = new List<Attribute>();
  45:  
  46:     public List<Attribute> Properties
  47:     {
  48:         get { return _Properties; }
  49:         set { _Properties = value; }
  50:     }
  51:  
  52:     #endregion
  53: }

Ok, now the code above contains something you may have not seen before. Namely the Expression<Func<T,object>> expression part. You see in C# 3.0, an operator was added called the lambda operator. The lambda operator is used to create lambda expressions. Lambda expressions are anonymous functions that can contain statements, etc. and can be used to create expression trees or delegates. The portion of that, that we care about is expression trees.

An expression tree, which was introduced along with Linq, allows for translating executable code into data allowing us to modify the code before executing it... To be honest, that doesn't sound all that useful but it means that we can do things like this:

   1: X=>X.PropertyName

And the property's information (such as name, type, etc.) would be available to us. And that's what we need, so that's what we're using. So how do we use the ClassMapping class?
   1: public class MyClassMap : ClassMapping<MyClass>
   2: {
   3:     public MyClassMap()
   4:     {
   5:         ID(x => x.ID);
   6:         Reference(x => x.TestProperty);
   7:     }
   8: }
   9:  
  10: public class MyClass
  11: {
  12:     public MyClass()
  13:     {
  14:     }
  15:  
  16:     public virtual int ID { get; set; }
  17:  
  18:     public virtual string TestProperty { get; set; }
  19: }

The code above will look familiar to you if you've used Fluent NHibernate (I'm using their technique for defining the mappings). But the business object is MyClass. MyClassMap is the mapping class and inherits from ClassMapping. The reason we made ClassMapping generic was so we could do this. You'll notice that both the ID and Reference functions take in T type as the first portion. This allows us to define an object of the type that we define (in the example above, MyClass), and call its properties (which will end up in the body portion of the expression and we can get our information from there).

So we have our very basic mapping, we have classes to pull and hold the information that we need so now we just need something to find all of our mappings.
   1: internal class ClassManager
   2: {
   3:     #region Constructor
   4:  
   5:     public ClassManager(Assembly Assembly)
   6:     {
   7:         LoadClasses(Assembly);
   8:     }
   9:  
  10:     #endregion
  11:  
  12:     #region Private Functions
  13:  
  14:     private void LoadClasses(Assembly BusinessObjectsAssembly)
  15:     {
  16:         Type[] Types=BusinessObjectsAssembly.GetTypes();
  17:         foreach (Type TempType in Types)
  18:         {
  19:             Type BaseType = TempType.BaseType;
  20:             if (BaseType != null && BaseType.FullName.StartsWith("ClassMapping"))
  21:             {
  22:                 Classes.Add(BaseType.GetGenericArguments()[0], new Class(TempType));
  23:             }
  24:         }
  25:     }
  26:  
  27:     #endregion
  28:  
  29:     #region Private Variables
  30:  
  31:     private Dictionary<Type, Class> Classes = new Dictionary<Type, Class>();
  32:  
  33:     #endregion
  34: }
  35:  
  36: internal class Class
  37: {
  38:  
  39:     public Class(Type ClassMapping)
  40:     {
  41:         IAttributeMap Item = (IAttributeMap)Activator.CreateInstance(ClassMapping);
  42:         foreach (Attribute Property in Item.Properties)
  43:         {
  44:             //Here is where we'll add our property overridding at a later time
  45:         }
  46:     }
  47: }

So there you go. Our ClassManager class uses reflection to find all classes that inherit from the ClassMapping class. In turn it creates a Class object (which will later override various properties and be used to create a derived type that we will use to actually store/load the information from the database). The Class object then creates an instance of the class mapping and can then get the information from it about the various properties.

So there's the beginning of my ORM. I'm certain that flaws will be found and things will change but this is what I have at the moment (actually I'm a bit further than this, but this is what I'm going to share for now). So take a look, leave feedback, and happy coding.



Comments

Qamar
July 02, 2010 5:51 AM

I like your article as I complete reading the first article. I am going to learn ORM. You have done a very nice job. Thank you very much for the efforts you have done and share with us.