1

Scenario:

I am implementing Asp.Net MVC project with Entity Framework. I have following entities:

class Employee{
   public int Id{get;set;}
   [Required]
   public string Name{get;set;}
}

class Department{
   public int Id{get;set;}
   public string DepartmentName{get; set;}
   public virtual Employee manager{get; set;}
}

Now, I have to create new department that will have a manager from the list of employees in database. For this, view and controller actions are:

@Html.EditorFor(model => model.DepartmentName)
@Html.DropDownListFor(model => model.manager.Id, new SelectList(ViewBag.Managers, "Id", "Name"))


public class DepartmentController: Controller{
    private MyDatabaseContext db = new MyDatabaseContext();

    [HttpGet]
    public ActionResult Create(){
        ViewBag.Managers = db.Employees.ToList();
        return View();
    }

    [HttpPost]
    public ActionResult Create(Department d){
       if(ModelState.IsValid){
          d.manager = db.Employees.Find(d.manager.Id);
          db.Departments.Add(d);
          db.SaveChanges();
          return RedirectToAction("Index");
       }
       else{
         //error response.
         //Error encounters as d.manager.Name field would be null.
       }
    }
}

Problem:

When running above program, I cannot create new Department's object, as the ModelState.IsValid is always false. The reason for this is that the navigation property manager has field Name, which would be null when submitting the form. As Name is required field, this would be listed as error.

Question:

How can I overcome the error due to null in field of navigation property? Or, is there other ways to implement this code so that I will get rid of this error?

Notes:

Please make note that I don't want to create different ViewModel merely useful for creating the Department object. I would prefer following DRY principle. Further, I don't want to create different field (something like, managerId) which would be foreign key to Employees table because I don't want the database associations taken care on the object oriented models. It's always cleaner to retrieve manager through department.manager, rather than reading manager object from entity framework by passing the department.managerId [Key] field.

Thank you.

  • 1
    As always, use a view model (it is the only realistic way to resolve your issue). It is not breaking the DRY principal.Every view, especially those for editing should have its own view model. Refer also [What is ViewModel in MVC?](http://stackoverflow.com/questions/11064316/what-is-viewmodel-in-mvc). And that view model should also contain an `IEnumerable ManagerList` so that you avoid using `ViewBag` and get strong typed binding. –  May 27 '16 at 22:57
  • I implemented a ViewModel in the way @StephenMuecke explained. This solution worked fine and the architecture and code also looks clean. However, still I have one question in my mind. In Spring MVC, we can put `@Valid` annotation for the navigation property, to make the framework to validate the navigation property as well. If we don't put `@Valid` annotation, then the framework doesn't perform validation, and we don't get any error. Do you know any such annotation/feature in Asp.Net MVC? – Bikash Bishwokarma May 28 '16 at 04:10

2 Answers2

3

Please make note that I don't want to create different ViewModel merely useful for creating the Department object. I would prefer following DRY principle.

Using a view model in this case is not a violation of the DRY principle. A view model represents a different concept (i.e. the data that your view requires). That is an entirely different thing to the data your database table (domain model) requires. If your view model and domain model happen to have the same properties when you initially implement them, that is entirely coincidental.

The DRY principle is about making sure you don't repeat the same concept in multiple places.

Using a view model is absolutely the correct approach, specifically, in your case, because it allows the validation requirements of your data access layer to vary independently of the validation requirements of your UI layer. By reusing your domain model in your UI, you lose the flexibility to do this, and you'll constantly run into the same issue you're describing.

John H
  • 14,422
  • 4
  • 41
  • 74
1

You need this

public int EmployeeId {get;set;} 

on Department.

User123
  • 549
  • 1
  • 11
  • 24
  • Yes, this approach works fine to overcome the error. However, let us figure out if there are other ways too to solve the problem, without modifying the models/entities. I mean, from perspective of domain model design, I am not comfortable adding database related fields in model. I prefer letting the entity framework take care of this. – Bikash Bishwokarma May 27 '16 at 21:52