Search code examples
asp.net-core-mvcmodel-binding

Bind embedded type when form is submitted


I have created 2 types, Car and Engine

public class Car
{
    public Guid Id { get; set; }
    [...]
    public virtual Engine Engine { get; set; }
}

public class Engine
{
    public int Capacity { get; set; }
    public EngineType EngineType { get; set; }
    public Aspiration Aspiration { get; set; }
    public double OilSumpCapacity { get; set; }
}

I've setup relation between them:

        modelBuilder.Entity<Car>(e =>
        {
            e.OwnsOne(e => e.Engine);
            e.HasMany(e => e.Analyses).WithOne(re => re.Car).HasForeignKey(e => e.CarId);
        });

Scaffolded Create.csthml view doesn't have props that come from Engine

    <form asp-action="Create">
        <div asp-validation-summary="ModelOnly" class="text-danger"></div>
        <div class="form-group">
            <label asp-for="OwnerName" class="control-label"></label>
            <input asp-for="OwnerName" class="form-control" />
            <span asp-validation-for="OwnerName" class="text-danger"></span>
        </div>
        [...]  
        <div class="form-group">
            <input type="submit" value="Create" class="btn btn-primary" />
        </div>
    </form>

and the controller

    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> Create([Bind("Id,OwnerName,Make,Model,RegistrationNumber,Vin")] Car car)
   

doesn't expect them.

How should I modify controller and view to also take Engine props into consideration?


Solution

  • Since the Engine is a complex model,and yo want to bind it,you can try to remove Bind attribute:

    [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> Create(Car car)
    

    And then you need to add inputs into view to bind the properties of Engine:

    <form asp-action="Create">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <div class="form-group">
                <label asp-for="OwnerName" class="control-label"></label>
                <input asp-for="OwnerName" class="form-control" />
                <span asp-validation-for="OwnerName" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Engine.Capacity" class="control-label"></label>
                <input asp-for="Engine.Capacity" class="form-control" />
                <span asp-validation-for="Engine.Capacity" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Engine.OilSumpCapacity" class="control-label"></label>
                <input asp-for="Engine.OilSumpCapacity" class="form-control" />
                <span asp-validation-for="Engine.OilSumpCapacity" class="text-danger"></span>
            </div>
            [...]  
            <div class="form-group">
                <input type="submit" value="Create" class="btn btn-primary" />
            </div>
        </form>
    

    If you want to bind EngineType and Aspiration,you can try to add inputs with asp-for="Engine.EngineType.xxx" and asp-for="Engine.Aspiration.xxx".