Rich
Rich

Reputation: 4992

View Scaffolding for Second foreign key isn't correct

I'm creating a simple 3 model MVC 5.2.3 example in Visual Studio with Entity framework version 6.1.3.

I have a Vehicle which has a 1 to many relationship with Contract and Mileage has a 1 to many relationship with Contract also.

Contract has 2 foreign keys, one for Vehicle and one for Mileage. I've added some data annotations to specify keys and foreign keys which according to what I've read should be unnecessary as I've stuck to the expected naming convention.

In the Contract view the first foreign key which is Vehicle has a populated dropdown with the actual vehicles in it, which is correct. The problem is the second foreign key, the Mileage, has a dropdown loaded with the Mileage IDs and not the actual mileages.

Any help on this would be greatly appreciated. Code below.

Razor view:

@model RRSMVCTest5.Models.Contract

@{
    ViewBag.Title = "Create";
}

<h2>Create</h2>


@using (Html.BeginForm()) 
{
    @Html.AntiForgeryToken()

    <div class="form-horizontal">
        <h4>Contract</h4>
        <hr />
        @Html.ValidationSummary(true, "", new { @class = "text-danger" })
        <div class="form-group">
            @Html.LabelFor(model => model.VehicleId, "VehicleId", htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.DropDownList("VehicleId", null, htmlAttributes: new { @class = "form-control" })
                @Html.ValidationMessageFor(model => model.VehicleId, "", new { @class = "text-danger" })
            </div>
        </div>

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

        <div class="form-group">
            @Html.LabelFor(model => model.InitialPayment, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.InitialPayment, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.InitialPayment, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.MonthlyPayment, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.MonthlyPayment, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.MonthlyPayment, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Create" class="btn btn-default" />
            </div>
        </div>
    </div>
}

<div>
    @Html.ActionLink("Back to List", "Index")
</div>

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

View models:

public class Contract
{
    //[Key]
    public int Id { get; set; }        
    public int VehicleId { get; set; }

    [ForeignKey("VehicleId")]
    virtual public Vehicle Vehicle { get; set; }        
    public int MileageId { get; set; }

    [ForeignKey("MileageId")]
    virtual public Mileage Mileage { get; set;}

    public double InitialPayment { get; set; }
    public double MonthlyPayment { get; set; }
}

public class Vehicle
{
    public Vehicle()
    {
        Contracts = new List<Contract>();
    }
    [Key]
    public int VehicleId { get; set; }
    public string  Name { get; set; }
    public virtual ICollection<Contract> Contracts { get; set; }               
}

public class Mileage
{
    public Mileage()
    {
        Contracts=new List<Contract>();
    }
    [Key]
    public int MileageId { get; set; }
    public int AnnualMileage { get; set; }
    public virtual ICollection<Contract> Contracts { get; set; }
}

Curiously when I change the data type of 'AnnualMileage' from int to string the dropdown gets loaded with the 'AnnualMileage' property as required. Does any one know of any annotation that can be used in the model to express which field should be chosen for display? A decision is being made by the scaffolding generator that would be useful to have control over.

Upvotes: 0

Views: 379

Answers (1)

David Ferenczy Rogožan
David Ferenczy Rogožan

Reputation: 25431

That's because the Vehicle model contains the Name property, but the Mileage doesn't, so the Razor helper DropDownList doesn't know what should be displayed as a text in the case of the Mileage and displays the IDs instead.

So you have two possibilities:

  • add the Name property to the Mileage model
  • tell the DropDownList helper what property to use for dropdown's text

I would choose the second option:

@Html.DropDownList("DropDownId", Model.Select(item => new SelectListItem
{
    Value = item.MileageId.ToString(),
    Text = item.AnnualMileage.ToString()
}))

Upvotes: 1

Related Questions