ASP.net MVC4 Multiselect ListBox with Many-to-Many relationship

asp.net-mvc-4 data-binding entity-framework razor

Question

I'm new to ASP.net, MVC4 and EF and having trouble making the leap from relatively simple samples to something (only slightly) more complex. I have simplified my model for the question here so consider the following. Forgive me if I have some of the terminology incorrect.

I have an Employee object and a Division object. An employee can be in many divisions and a division can have many employees.

public class Employee
{
    public int EmployeeId { get; set; }
    public String FirstName { get; set; }
    public String LastName { get; set; }

    public virtual ICollection<Division> Divisions { get; set; }
}

public class Division
{
    public int DivisionId { get; set; }
    public String DivisionName { get; set; }

    public virtual ICollection<Employee> Employees { get; set; }
}

I have these mapped in the context file via the following:

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {

        modelBuilder.Entity<Employee>()
                .HasMany(e => e.Divisions)
                .WithMany(d => d.Employees)
                .Map(m =>
                {
                    m.ToTable("EmployeesDivisionsId");
                    m.MapLeftKey("EmployeeId");
                    m.MapRightKey("DivisionId");
                });      
    }

For my View Controller I have the following. I have used a ViewBag (what a name) for many to one relationships and they have worked fine, so I'm trying to modify that to work with the many to many here:

    public ActionResult Index()
    {
        return View(db.Employees).ToList());
    }

    //
    // GET: /Employees/Details/5

    public ActionResult Details(int id = 0)
    {
        Employee employee = db.Employees.Find(id);
        if (employee == null)
        {
            return HttpNotFound();
        }
        return View(employee);
    }

    //
    // GET: /Employees/Create

    public ActionResult Create()
    {
        ViewBag.Divisions = new MultiSelectList(db.Divisions, "DivisionId", "DivisionName");

        return View();
    }

    //
    // POST: /Employees/Create

    [HttpPost]
    public ActionResult Create(Employee employee)
    {
        ViewBag.Divisions = new MultiSelectList(db.Divisions, "DivisionId", "DivisionName");

        if (ModelState.IsValid)
        {
            db.Employees.Add(employee);
            db.SaveChanges();
            return RedirectToAction("Index");
        }

        return View(employee);
    }

Finally in the Edit View I have the following code. Again for a many to one relationship, a simple DropDownList works fine with the ViewBag in the controller, and with this many to many multiselect/ListBox method the 'Divisions' show up in the view, however when the Save button is hit, the validation of '1, 2' is not valid is displayed.

    <div class="editor-label">
        @Html.LabelFor(model => model.Divisions)
    </div>
    <div class="editor-field">
        @Html.ListBox("Divisions")
        @Html.ValidationMessageFor(model => model.Divisions)
    </div>

So as I understand it, the list of 'Divisions' are being grabbed properly from the database and selected correctly in the view but when saving to the database the association through the mapped relationship isn't being made.

So my questions are: How do I make this work so when I save, the correct 'Divisions' are saved to the Employee?

Also, I've heard people don't like using ViewBags, is there a (better?) alternate way?

1
4
10/10/2012 3:38:43 AM

Popular Answer

This answer maybe a bit late. However, here's one or two things that might be helpful to others finding this question.

You are using ListBox() instead of ListBoxFor() so the data isn't being automatically bound to your model. So in your controller you need:

[HttpPost]
public ActionResult Create(Employee employee, string[] Divisions)
{
    // iterate through Divisions and apply to your model
    ...
}
0
11/9/2012 7:54:34 AM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow