Question

Basically I want a view which contains an Owner's details. The Owner can have multiple types of Vehicle's (or none), which can be selected with a Checkbox:

The Index View

On submit, the database has to be updated, because next time the Owner is displayed in the View, the Owner must have the correct checkboxes checked.

I am unsure how to structure my EF Models, and not sure I am linking it correctly to get the result I want.

I do not want hard-code the Vehicle types as fields into the Owner object, because there are quiete a huge number of vehicles.

Can anyone point me in the right direction of how to link these models? Will I need two or three tables in the database?

This is what I have at the moment, but it is probably wrong. If you have an idea please stop reading now to avoid confusion. Any comments are welcome!

The Models :

public class Vehicle
{
    public int VehicleID { get; set; }
    public string Name { get; set; }
}

public class Owner
{
    public int OwnerID { get; set; }
    public string Name { get; set; }
    public virtual ICollection<OwnerVehicle> OwnerVehicles { get; set; }
}

public class OwnerVehicle
{
  public int OwnerVehicleID { get; set; }

  public bool Ticked { get; set; }
  //Not sure if this is needed, because ticked will always be true
  //I delete OwnerVehicle if not needed

  public int OwnerID { get; set; }
  public virtual Owner Owner { get; set; }

  public int VehicleID { get; set; }
  public virtual Vehicle  Vehicle { get; set; }
}

Controller :

public ActionResult Index()
    {
        //prepopulate Owner objects on the fly for this example, in my project it would fetched/created with EF into database
        Owner owner = getOwner();
        return View(owner); // we return the owner to view
    }

    public Owner getOwner()
    {
        //Create a owner
        Owner owner = new Owner() { OwnerID = 1, Name = "JACK" };

        //Create a list of vehicles
        List<Vehicle> Vehicles = new List<Vehicle>();
        Vehicles.Add(new Vehicle() { VehicleID = 1, Name = "I have a car"});
        Vehicles.Add(new Vehicle() {VehicleID = 1, Name = "I have a bike" });

        //the owner doesnt have any vehicles yet, therefor object OwnerVehicle is null at the moment

        return owner;
    }

    [HttpPost]
    public ActionResult Index(Owner owner)
    {   
        //at this point, the owner needs have his list of Vehicles linked, and written to database
        //
        //ToDO
        //return View();
    }

The View below wont compile, because I am lost.
Index.cshtml

    @model Owner
    @using (Html.BeginForm())
    {
          <div class="editor-field">
                @Html.EditorFor(model => model.OwnerVehicles)
            </div>
    }

EditorTemplates/OwnerVehicles.cshtml

    @model OwnerVehicle
    <div>
        @Html.CheckBoxFor(x => x.Ticked)
        @Html.LabelFor(x => x.TODO, Model.TODO)
        @Html.HiddenFor(x => x.TODO)
    </div>
Was it helpful?

Solution 2

CptRobby helped me to crawl the web even deeper, and found my question to be a duplicate of this one

Ciaran Bruen created a great tutorial which can be found here, and there is a downloadable solution on the left of the page.

It shows how to create the many to many relationship, the checkboxfor and updating the database.

OTHER TIPS

I would create an object that would help in presenting what you are trying to output. It would be in the "model", but wouldn't be mapped to the database in any way. It would look something like this:

public class VehicleHelper //or whatever you would like to call it...
{
  public Vehicle Vehicle { get; set; }
  public bool Ticked { get; set; }
}

Then your Owner would have a list of these VehicleHelpers like so:

public class Owner
{
  //include the properties you listed here...

  [NotMapped]
  public IEnumerable<VehicleHelper> VehicleHelpers { get; set; }
}

Then the Controller would populate the VehicleHelpers property as needed:

public ActionResult Edit(int id)
{
  MyContext db = new MyContext();
  Owner owner = db.Owners.FirstOrDefault(o => o.OwnerID == id);
  if (owner == null) thrown new Exception("Invalid Owner ID");
  owner.VehicleHelpers = db.Vehicles
    .Select(v => new VehicleHelper() { Vehicle = v, Ticket = false });
  foreach (Vehicle ownedVehicle in owner.OwnerVehicles.Select(ov => ov.Vehicle))
  {
    VehicleHelper helper = owner.VehicleHelpers
      .FirstOrDefault(vh => vh.Vehicle == ownedVehicle);
    if (helper == null) continue;
    helper.Ticked = true;
  }
  return View(owner);
}

[Note: This following part is where I'm not certain the exact syntax, conventions and such, because I'm just learning MVC and Razer myself, but it should be close. Feel free to edit or suggest edits. ;)]

Then you would have an editor template for the VehicleHelper, which would look something like this:

@model VehicleHelper
<div>
  @Html.CheckBoxFor(vh => vh.Ticked)
  @model.Vehicle.Name
  @Html.HiddenFor(vh => vh.Vehicle.VehicleID)
</div>

I hope that at least helps point you in the right direction. ;)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top