A Data Layer framework is like a game system, you swear it's the best until something better comes out. When I choose a DAL framework to work with, its for an extended period of time. It has to be easy to setup, easy to work with, be robust, and have a future. I have to admit that I haven't worked on huge sites that have millions of visitors, most of my sites are smallish with 100's of users at a time tops so performance isn't really an issue for me. I'm more concerned with how fast I can build things. I want to have a requirement and push it out the door the fastest way possible.
Anyhoo, Subsonic looks to be filling those roles, for the most part. dOOdads did the above really well, but lets compare the two on HOW easy and pain free they are. Caveat: This is in no way a tutorial, so my explainations below are not exact.
How easy is it to setup?
dOOdads
You first include the given project in your own solution. You then need to choose which database you're building towards, select the files to "compile", and then include the MyGeneration_2005.dll in your PL, BLL, and DAL. You then use the MyGeneration tool (freeware, works in tandem with dOOdads) to generate DAL classes, and then the SPROCs those classes will use to perform information CRUD. The MyGeneration tool is pretty nice, if I need to make changes to the generated code, it's pretty straight forward, and took about and hour to get used to.
With dOOdads you have the additional step of generating the SPROCs and then adding those to your database. Since Subsonic doesn't use SPROCs (it can if you want it to), this second step is absent.
SubSonic
Since I have a Web Application Project, SubSonic is harder to setup than dOOdads. I want namespaces on my generated objects, plus I want to run the code generation from my own project. Ripping this from the given SubSonic package was a pain. I couldn't find any documentation, but I went through and figured out how to add namespaces, and plunked in my project's directory in the given textbox. With each new version that comes out, I'm sure my changes will be removed so I'll have to re-add them each time. Blech.
The generator also requests a path, so each time you bring up the BatchClassGenerator page you have to look up the directory you're sending files to. MyGeneration's tool remembers my "last generated to" path so I don't have to type it in. The other downfall of having the generator "in project" is that my solution must compile, otherwise I can't run my project in "Debug" mode and therefore run the generator. I can't "View in browser" if I have administrative rights (or give ASPNET or Network Service write perms on my directory) and hit "Yes" in the continue box to actually bring up the page when VS encounters errors.
Notably, Subsonic seems more built for Web Site Projects than WAPs. It would seem that the only setup you need to do with WSPs is copy the DLL and put a build provider file in your App_Code. Almost makes me want to switch to it...almost.
Winner: dOOdads by just a little. If there was a "build provider" for WAP and code generation was handled in an external tool (like MyGeneration perhaps?) Subsonic would win hands down. If you have a WSP, this is a no brainer, use Subsonic and never touch generation again.
Code Comparision
I like to abstract my code in a business or controller layer (most of the time combining them, so lets call it Biz). dOOdads generates abstract classes which the Biz layer inherits. Mostly these are left blank, and then from your PL you manipulate them. In Subsonic you are given partial classes, which I have placed in my DAL in a "generated" folder. You can create "extentions" to these classes by place other like named partial classes in the directory if you wish. This way makes you use more of a Controller, BLL, and DAL approach, except the BLL is in the partial classes in your DAL.
The two different frameworks also have radically different patterns of access. Subsonic uses the ActiveRecord pattern while dOOdads uses collections for everything. That means if you get a single record it's the same as if you get a group of records. In Subsonic there is a difference, you can either get a single record, or use the collection object to get a collection of objects. I'm sure there are performance benefits to either way, but I've never really tested either method as nothing in either has ever run "slowly". Mind you, I don't have millions of users pounding my websites, if you do, do your own testing :)
Now lets take a look at some code. Here's a look at code doing the same thing, the first is from dOOdads, and the second is from SubSonic. I like to create static classes that return the data I need, so these examples will be from that standpoint.
Returning some records with a Where statement:
dOOdads:
Tip t = new Tip();
t.Where.CategoryID.Value = categoryID;
t.Where.CategoryID.Operator = WhereParameter.Operand.Equal;
t.Query.AddOrderBy(ColumnNames.ModifiedOn, WhereParameter.Dir.DESC);
if (t.Query.Load())
return t;
else
return new Tip();
SubSonic:
return new TipCollection().Where(Data.Tip.Columns.CategoryId, categoryID).OrderByAsc(Data.Tip.Columns.Title).Load();
8 lines down to one. You also get an IEnumerable strongly type collection of Tip objects. Nice. I do wish I could still inherit the Data object so I don't have to specify Data.Tip.Columns.CategoryId, just Columns.CategoryId but I'm just nit picking.
Returning a single record:
dOOdads:
Tip t = new Tip();
if(t.LoadByPrimaryKey(tipId))
return t;
SubSonic:
return new Data.Tip(tipId);
Another one liner. The one-liners in subsonic make me wonder about even using a Controller type class for these types of operations. I mean...one line here, or one line on the PL? Make no difference that I can see.
More complex of a query:
In this one SubSonic code comes first, with dOOdads after placed with corresponding calls (I commented out the dOOdads code)
Query q = Data.Tip.CreateQuery();
/*
Tip t = new Tip();
*/
q.Top = topAmount.ToString();
q.OrderBy = OrderBy.Desc(Data.Tip.Columns.CreatedOn);
/*
t.Query.Top = topAmount;
t.Query.AddOrderBy(ColumnNames.ModifiedOn, WhereParameter.Dir.DESC);
*/
q.AddWhere(Data.Tip.Columns.TipType, latestType);
/*
t.Where.TipType.Value = latestType;
t.Where.TipType.Operator = WhereParameter.Operand.Equal;
*/
if (categoryID != Category.Empty)
{
q.AddWhere(Data.Tip.Columns.CategoryId, categoryID);
/*
t.Where.CategoryID.Value = categoryID;
t.Where.CategoryID.Operator = WhereParameter.Operand.Equal;
*/
}
TipCollection tc = new TipCollection();
tc.Load(Data.Tip.FetchByQuery(q));
return tc;
/*
if (t.Query.Load())
return t;
else
return new Tip();
*/
The only advantage SubSonic seems to have in the extended query department is the Where statements are condensed into one line. Still you get that enumerable collection. In dOOdads you have to "do...while" loop your way through each record. Not entirely a bad thing, but since SubSonic is "newer" it uses Generics and thus feels much more natural when coding something along those lines.
Transaction, deletions, and the like between dOOdads and SubSonic are pretty much the same. SubSonic scores again with slightly shorter code. dOOdads could catch up with some contructor changes, but that could be a problem as we'll later see in my post.
Winner: SubSonic
Robustness
dOOdads hasn't failed me in the year or so of using it. I haven't felt like I needed to "hack" anything together to get things accomplished. SubSonic is still maturing yet so far I've only seen one really weak area - data deletions. You are able to Delete (Data warehouse style of setting Deleted column to true) or Destroy using a static method, but this doesn't allow you to delete from entire tables or anything outside the range of deleting where you have the primary key (AKA single record). I've seen other requests for this so I know I'm not alone.
If you want to stay away from View and SPROCs you probably won't like either as you can't do complex joins within the frameworks, but this has really never bothered me. I like to use the strength of each tool I have at my disposal, and I like to accomplish things on the data side as quickly as possible, mainly because I hate dealing with data.
While I would give the nod to dOOdads there's one thing that it really lacks...
Winner: dOOdads, for now
Future Development
dOOdads development seems dead, or at the very least dormant. It seems like the dOOdads creators went off and created EntitySpaces, which is similar to dOOdads, but isn't freeware. I understand their decision, but I like using tools that are free, and I can potentially contribute or change to fit my needs.
SubSonic's development seems very much alive. In fact, every time I check the recent check-ins page, I see that there are multiple builds being pushed out (by really smart people too) daily. That means there are tons of things happening, and other people believe in supporting the "cause". The release schedules seem pretty much on-time and things are looking up for the project. It makes me want to even contribute (although I can't figure out how to even get started doing so).
Winner: SubSonic
The Winner
Subsonic comes out on top, and I'm committed to using it in at least the next few projects I put out. The biggest category from above for me is future development. Since it seems to be alive and well within the SubSonic project, SubSonic wins. The issues that I have with it will most likely be solved soon, as their release schedules are on time and there are lots of features being added daily. Their forums are pretty responsive and I can't wait to see if I can jump in to help develop some things as I have a few ideas on how to improve some things.