m1gs
m1gs

Reputation: 197

List the table values of a foreign key MVC

here is the class I am working on:

public class appointment
{
    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int appointment_id { get; set; }
    [DataType(DataType.MultilineText)]
    public string appointment_description { get; set; }
    public int student_id { get; set; }
    public virtual student student { get; set; }
    public int sched_id { get; set; }
    public virtual sched schedule { get; set; }
}

As you can see, one of my foreign keys is the "schedule".

here is my schedule class

public class sched
    {

        [Key]
        [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
        public int sched_id { get; set; }
        public string sched_day { get; set; }

        public TimeSpan sched_stime { get; set; }

        public TimeSpan sched_etime { get; set; }

        public int faculty_id { get; set; }

        public virtual faculty faculty { get; set; }
    }

I generated this in MVC 5 CRUD in create, this is the code in my view:

 <div class="col-md-10">
                @Html.DropDownList("sched_id", null, htmlAttributes: new { @class = "form-control" })
                @Html.ValidationMessageFor(model => model.sched_id, "", new { @class = "text-danger" })
            </div>

Here is my controller:

public ActionResult Book()
{
    return View();
}

[HttpPost]
public ActionResult Book(CS.Models.appointment appoint)
{
    if(ModelState.IsValid)
    {
        db.appointments.Add(appoint);
        db.SaveChanges();
    }
    return RedirectToAction("Booked", "Home");
}

but there was an error:

There is no ViewData item of type 'IEnumerable<SelectListItem>'

All I want to do is display the data of the sched class (from the database) which a foreign key from the class I am working on in a dropdownlist.

Is there a way I can do that? I am very new in MVC.

Upvotes: 2

Views: 2542

Answers (1)

Dmytro
Dmytro

Reputation: 17196

There are several things wrong here:

First of all - @Html.DropDownList("sched_id", null, this line of code. When you build your select list, if I understood correctly, of schedules then, instead of null, you have to provide the list of items you want to build your DropDownList from. This is the IEnumerable<SelectListItem> mentioned in the error which can not be null. Which leads us to the second issue.

You're using you business models directly in your view which is not kinda right. Because, in your particular case, you have to initialize your list so you must have the collection of ALL schedules to select from. Which is not the part of your business model. Instead of CS.Models.appointment you have to use a view model which will contain all properties you have fill to post your appointment and two additional members:

IEnumerable<SelectListItem> ScheduleSelectListItems { get; set; };
int SelectedScheduleId { get; set; }

Populate the list of SelectListItems you will have in your get action. Something like this:

public class AppointmentViewModel
{
    public int appointment_id { get; set; }
    public string appointment_description { get; set; }    
    public StudentViewModel student { get; set; }
    public IEnumerable<SelectListItem> ScheduleSelectListItems { get; set; };
    public int SelectedScheduleId { get; set; }
}


public ActionResult Book()
{
    var items = db.schedules.ToList().Select(sched => new SelectListItem { Text = string.Format("{0} - {1}", sched.sched_stime, sched.sched_etime), Value = sched.Id });

    var model = new AppointmentViewModel { ScheduleSelectListItems = items };
    return View(model);
}

And do not forget to update your view to use AppointmentViewModel as @model.

<div class="col-md-10">
@Html.DropDownList("SelectedScheduleId", Model.ScheduleSelectListItems, htmlAttributes: new { @class = "form-control" })
@Html.ValidationMessageFor(model => model.SelectedScheduleId, "", new { @class = "text-danger" })
</div>

Which leads us to the third issue. Since you're no using any view models - you don't have any mapping (copying all fields from view model to actual business model which will be saved to the database). To simplify the task and avoid using external tools like AutoMapper for this purpose at the moment you can do the mapping manually. In some external class, for example, to make controller actions code as clean as possible.

public static class Extensions
{
    public static appointment ToAppointment(this AppointmentViewModel appointmentViewModel)
    {
        var result = new appointment
        {
             appointment_id = appointmentViewModel.appointment_id;
             // Copy all other properties here
             ...
        };
        return result;        
    }
}

[HttpPost]
public ActionResult Book(AppointmentViewModel appoint)
{
    if(ModelState.IsValid)
    {
        // Map you view model to the model
        var appointment = appoint.ToAppointment();

        // Get you selected schedul from the database using either foreighn key either navigation property
        var schedule = db.schedules.FirstOrDefault(sched => sched.Id == appoint.SelectedScheduleId);
        appointment.schedule = schedule;

        db.appointments.Add(appointment);
        db.SaveChanges();
    }
    return RedirectToAction("Booked", "Home");
}

Upvotes: 1

Related Questions