0

I am currently working on an update view for a model I have in ASP.NET MVC. The model is called Document and has child Links:

[Association(ThisKey = "AssetID", OtherKey = "AssetID")]
private EntitySet<Link> links = new EntitySet<Link>();
public IQueryable<Link> Links
{
    get { return links.AsQueryable().Select(l => l); }
    set 
    {
        links.Assign(value);
    }
}

I've got my strongly-typed update form rendering the model correctly (including all links) through a EditorTemplate for link and then use of Html.EditorFor(model => model.links). This successfully grabs and displays all links for the given Document.

When the form is submitted and I use Fiddler to see the data that is posted back, for each link it contains all the fields like Links[0].Id = 12323, Links[0].DisplayOrder = 1, etc.

The problem though is when I put a breakpoint on the controller method that I am posting to, and examine the Document object that is being posted, its Links collection is empty. I have tried adding additional binding properties to my controller as described here, but with no luck--the argument passed to the parameter is always null.

Any ideas why my model does not contain these links when I try to update it? Thanks

Community
  • 1
  • 1
Andrew Keller
  • 3,198
  • 5
  • 36
  • 51

1 Answers1

2

The reason this happens is simple: it is because you are not using view models which is what I would recommend. Let me elaborate. In your views you are directly using your data models which are not POCO objects and using Linq to SQL pollutes them even further with those EntitySet<T> stuff which are specific to your DAL and just look at the setter of the Links property: links.Assign(value);. Don't expect from the default model binder to be that intelligent. A view should never work with things like EntitySet<T> (this is an implementation specific detail).

So start by defining a POCO view model which expresses the intent of the view which is editing links:

public class MyViewModel
{
    // As you can see the sole responsibility of the view is to 
    // show a list of input fields for each link to be edited.
    // TODO: you could also have a view model for Link the same way 
    public IEnumerable<Link> { get; set; }
}

Now strongly type your view to this view model instead of the model. Also the POST action takes the view model as argument. You could use AutoMapper to perform the conversion between your model and view models.

In fact every time I see a question on SO tagged with both asp.net-mvc and linq-to-sql (or entity framework) I know that there's something wrong. Those two things should be completely separate and have nothing in common. You DAL should be abstracted away in a repository so that MVC never knows about the data access technology you are using.

The normal scenario would be this:

The controller action receives a view model as argument, validates it, maps this view model to some model and invokes some method from the repository passing the model. The repository returns another model which in turn is converted into a view model and passed to the view to be rendered (of course this is the complete scenario, there are cases where you could skip steps for simple actions).

Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928