Tech
I wasn't entirely happy with my previous implementation of a generic LINQ-to-SQL ModelBinder. There's a bit of tier-jumping going on, it would be better if the ModelBinder interacted with some loosely-coupled Service Layer. Also, registering my custom ModelBinder in Global.asax messes up the functionality of UpdateModel and TryUpdateModel, both very important tools for handling form posting situations.
With this in mind, I've adapted the concept to apply more generally.
In my previous post, Assigning responsibility in ASP.NET MVC I discussed using ASP.NET MVC's ModelBinder framework to perform SELECT operations against the database. Using this technique, your Action methods (e.g. Products/Details/1) recieve a domain object (Product p) instead of an id (int id). This makes your Action methods more database agnostic, easier to unit test, and saves you repeating your database select inside every Action method that needs to convert an id into a domain object.
In this post, I describe an implementation of a generic ModelBinder to select domain objects from any Linq-to-SQL datacontext.
I've been working on a more generic implementation of Maarten Balliauw's Linq-to-SQL Model Binder. Maarten's implementation bothers me because it builds up a query as a string and uses MyDataContext.ExecuteQuery to get the result as a non-generic IEnumerable. I don't find this implementation particularly elegant, and in particular Maarten notes that as it stands his code is vulnerable to SQL Injection.
A similar post by Timothy Khouri (using ToString() to build up a base-64 representation of an object to pass between requests, and a matching ModelBuilder to re-build the object on the other side) was criticised on the grounds that "you wouldn't ever want any database interaction going on during the binding process".
This got me thinking a little bit about how responsibility is divided up in ASP.NET MVC.
Late last year, I finally got over my preconceptions and gave ASP.NET MVC a try. The result has been a massive u-turn in my opinion of the framework. Now that I've used it in a couple of projects (including porting Worlds Apart to the framework), let me share a few of my thoughts with you.
Last time, I examined one of the limitations of LINQ to SQL - the lack of automatic tools to cut out the junction table in a many-to-many relationship. I examined the reasons behind this limitation and concluded that providing automation for the simplest case ( foreach (Product p in order.Products) ) left us with two very important issues:
- We currently don't have a way of sending changes to the object model back to the database -
order.Products.Add( ...won't result in a new record being added to the junction table. - We need a way to access properties of the relationship beyond references to the two related entities (e.g. "Quantity" in the Order_Detail table relating Orders and Products).
In this article, I examine ways to solve these issues.
LINQ is a new component in .NET 3.5 that has a lot of .NET developers very excited. It provides a simple and flexible method of querying object-encapsulated data. The LINQ to SQL provider in particular has been getting a lot of attention since it can be used to query SQL Server databases using the same simple syntax that is used to query collections in memory - and furthermore can send updates made to the data back to the database. This feature, combined with very slick integration into Visual Studio 2008, provides a very strong motivation for developers to make the leap to .NET 3.5.
Unfortunatley, LINQ to SQL has a few limitations, the most obvious of which is the inability to directly handle the common representation of a many-to-many relationship. In this series, I look at the issue and some of the ways of circumventing it.