Populate DropDownList in ASP.NET MVC from database table using Entity Framework 6 and ViewModel

asp.net-mvc dropdownlistfor entity-framework razor viewmodel

Question

I have been scratching my head for a whole night on an issue I can do quickly using ajax/jquery and stored procedures. I want to

1) Populate a drop down list from values obtained from a database table using Entity Framework and view model. I DO NOT WANT TO USE VIEWBAG OR VIEWDATA. Any help appreciated.

2) How can I generate a Create View using the View Model with the all the default fields ? The scaffholding works on a model but not on a view model ?

MY MODELS

public class Employee
{
    public int EmployeeID { get; set; }
    public string Name { get; set; }
    public string Gender { get; set; }
    public string City { get; set; }
    public string Level { get; set; }
    public int DepartmentId { get; set; }
}

public class Grade
{
    public int ID { get; set; }
    public string Level { get; set; }
}

View Model

public class GradeSelectListViewModel
{

    public Employee Employee { get; set; }
    public IEnumerable<SelectListItem> Grades { get; set; }
    public GradeSelectListViewModel(Employee employee, IEnumerable grades)
    {
        Employee = employee;
        Grades = new SelectList(grades, "Grade", "Name", employee.Level);
    }
}

MY CONTEXT CLASS

public class EmployeeContext : DbContext
{
    public DbSet<Employee> Employees { get; set; }
    public DbSet<Department> Departments { get; set; }
    public DbSet<Grade> Grades { get; set; }
}

MY CONTROLLER

public ActionResult Edit (int? id)
{
    using (var db = new EmployeeContext())
    {
        var model = new GradeSelectListViewModel(db.Employees.Find(id), db.Grades);
        //model.Employee = db.Employees.Single(x => x.EmployeeID == id);
        model.Grades = db.Grades.ToList().Select(x => new SelectListItem
        {
            Value = x.ID.ToString(),
            Text = x.Level
        });
        return View(model);
    }
}

MY RAZOR PAGE CSHTML

@model MVCDemo.ViewModels.GradeSelectListViewModel
....
@using (Html.BeginForm()) 
{
    @Html.AntiForgeryToken()
    ....
    @Html.DropDownListFor(x => Model.Employee.Level,
        new SelectList(Model.Grades, "ID", "Level"),
        "Select Level")
    ....
    <input type="submit" value="Create" class="btn btn-default" />
}
1
4
3/2/2017 8:00:08 AM

Accepted Answer

The main issue is that in the view you have new SelectList(Model.Grades, "ID", "Level") but Grades is IEnumerable<SelectListItem> and SelectListItem does not contain properties named ID and Level.

However there are a a few other issues with your code. First a view model should not contain a data model, and instead your view model should be

public class GradeSelectListViewModel
{
    public int? ID { get; set; } // make this ID so you do not need an input for it
    public string Name { get; set; }
    .... // other properties of Employee that your editing
    [Required(ErrorMessage = "..")]
    public int? Level { get; set; } // make value types nullable to protect against under-posting attacks
    public IEnumerable<SelectListItem> Grades { get; set; }
}

and add display and validation attributes as required. Note that I deleted the constructor (you don't seem to be using it, but if you did, then you also need to include a parameter-less constructor, otherwise an exception will be thrown when submitting to the POST method. I also assume that Level should be typeof int since you binding to the int ID property of Grade.

The the code in your GET method should be

Employee employee = db.Employees.Find(id);
var model = new GradeSelectListViewModel()
{
    ID = employee.EmployeeID,
    Name = employee.Name,
    Level = employee.Level, // convert to int?
    ....
    Grades = db.Grades.Select(x => new SelectListItem
    {
        Value = x.ID.ToString(),
        Text = x.Level
    })
};
return View(model);

and in the view

 @Html.DropDownListFor(x => Model.Level, Model.Grades, "Select Level")

Note also that in the POST method, your need to reassign the SelectList if you return the view because ModelState is invalid.

7
3/2/2017 10:10:45 AM

Popular Answer

You can use the following approach that populates three DropDownListFor at the same View:

ViewModel:

public class GroupViewModel
{  
    public IEnumerable<SelectListItem> Schedules { get; set; }
    public int ScheduleId { get; set; }

    public IEnumerable<SelectListItem> Labs { get; set; }
    public int LabId { get; set; }

    public IEnumerable<SelectListItem> Terms { get; set; } 
    public int TermId { get; set; }
}



Controller:

public ActionResult Create()
{
    //Populate DropDownList binding values
    var model = new GroupViewModel
    {
        //Preselect the Lab with id 2
        //LabId = 2,

        Labs = repository.Labs.Select(c => new SelectListItem
        {
            Value = c.Id.ToString(),
            Text = c.Name
        }),
        Terms = repository.Terms.Select(c => new SelectListItem
        {
            Value = c.Id.ToString(),
            Text = c.Name
        }),
        Schedules = repository.Schedules.Select(c => new SelectListItem
        {
            Value = c.Id.ToString(),
            Text = c.Name
        })
    };
    return View("Create", model);
}



View:

@Html.DropDownListFor(m => m.LabId, new SelectList(Model.Labs, "Value", "Text"), 
    "Select", new { @class = "selectpicker" })

@Html.DropDownListFor(m => m.ScheduleId, new SelectList(Model.Schedules, "Value", "Text"), 
    "Select", new { @class = "selectpicker" })

@Html.DropDownListFor(m => m.TermId, new SelectList(Model.Terms, "Value", "Text"), 
    "Select", new { @class = "selectpicker" })

Hope this helps...



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