SubSonic to View and back again...adventures of a POCO

For a project I'm currently working on, we're going to be implementing the repository pattern to provide a layer of abstraction and separation between our Model/Domain and the data access logic.  One of the things we're being mindful of is that we don't want to go toting around objects that include logic on how to get information into or out of the database.  Essentially, while SubSonic generates a great little set of DAL objects using either ActiveRecord or the Repository Pattern, we don't want to be cluing in our Model or our Controller on how to deal with data persistance and querying.  That shall be the responsiblity of one or more IRepository interfaces, likely generated by domain object (IPersonRepository, IProjectRepository, IFooRepository, IBarRepository, etc.).  So what might an IPersonRepository hand up into the Model layer of our application for manipulation by the controller?..POCOs (Plain old CLR Objects or Plain Old C# Objects).  Essentially, Dave came up with a MyGeneration template to generate a set of POCOs for our model that are simply lightweight classes with an overloaded constructor and a bunch of properties that hold values for DAL objects including contained collections of other POCOs that participate in data schema relationships (a Person POCO might contain a collection of one to many Address POCOs for example).  We want no methods or business logic on our POCOs; their job is to get data values from one place to another.


The .NET ones...not these guys!
Now, the SubSonic API provides some nice convenience functions to get typed POCOs back from a SubSonic query of the database.  Please see Rob's post here for more info on SqlQuery::ExecuteSingle and SqlQuery::ExecuteTypedList methods.  These methods essentially use a little bit of System.Reflection to look for common property names between a SubSonic type and a POCO type and instantiate POCOs and copy over the values of matching properties.  That's great for getting data out of the database, through the repository, and up to the MVC gang for manipulation and rendering in the view.  The issue becomes, how does one get a POCO back into a SubSonic Generated DAL type to do an update or an insert into the database.  Consider the following scenario: A user interacts with the view to update Person information (marital status change, addition of a new address and setting of the address as primary, etc.).  All of this information gets rolled into a POCO and shipped back to the IPersonRepository boundary where we would like to shove it back into the database.  But how?  What we have is a Person POCO object and our IPersonRepository will use SubSonic generated DAL objects to update the database.  See, while SubSonic is billed as an OR/M tool, there really isn't any "M" for moving from the View, back through the Repository to the Database. At first glance we're left with having to write code that manually converts a POCO to a SubSonic type inside the repository...not particularly attractive for every single update and insert that might be performed on a medium to large sized schema.   Since the best programmers steal what they can't borrow, I built upon what Rob with his BuildTypedResult<T>() method on the SqlQuery class in SubSonic.  The result is a RepositoryHelper class that sits in the project containing my concrete IRepository implementation classes...this class will likely grow and evolve as the project moves forward (think deep get and deep save tools that I'm still noodling on).  You can grab a copy of the initial class here.(I need to get some online storage so you'll have to copy/paste from the *.doc right now). The only interesting method at present is the BuildRepositoryTypeFromPoco<T> method which will automagically convert from your POCO type to the corresponding SubSonic type without you having to individually loop over properties or write "Object dot" syntax 50 times in an overloaded constructor. So let's look at our theoretical IPersonRepository::Save method might look like using the helper function: /// <summary> /// Saves the project. /// </summary> /// <param name="pocoPi">The poco pi.</param> public void SaveProject(Project_Investigation pocoPi) { //Convert single POCO to object array Object[] pocos = new Object[1]; pocos[0] = pocoPi as Object; //Call utility class to hand back a SubSonic type so we can do a Save IList<ProjectInvestigation> pi =RepositoryUtility. BuildRepositoryTypeFromPoco<ProjectInvestigation>(pocos, true); //Hacky work around. When new object is created after stateless call, //all columns shown as dirty. This is needed to prevent PK column from //getting torched after update. pi[0].DirtyColumns.Remove(pi[0].GetSchema().PrimaryKey); //Use subsonic DAL version of the object to save pi[0].Save(); } Beats writing code to manually map all properties don't it? Note that you will need to tell the helper function whether your POCOs correct underscores like your SubSonic objects or not. Hope to post some more tidbits as these helper functions evolve.