Thursday, April 21, 2011

Entity Framework POCO Proxies in Asp.Net MVC

As many of you already know, the asp.net MVC framework has the ability of creating a model instance each time an http post is executed. In the following picture you can see that the component that performs that task is the ModelBinder.


It is also true that the way in which Entity Framework implements "lazy load" on POCOs is replacing the real objects with proxies. So when the context returns an entity from the database, a proxy is returned instead of the real entity (for more information about EF proxies just follow this link).


But, what if the entity is not created by the context? How can the ModelBinder create a proxy instead of the real entity?

In order to do that, we need to call the Create method of the EF DbSet and it will create the proxy for us. The following snippet shows how:

var productProxy = modelContext.Products.Create();

Now let's put this behavior inside our own ModelBinder:

public class EntityModelBinder : DefaultModelBinder
{
    protected override object CreateModel(ControllerContext controllerContext,
                                          ModelBindingContext bindingContext, 
                                          Type modelType)
    {
        // Get the EF context using an IoC container
        var modelContext = DependencyResolver.Current.GetService<IModelContext>();

        var set = modelContext.Set(modelType);

        if (set != null)
            return set.Create(modelType);

        return base.CreateModel(controllerContext, bindingContext, modelType);
    }
}


Finally, we need to configure our new ModelBinder in the Application_Start (Global.asax).

public class MvcApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        ...
        ModelBinders.Binders.DefaultBinder = new EntityModelBinder();
    }
}

So now, we can use the lazy load feature inside our controllers:

public class ProductController : Controller
{
    [HttpPost]
    public ActionResult Edit(Product product)
    {
        modelContext.Entry(product).State = EntityState.Modified;

        // Use "lazy load" to get the Category object from the DB
        var threshold = product.Category.PriceThreshold;

        ...
    }
}

The source code of this sample can be downloaded from this link (MVC v3 + EF v4.1).

 

4 comments:

Clint Chapman said...

Sweet. Exactly what I was looking for. I've been having trouble get objects to validate with no lazy loading on my POCOs. I'm not sure why there isn't an easier way to switch this functionality on. Thanks a bunch!

Luiz Bicalho said...

Great post, that was almost what I wanted,i'm trying to load the referenced objects from the database, but in the create action
as I asked in this post

http://social.msdn.microsoft.com/Forums/en-US/adodotnetentityframework/thread/f11507bf-d5fa-4194-871e-1475f3e33d4a

Jorge Fioranelli said...

Hi Luiz,

I have answered your question in the MS forum.

I hope it helps.

Cheers

Jorge

Luiz Bicalho said...

Thanks, I answered again your post

I looked up your mvc ntier model, I had some idea to create a similar result as an generator to use in Mvc Scaffolding, and this is a big problem now