Castle Active Record

I have recently gotten into databases at work. I HATE programming against databases. I have spent the majority of my career avoiding jobs where I need to program against them. I just don’t like doing it. I mean, they are great for persistence and retrieval, but I hate how muddy they make the code… all the CRUD (Create, Retrieve, Update and Delete) code that needs to be written… all the special queries… yuck.

Which is why in my current project (a re-architecture of an existing system) when it came time to include a database instead in place of the dreaded XML files, I found myself in a tough spot. I really like the active record pattern, so I implemented my business object persistence using that pattern.

While doing this, I came across an amazing open-source product called Castle ActiveRecord (part of the Castle Project). Coincidentally, I got to see a talk by Michael Eaton at Lansing Day of .NET a few weeks later. It is a simple framework that abstracts away all database programming. WOW! What could be better? It is amazingly simple to use and I barely touch the database. I don’t even need to create the database schema. Castle ActiveRecord does it all for me.

So I did what I often do when I want to learn a new technology… I signed up for a tech talk to my developer team on the topic. I gave an hour-long talk on the Active Record pattern and the Castle ActiveRecord framework. With it, I came up with a fully functional (albeit toy-like) demo project.

The project is a Recipe Box application. My business objects and database schema look like this:

They are freakishly similar. The beauty is that I never had to write the schema. ActiveRecord did it for me.

Here is the guts of my business object code:

   1: [ActiveRecord]
   2: public class Recipe : ActiveRecordBase<Recipe>
   3: {
   4:   [PrimaryKey]
   5:   public int Id { get; set; }
   6:  
   7:   [Property]
   8:   public string Title { get; set;}
   9:  
  10:   [Property]
  11:   public string Description { get; set; }
  12:  
  13:   [Property]
  14:   public string Author { get; set; }
  15:  
  16:   [HasMany(Inverse = true, Cascade = ManyRelationCascadeEnum.AllDeleteOrphan)]
  17:   public IList<Step> Steps { get; set; }
  18:  
  19:   [HasMany(Inverse = true, Cascade = ManyRelationCascadeEnum.AllDeleteOrphan)]
  20:   public IList<Quantity> Quantities { get; set; }
  21: }
  22:  
  23: [ActiveRecord]
  24: public class Step : ActiveRecordBase<Step>
  25: {
  26:   [PrimaryKey]
  27:   public int Id { get; set; }
  28:  
  29:   [Property]
  30:   public string Command { get; set; }
  31:  
  32:   [BelongsTo("RecipeId")]
  33:   public Recipe Recipe { get; set; }
  34: }
  35:  
  36: [ActiveRecord]
  37: public class Quantity : ActiveRecordBase<Quantity>
  38: {
  39:   [PrimaryKey]
  40:   public int Id { get; set; }
  41:  
  42:   [Property]
  43:   public double Value { get; set; }
  44:  
  45:   [Property]
  46:   public Units Units { get; set; }
  47:  
  48:   [BelongsTo("IngredientId")]
  49:   public Ingredient Ingredient { get; set; }
  50:  
  51:   [BelongsTo("RecipeId")]
  52:   public Recipe Recipe { get; set; }
  53: }
  54:  
  55: [ActiveRecord]
  56: public class Ingredient : ActiveRecordBase<Ingredient>
  57: {
  58:   [PrimaryKey]
  59:   int Id { get; set; }
  60:  
  61:   [Property]
  62:   public string Name { get; set; }
  63:  
  64:   [Property]
  65:   public string Description { get; set; }
  66: }

It is that simple (I left out constructors, ToString() and other logic for this post. I load it up and start programming against the objects:

Create:

   1: var ingredient = new Ingredient("Milk", "A drink made from mammals");
   2: ingredient.Save();

 

Retrieve:

   1: Ingredient.FindAll();

 

Update:

   1: ingredient.Description = "A white liquid";
   2: ingredient.Save();

 

Delete:

   1: ingredient.Description = "A white liquid";
   2: ingredient.Save();

 

It couldn’t be any easier, as far as I am concerned. Delete, Save, FindAll and many other methods like those were created for me when I inherited my objects from ActiveRecordBase. This gives me a ton more time to be coding my features, and forgetting about my persistence mechanism.

As much praise as I have given to ActiveRecord, there are some weaknesses. Here are the ones I can point out:

  • You have less control over your database
  • It is not as performant as direct SQL and stored procedures can be
  • You loose your one shot at inheritance. If your business objects already derive from something, you are out of luck
  • It cause an even bigger rift between Devs and DBAs
  • You are forced to write classes with strong dependencies with each other
  • You need to deploy at least 6 Dlls at 1.6 MB in size

Finally, I want to make a quick mention to Microsoft’s Entity Framework. It is supposed to do a lot of what Casltle ActiveRecord already does. It is currently in CTP, and I will probably play with it soon. Unfortunately, many in the development community have given it a vote of "No Confidence". I am not qualified to judge here, but I hope that when EF comes out later this year, the community is a bit more positive about it. We’ll see.

Leave a Reply