I’ve been spending some time getting my head wrapped around the idea of MicroOrms lately. A lot of this has to do with some of the scalability/caching issues I’ve been having with NHibernate. Don’t get me wrong, I still love NHibernate, but it can be a bit of a beast when you are really trying to drive performance, there is a lot of overhead in there. Besides, my general rule has been a good ORM can handle 80-90% of your queries, and then performance tune out as needed. I’m at the performance tuning part now.
BTW: if you are using Entity Framework you are in the same boat.
So the question is, what to do with that last 10-20% that you need performance on? Previously I had gone straight to Ado.Net, or used my own FluentAdo project. But a few new projects have dropped in on the scene and it was time to take a look.
Let’s start off with some requirements:
- Don’t be a pain to setup.
- Don’t hork up my domain model (I have NHibernate for that). POCO preferred.
- Be able handle multiple result sets (something NHibernate does not do well)
- Preference executing raw sql, not an api.
- I don’t need:
- A custom query api for constructing sql.
- Change tracking
- Caching
- Lazy Loading
- Automatically loading child objects
- Basically, be simple, be light, be fast, don’t be another NHibernate.
Now the Contenders:
- Dapper
- Simple.Data
- Massive
Dapper
Dapper is my current favorite. I deals with POCO objects, setup is very simple, very little overhead and ceremony. That said, it is probably the rawest for dealing with sprocs. But for a bare metal way of loading domain objects, this guy is hard to beat.
Here is a sample query:
var customer = _connection.Query<Customer>(
"select * from dbo.Customers where CustomerId = @id",
new {id = 1})
.FirstOrDefault();
Basically, Dapper handles all of my requirements with ease. I almost forgot to mention, Dapper is compatible with .Net 4.0 and 3.5. That is a huge win for me. Plus, the guys on Stack Overflow are using it, which makes for an easy “sell” to my management team.
Simple.Data
- Simple.Data is also very interesting. It makes extensive use of .net 4.0 and the dynamic. Simple.Data is fairly ORM’ish, in that it seems to scan your database schema and dynamically add methods for retrieving data. But it still uses POCO classes so I am good with that.
Here is a sample query:
var db = Database.Open();
var customer = db.Customers.FindByCustomerId(1);
To get that to work I defined the customer class with a CustomerID…and that is it. Dapper came up with the FindByCustomerId part. It also adds stored procs as well, so if I have a sproc called “GetCustomers”, I can call:
db.GetCustomers()
It is just scary what is going on here. Granted there is a down-side to this system – albiet minor. There is a bit of overhead while Simple.Data scans your database schema and gets setup.
Verdict: I don’t mind Simple.Data, but the .Net 4.0 only part is a problem, plus it strays a bit into becoming a ORM – a bit too much API, but nothing obnoxious.
Massive
I should have known how this one would turn out ahead of time, but I really didn’t want to believe it. When I was young and foolish I was a SubSonic guy. Truth is, I read Rob Connery’s blog religiously. But I moved passed SubSonic and onto NHibernate and never looked back. Heck, I moved passed Active Record and onto Repository Pattern. (Since then I’ve moved on again to Query/Command Pattern, but another time for that).
First off, Massive horks up my domain model. Each entity has to inherit from DynamicModel. So before my model looked like this:
class Customer
{
public int CustomerId { get; set; }
public string Name { get; set; }
public string Address { get; set; }
}
Now, Massive-fied:
class Customer: DynamicModel
{
public Customer(): base("Default")
{
TableName = "Customers";
PrimaryKeyField = "CustomerId";
}
public int CustomerId { get; set; }
public string Name { get; set; }
public string Address { get; set; }
}
And that “Default” in there, that is the name of my connection string. Wonderful. Also, because my table names are plural, I have to specify the name of my table for them in EVERY SINGLE CLASS.
Now, how to query:
var tbl = new Customer();
var customer = tbl.Single(1);
Smack-dab, back to Active Record.
Also, I didn’t see anything on how to parse multiple result sets.
Go to Rob’s site and you will see more samples. Needless to say, it is off my list. Granted, Massive is still much less overhead than NHibernate and Entity framework, but there is too much API there for me, too much setup, I don’t get my POCOs, etc.
What about PetaPoco? http://www.toptensoftware.com/petapoco/
Nice article. I had the same problem and finally i use BlToolkit library : http://bltoolkit.net/
One of the choices you may need to make is whether you can support .net 4 – if you can’t you’re choices are really only Dapper or PetaPoco.
“select * from”I think this part is Dapper’s killer.
Just went through the same process. As of now we’re leaning to PetaPoco. Uses POCO’s and unlike Dapper the whole thing isn’t static.
Yeah this is a shame you left out PetaPoco.
It wasn’t that I deliberately left out PetaPoco…I just had not heard of that one before. Investigating now.
I also choose PetaPoco after reviewing it alongside each of these 3 micro-ORM’s. We’re enjoying using it, and utilize most of its features.
I’m actually quite surprised about your comments on NHibernate. I’ve had quite the opposite feeling. Gaining performance was much easier than other ORM (or non-ORMS) and didn’t hork my domain model.
” But I moved passed SubSonic and onto NHibernate and never looked back. Heck, I moved passed Active Record and onto Repository Pattern. (Since then I’ve moved on again to Query/Command Pattern, but another time for that)” Amen. It’s time we all move on from the Repository Pattern. A post on the topic would be most welcome.
Hi, have you looked at BLToolkit? It has some functionality you don’t need (caching and so on) but you could just skip it, such functionality is optional. And here is an example of how to load data from DB – http://bltoolkit.net/Doc.DbManagerVsAdo.ashx
I took a gander thru PetaPoco. I’m not a fan of Attribute driven development…mainly because I already have a ton of attributes for Asp.Net, Asp.Net MVC, and NUnit. Plus, I find attributes to be less discoverable. But PetaPoco did fix some things I did not like with Massive.
Again, I’m not looking for a replacement for my current ORM, more something to use when the ORM doesn’t work. PetaPoco seems to want to be an ORM replacement (like Massive and Simple.Data).
Anyway, that is my $.02 for right now.
I believe “Dapper came up with the FindByCustomerId part.” is meant to read “Simple.Data came up with the FindByCustomerId part.”
I’ve been playing around with PetaPoco, which syntactically is very similar to Dapper and very much like it.
Second that post request. My only complaint with SubSonic is a few missing features. Sadly enough, it seems development of the product is dead 🙁
Great post Chris. I’m interested in hearing more about Query/Command Pattern.
From Massive documentation …
“//you don’t have to specify the connection – Massive will use the first one it finds in your config”
Reading for comprehension is just as important as reading for speed …
That said, PetaPoco is great … and got all of its ideas from Conery’s SubSonic/Massive …
Of course we got more ideas about this microorms.. Really very interesting to read this one. We are expecting like this information from you.. thanks a lot..
outsourcing web developers | outsourcing joomla web development