crayden
crayden

Reputation: 2270

Entity Framework Core Update Duplicating

When attempting to update an entity with a child entity collection, each member of the child collection is duplicated. Why are the child entities being duplicated when using the Update method in the controller?

This application uses ASP.NET Core 2.1 and Entity Framework Core, that connects to MS SQL Server LocalDB in Visual Studio 2017.

ParentEntity.cs

namespace MyProject.Models
{

    public enum EntityType { Type1, Type2, Type3}

    public class ParentEntity
    {
        public int ParentEntityID { get; set; }

        public string Text { get; set; }

        public EntityType EntityType { get; set; }

        public ICollection<ChildEntity> ChildEntities { get; set; }

    }
}

ChildEntity.cs

namespace MyProject.Models
{
    public class ChildEntity
    {
        public int ChildEntityID { get; set; }
        public string ChildEntityText { get; set; }

        public int ParentEntityId { get; set; }
        public ParentEntity ParentEntity { get; set; }
    }
}

EditEntity.cshtml

@model ParentEntity

<h1>Edit Entity</h1>
<form asp-controller="Entity" asp-action="Edit" method="post">
    <input type="hidden" asp-for="ParentEntityID" />
    <input type="hidden" asp-for="EntityType" />
    <label asp-for="Text"></label>
    <input asp-for="Text" class="form-control" />

    @{ int i = 1; var a = Model.ChildEntities.ToArray(); }
    @for(var c = 0; c < Model.ChildEntities.Count(); c++)
    {
        <label>Child Entity @i</label>
        <input name="ChildEntities[@c].ChildEntityText" value="@a[c].ChildEntityText" />
        i++;
    }

    <button type="submit">Save</button>
</form>

EntityController.cs

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, [Bind("ParentEntityID, Text, EntityType, ChildEntities")] ParentEntity pa)
{
    if (id != pa.ParentEntityId)
    {
        return NotFound();
    }

    if (ModelState.IsValid)
    {
        try
        {
            context.Update(pa);
            await context.SaveChangesAsync();
        }
        catch (DbUpdateConcurrencyException)
        {

        }
        return RedirectToAction("EditEntity");
    }
    return View(pa);
}

Upvotes: 4

Views: 1986

Answers (2)

crayden
crayden

Reputation: 2270

All that was required was to add to following to each row of the for loop in the view.

<input type="hidden" name="ChildEntities[@c].ChildEntityID" value="@a[c].ChildEntityText" class="form-control" />

Upvotes: 0

Ryan Bennett
Ryan Bennett

Reputation: 3432

First thing I would check is if the ChildEntityIds on the ChildEntities are actually set when they come in from the controller. If the ids are 0 EF will think they are new entities and do an insert.

If they do have ids set to non-zero ints, I would try do a loop over them and attach the entities so the context knows about them. Something like:

foreach(var child in pa.children){
    context.Attach(child);
}

await context.SaveChanges();

Upvotes: 2

Related Questions