In a previous post, I outlined the generics-based Repository model I built for DevEvents. There are two additional pieces of extensibility to the model that I left out for the sake of clarity. The first one, and the one I’ll cover in this post, is LINQ to SQL model binding.
During the initial development of the DevEvents framework, I was using MVC model binding for forms and entities:
public ActionResult Create(FormCollection form)
{
var org = new Organization();
try
{
UpdateModel(org, form);
Unfortunately, from time to time I would receive a stack overflow exception when calling UpdateModel. This is because LINQ to SQL entities contain references as properties to related entities, and the model binding would iterate recursively through them, forever.
Fortunately, UpdateModel contains a generic overload that helps to solve this problem:
protected internal void UpdateModel<TModel>(TModel model) where TModel : class;
For TModel, I can specify an interface which contains properties for the fields to bind. I have 60 tables though, and I didn’t want to manually create interfaces for each of them, so I set about with a T4 template to auto-create the interfaces based on my LINQ to SQL model. The generated code lives in the same namespace as my model, and contains a base, empty interface:
public interface IFormBindable { }
Then, I iterate through the DBML XML and create an interface that implements IFormBindable for each table. Finally, I iterate through the columns, and create properties for each column that is a primitive type.
public interface IPresentationFormBindable : IFormBindable
{
System.String Title { get; set; }
System.String Abstract { get; set; }
...
}
In order to make my model entities bindable, I apply these custom interfaces to their respective types in model partial classes, such as:
public partial class Presentation : IPresentationFormBindable
Finally, I can call UpdateModel for a presentation as follows, and only the properties specified on the IFormBindable interface will be bound.
public ActionResult AddPresentation(string id, FormCollection form)
{
...
Presentation presentation = _presentationRepository.GetPresentationByPresentationID(id);
UpdateModel<IPresentationFormBindable>(presentation, form);
...
The second item I left out of the generic repository post for clarity was validation, which I plan to discuss in an upcoming post.
Hope this helps!