Reputation: 1453
So I'm having difficulties with my 'flight order management system' in MVC 5.
What I'm trying to do is to add an existing passenger to a flight using the requirements given in a specific questions.
this is my code:
Flight:
public class Flight
{
public int Id { get; set; }
public string Depart { get; set; }
public string Destination { get; set; }
public DateTime TakeOffTime { get; set; }
public DateTime LandingTime { get; set; }
public virtual List<Passenger> Passengers { get; set; }
}
Passenger:
public class Passagenger
{
public int Id { get; set; }
public string Name { get; set; }
public int Gender { get; set; }
[Range(0,130)]
public int Age { get; set; }
}
We need to make a redirect at the index page (showing all flights) and a redirect link with the details page, where an admin can add a passenger to a flight. He does this by using a dropdown of the existing passengers and a 'add' button.
However, after the 'add' button is pushed, a table needs to pop up showing all passenger on the flight that it redirected to.
How would I approach this? I have already the following controller:
public ActionResult Details()
{
ViewBag.PassengerId = new SelectList(db.Passengers, "Id", "Name");
return View();
}
[HttpPost]
public ActionResult Details(int passengerId)
{
Passenger = db.Passegers.Find(passengerId);
if(ModelState.IsValid)
{
//add the passenger to the selected flight that it redirected to, but how to get the id of it now?
}
//Get all passengers of the flight, how to get the id?
List<Passagier> Passagiers = db.Passagiers.ToList();
return View(Passagiers);
}
My details view:
@using (Html.BeginForm("Details", "Home", FormMethod.Post))
{
@Html.DropDownList("passengerId", (SelectList)ViewBag.PassengersId);
<input type="submit" value="Add" />
}
I can't use anything that the related answers are giving me (viewModel, ienumerable,...) hence why I'm asking this.
How would I be able to pass the current route id of the page (flightID) and the passengersID to the controllers action? What would be a good approach to this?
I am nearly there I think because the redirects work and so does my dropdown list showing all the passengers.
Upvotes: 1
Views: 2966
Reputation: 239290
First, any requirements that prohibit good design should be fought against. Project owners pay developers because they do not have the requisite skills, themselves. It is your job as a developer to educate the project owner when there are requirements that do not make sense. If the project owner insists on doing something fundamentally wrong, in spite of your protests, then that's a sign to you to drop them like a hot rock. They will only be a source of problems for you. Don't be afraid to fire clients. There's plenty of fish in the sea, but a bad client will be an anchor around your neck.
That said, you may just be misunderstanding the requirements. While there's places where you can use List<T>
and probably even should use List<T>
, your database-persisted entity is not one of them. It must be ICollection<T>
. Period. A property of List<T>
will not be persisted by Entity Framework.
That's where view models come in, as your view model can and should use List<T>
, and then you can map that back and forth to the ICollection<T>
on your entity. Again, if the requirements prohibit the use of view models, then your client either is uninformed or stupid. Your duty is to make sure they are informed, and if it turns out they're just stupid, then drop them.
Next, whenever you have a list of something you're posting to, you need to use ListBoxFor
, rather than DropDownListFor
. The latter only allows a single selection, but here you'll need to persist multiple passengers. On your view model, you should have a property like:
public List<int> SelectedPassengerIds { get; set; }
And, then one to hold your passenger options:
public IEnumerable<SelectListItem> PassengerOptions { get; set; }
In your action, you will map the Flight
entity to your view model as normal, but for your Passengers
collection you would do:
model.SelectedPassengerIds = flight.Passengers.Select(m => m.Id).ToList();
Then, set PassengerOptions
:
model.PassengerOptions = db.Passengers.Select(m => new SelectListItem { Value = m.Id.ToString(), Text = m.Name });
Finally, in your view, you'll have:
@Html.ListBoxFor(m => m.SelectedPassengerIds, Model.PassengerOptions)
On post, you need to map on the appropriate posted values from your view model back on to your Flight
entity. For your Passengers
collection, you will do:
// Remove deselected passengers
flight.Passengers.Where(m => !model.SelectedPassengerIds.Contains(m.Id)).ToList()
.ForEach(m => flight.Passengers.Remove(m));
// Add newly selected passengers
var newPassengerIds = model.SelectedPassengerIds.Except(flight.Passengers.Select(m => m.Id));
db.Passengers.Where(m => newPassengerIds.Contains(m.Id)).ToList()
.ForEach(m => flight.Passengers.Add(m));
Upvotes: 3