1

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>
tereško
  • 58,060
  • 25
  • 98
  • 150
David Smit
  • 829
  • 1
  • 13
  • 31

2 Answers2

2

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. ;)

CptRobby
  • 1,441
  • 15
  • 19
  • Thanks CptRobby! Thanks a lot for taking the time to read and answer the question, it is definitely working, I can see in the `HttpPost` that the `Owner` object contains the updated `VehicleHelper`. But I am sorry to ask this of you, but can you please help with the `HttpPost` when updating/deleting/adding of the new records to the database as well? Because the `VehicleHelper` is now separate from `OwnerVehicle`, I have to somehow map it back and update/delete on certain criteria. This is really frustrating and I wonder if you had an easy way of doing this? – David Smit Jul 09 '13 at 13:51
  • Hi @CptRobby, ignore my question in comments above for now, I am going to try and implement what they described in this downloadable project. Also has a checkbox. Will report back with results : http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/updating-related-data-with-the-entity-framework-in-an-asp-net-mvc-application – David Smit Jul 10 '13 at 10:43
  • Hi @CptRobby, I just want to say thanks again for helping me out, I was really frustrated after struggeling with it for a long time, and you came to the rescue! Do you mind if I mark my answer as correct, it contains update to database as well. If you want the points I can mark yours as correct as well, because yours is also working – David Smit Jul 10 '13 at 14:32
  • @David Smit - You're welcome to mark your answer as the accepted answer. I do have a few suggestions for improving it though that I might write up in a separate answer though. – CptRobby Jul 10 '13 at 17:01
  • 1
    @DavidSmit - One question I have is if you are interested in storing any additional information in the OwnerVehicle record. Some examples would be Mileage, PurchasePrice, or VIN, something that would not be applicable directly to either the Owner record or the Vehicle record. If you aren't going to have any other information in the OwnerVehicle record and the only thing it represents is that there is a connection between the two, then you can model a many-to-many relationship in EF without needing an OwnerVehicle class, and that make it easier to manage. – CptRobby Jul 10 '13 at 17:09
  • No I don't need any more info in the OwnerVehicle record, just them to be linked somehow. If I don't need the OwnerVehicle class, and it simplifies things that would be awesome. But surely I must somehow create the 'OwnerVehicles' table in the dabatase for the data to be saved? – David Smit Jul 11 '13 at 07:11
  • Ah you are right I should have done a "many to many ef mvc relationship" search in google. This answer looks like a good idea, I will try to implement : http://stackoverflow.com/questions/11531769/saving-many-to-many-relationship-data-on-mvc-create-view/11593957#11593957 – David Smit Jul 11 '13 at 07:15
  • 1
    Yeah, his answer is pretty much dead on. I would suggest reading his blog posts that he linked to though (especially the 3rd one) because he left some things out that are needed for updating existing records rather than just creating new ones. Good luck and let me know if you run into any more problems! ;) – CptRobby Jul 11 '13 at 13:44
0

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.

Community
  • 1
  • 1
David Smit
  • 829
  • 1
  • 13
  • 31