
I have a SubSonic prototype that’s been sitting on my hard drive for a while – something I’ve been meaning to spruce up for a bit and release. As of right now I’m happy I didn’t – the code would be considered SubSonic’s and I’d rather it get pulled into a larger effort (wink wink, nudge nudge… bat over the head).
I massaged the interfaces I’ve been using and in this post I thought I’d lay it out for comment.
Functional Background
The idea is that you “plug in” the ActiveRecord “stuff” to your web app and use it as you see fit – with perhaps a default being offered from Phil and team (using one of the ORMs their baking up there…
:):). So imagine that, out of the box, in the Global.asax is a line like this:
Controller.SetActiveRecordEngine(new EFActiveRecordEngine());Yes yes I know. Settle down.
First Pass
To get all of this to work properly we need to define two interfaces – one that works the database, the other that describes the object. I’ve been sort of thinking a lot about this for a long time… can you tell?
Here’s a starter interface for IActiveRecord, with the goal of keeping it lean and simple:
public interface IActiveRecord { object Add(); int Update(); void Save(); void Delete(); void Destroy(); string KeyName(); string KeyValue(); string DescriptorName(); string DescriptorValue(); }
Aside from the typical CRUD stuff, there are 4 methods that allow you to do some groovy UI work here (Key/Descriptor stuff). With these specified we can hijack the HTMLHelpers to do our bidding – things like DropDowns and simpler tables. Heck we could even do Editor<T> if we wanted.
The next part is the engine – the thing that would do the query stuff:
public interface IActiveRecordEngine { T Get<T>(object key) where T : new(); T Get<T>(Func<T, bool> expression) where T : new(); IQueryable<T> All<T>() where T : new(); T Add<T>(T item) where T : new(); void AddMany<T>(IEnumerable<T> items) where T : new(); void Update<T>(T item) where T : new(); void UpdateMany<T>(IEnumerable<T> items) where T : new(); int Delete<T>(Func<T, bool> expression) where T : new(); int Destroy<T>(Func<T, bool> expression) where T : new(); }
The power of Linq means that we don’t need to define much beyond “All()” – aside from the CRUD stuff. This is our answer to “method missing” with Rails’ ActiveRecord. Well at least sort of.
Putting the Pieces Together
Under the hood the vendor who implements these interfaces would be responsible for allowing the developer to harness their particular ActiveRecordEngine to IActiveRecord – meaning that when object “Post” which implements “LinqToSqlActiveRecord” calls “Add()” then the underlying “LinqToSqlActiveRecordEngine” does the heavy lifting.
Your Thoughts Please – and Your Voice
Data access is a pain in the ass and something that we should really move beyond. If this interests you – heckle some people. Twitter it, blog it. Make yourselves heard. Phil is very much into this (it was our convo that sparked this whole thing) and let’s resolve this API so we can (if we so choose) all speak the same data access language when using ASP.NET.
Talk to me! If you want something like this – you need to speak up.
