Ayende @ Rahien

Refunds available at head office

Moving away from the Active Record model

Fowler defines Active Record as:

An object that wraps a row in a database table or view, encapsulates the database access, and adds domain logic on that data.

Note that I am talking about the Active Record pattern and not a particular Active Record implementation.

A typical Active Record class will look like this:

image

By design, AR entities suffer from one major problem, they violate SRP, since the class is now responsible for its own persistence and for the business operations that relates to it. But that is an acceptable decision in many cases, because it leads to code that is much simpler to understand.

In most cases, that is.

The problem with AR is that it also treat each individual entity independently. In other words, its usage encourage code like this:

var person = Person.FindBy("Id", 1);
person.Name = "Oren";
person.Save();

This is a very procedural way of going about things, but more importantly, it is a way that focus on work done on a single entity.

When I compare the abilities of the Active Record style to the abilities of a modern ORM, there is really nothing that can compare. Things like automatic change tracking or batching writes to the database are part of the package with an ORM.

The sort of applications we write today aren’t touching a single row in the database, we tend to work with entities (especially root aggregates) with operations that can touch many rows. Writing those sort of applications using Active Record leads to complications, precisely because the pattern is meant to simplify data access. The problem is that our data access needs aren’t so simple anymore.

Active Record can still be useful for very simple scenarios, but I think that a major drive behind it was that it was so easy to implement compared to a more full featured solution. Since we don’t need to implement a full featured solution (it comes for free with your ORM of choice), that isn’t really a factor anymore. Using a full blown ORM is likely to be easier and simpler.

Comments

Christophe Vanfleteren
09/10/2010 09:21 AM by
Christophe Vanfleteren

My feelings exactly.

The kind of use cases I'm working with would be complicated as hell in an Active record pattern, and would make for some very ugly code.

Using a full ORM (Hibernate in our case) really alleviates all of that.

Colin Ramsay
09/10/2010 09:24 AM by
Colin Ramsay

The implementation of Active Record which Rails uses is a good example of this; the Arel relational algebra allows composition of queries in a pretty elegant way. They've extended the AR pattern out into something much more appropriate for advanced scenarios.

Daniel
09/10/2010 09:36 AM by
Daniel

Oh noes!

I just come to the moment where I have a very good knowledge of Castle AR + NHibernate ICriteria to use them succesfully and efficiently in my projects and now you say that AR is not good anymore? :))

Ayende Rahien
09/10/2010 09:39 AM by
Ayende Rahien

Daniel,

Make a distinction between the Active Record pattern and the Castle.ActiveRecord project.

Alex Simkin
09/10/2010 11:57 AM by
Alex Simkin

So Castle.ActiveRecord is still good?

Jason Meckley
09/10/2010 12:22 PM by
Jason Meckley

@Alex

Active Record, both pattern and implementation are good. Oren is working in a context where the ActiveRecord pattern inhibits simplicity, rather than enhances it.

Like Oren said, the implementation of AR (Castle) and concepts of AR are 2 distinct things. Castle AR uses NH to implement the AR pattern.

You also need to consider the context/application you are designing. True DDD only applies to small percentage of projects where the AR pattern doesn't make sense. There is still a large market/code base for simpler AR designs. After all MS is still making forms over data frameworks like lightswitch :)

Oren's view makes sense for the context in which he works.

Justin
09/10/2010 06:17 PM by
Justin

Help me understand how you compare a pattern (Active Record) directly to a generic term for a tool (ORM)?

Active record is a pattern that an ORM can implement.

NHibernate is a specific ORM that instead implements a repository pattern.

Castle is a ORM that implements the Active record pattern, it uses Nhibernate and and therefore the repository pattern internally, but that is an implementation detail, like using a relational database for a key value store.

Criticizing the Active record pattern also criticizes any implementation of that pattern, including Castle, how can you make the distinction? You are criticizing the pattern as a whole not just one implementation right?

Ayende Rahien
09/11/2010 12:29 PM by
Ayende Rahien

Justin,

Castle ActiveRecord offers you several choices, you can use it with a Unit of Work or AR.

Dmitry
09/11/2010 04:04 PM by
Dmitry

I do not think the Active Record pattern implies that you cannot have nested graphs, batching or transactions that span over multiple operations.

It means that a class represents a table and an object represents a row. Persistence operations do not have to be used on a row-per-row basis except for simpler cases. And there could be a query language as well or an ability to materialize graphs from an SQL query.

Dathan
09/13/2010 03:22 PM by
Dathan

@Dmitry,

It depends - the schema implied by an Active Record pattern doesn't preclude more advanced features. But the definition given at the start of the blog post - "An object that wraps a row in a database table or view, encapsulates the database access, and adds domain logic on that data." - does. You're working off of a different understanding of the pattern than the one described by Ayende - in the version of the pattern he's described, persistence operations only exist in single-row flavors. Once you start talking about ActiveRecord implementations that support more sophisticated optimizations, many of his criticisms no longer apply.

Justin
09/14/2010 05:38 PM by
Justin

So what your saying is Castle Active Record is ok so long as you don't use the Active Record?

I would argue that UOW and AR are not mutually exclusive. UOW is a at higher level of abstraction and categorized by Fowler as a behavioral pattern. AR and Data Mapper(Repository) are categorized as architectural patterns that sit lower in the stack.

A UOW manager can call the AR persistence methods or repository methods and still function logically the same.

Ayende Rahien
09/14/2010 09:50 PM by
Ayende Rahien

No,

I am saying that when deciding to use AR pattern, you should consider your actual use case scenario.

Comments have been closed on this topic.