Validation of Viewmodel containing nested domain objects

asp.net-mvc

Solution

You should create a correct ViewModel for your View.

The best approach imo is not to expose your domain entities to the view.

You should do a simple DTO flattening from your entities to your viewmodel.

A class like that

public class ProductViewModel
{
   public int ID { get; set; }
   [Required]
   public string Name { get; set; }
   public int CategoryId? { get; set; }
   public SelectList Categories { get; set; }
}

From your controller you map the product to your viewmodel

public ViewResult MyAction(int id)
{
   Product model = repository.Get(id);

   //check if not null etc. etc.

   var viewModel = new ProductViewModel();
   viewModel.Name = model.Name;
   viewModel.CategoryId = model.Category.Id;
   viewModel.Categories = new SelectList(categoriesRepo.GetAll(), "Id", "Name", viewModel.CategoryId)

   return View(viewModel);
}

Then in the action that respond to the post, you map back your viewModel to the product

[HttpPost]
public ViewResult MyAction(ProductViewModel viewModel)
{
   //do the inverse mapping and save the product
}

I hope you get the idea

Problem

I have the following 2 entities: ``` public class Product { [Key] public int ID { get; set; } [Required] public string Name { get; set; } public virtual Category Category { get; set; } } public class Category { [Key] public int ID { get; set; } [Required] public string Name { get; set; } public ICollection<Product> Products { get; set; } } ``` and a view model ``` public class ProductCreateOrEditViewModel { public Product Product { get; set; } public IEnumerable<Category> Categories { get; set; } } ``` The create view for Product uses this ViewModel. The category ID is set as follows in the view: ``` <div class="editor-field"> @Html.DropDownListFor(model => model.Product.Category.ID,new SelectList (Model.Categories,"ID","Name")) @Html.ValidationMessageFor(model => model.Product.Category.ID) </div> ``` When the form posts I get an instance of the view model with a product and the selected category object set but since the "Name" property of Category has a [Required] attribute the ModelState is not valid. As far as creating a Product goes I don't need or care for the "Name" property. How can I get model binding to work such that this is not reported as a ModelState error?

Original source