1

Details:

  • ASP.Net MVC 5
  • .Net 4.5
  • MVVM
  • Entity Framework 6 Code First

I have ViewModels with complex properties on them. I have read about how I can use the BindAttribute to include or exclude properties for model bidning and got basic properties working with this.

However one thing I cannot find is how to control the binding of child properties within a collection property. For example I have the following

[Bind(Include = "Model.Id, Model.Positions.StartDate")]
public class ProjectViewModel
{
    public Project Model {get;set;}

    public ProjectViewModel(Project project)
        : base(project)
    {
          Model = project;
    }

    public ProjectViewModel()
    {

    }

}

A Project has a list of Positions:

public class Project : BaseEntity
{
    .
    .
    .

    public virtual IList<Position> Positions
    {
        get;
        set;
    }

}

And a Position has a start and end date:

public class Position : BaseEntity
{
    [SensibleDateTime]
    public DateTime StartDate { get; set; }

    [SensibleDateTime]
    public DateTime EndDate { get; set; }

    [Required]
    [ForeignKey("Project")]
    public Int64 ProjectID { get; set; }
    public virtual Project Project { get; set; }
}

I have a screen using the Project View Model with a grid of positions where the user is allowed to change the start and end date of those positions. I do not want to allow them to let them amend any other properties of the Position including by manipulating the request / post to the server.

I am writing my own custom model binder which inherits from the DefaultModelBinder which gets the original entity out the database. I just want to bind permitted bound fields on top to get these new values and all the original values will already exist.

I am aware I could get the original entity out the database inside the controller instead and map the bound start and end date onto the entity manually. I want to avoid this if possible and make the controller code as simple as possible as this will be a very common task. Additionally it seems like using standard MVC mechanisms would be the preferred approach.

I have tried the following bind statement on the Project View Model:

[Bind(Include = "Model.Positions.StartDate")]

None of the new values are bound including the start date of the positions. If I write a simple include for a property directly on the Project View Model or Model it works.

How do you write a Bind attribute statement that refers to a property within an entity collection?

Alan Macdonald
  • 1,872
  • 20
  • 36
  • You claim to be using a view model, but in fact your not. A view model contains only those properties you need in the view for display/editing and using a view model means you should never use the `[Bind]` attribute. You also claim you want to use the _"standard MVC mechanisms"_ which means you post view model, get the corresponding data model from the database and map the view model properties to the data model, then save the data model. Its not clear why you would want to avoid this. –  May 19 '15 at 01:04
  • @StephenMuecke Do you have a reference for the definition of a view model only containing the properties required in a view and absoltely nothing more? I have found exposing the model object to be a good compromise between productiivty and idealism about the pattern. I am writing a custom framework on top of MVC that handles our companies common tasks with as little code as possible in order to gain buy in from the developers used to our previous development platform. As explained this will be a common scenario and I want to make the controller code as easy to write and as small as possible – Alan Macdonald May 19 '15 at 11:02
  • There are hundreds of articles on the web explaining what a view model is in MVC - suggest you start with [this one](http://stackoverflow.com/questions/11064316/what-is-viewmodel-in-mvc). If you use tools such as [automapper](https://github.com/AutoMapper/AutoMapper) mean that mapping to and from view models is usually only one line of code, but of course you can always create your own helper methods to do the mapping to minimize the controller code –  May 19 '15 at 11:10
  • @StephenMuecke Yes I've read some of them. There are competing defintions on the page you linked alone. Granted the accepted answer states a VM should only contain the properties a view requires but many others are not this strict. If I have needs for specific properties for my view that are outside of my normal domain model I add properties to the VM and not the model. It's simply that the reverse case is not true, my view will automatically have access to the full model. ViewModel / controller code is minimal and simple as possible with no replication. I am aware automapper exists.. – Alan Macdonald May 19 '15 at 11:21

1 Answers1

0

I can't say for sure as I never use the Bind attribute, but the dot syntax should work. However, I'm reasonably sure that Bind focuses on the posted name, not the actual model property. In other words, you would most likely need to do something like "Positions[0].StartDate,Positions[1].StartDate,...".

In general, it's far better to just use view models to only include the properties you want to be editable.

Chris Pratt
  • 232,153
  • 36
  • 385
  • 444
  • Unfortunately this doesn't work even for the first position. It wouldn't have been a solution anyway since there will be n positions where n is not known in advance. – Alan Macdonald May 19 '15 at 13:55