user1704029
user1704029

Reputation: 275

Update a many-to-many relation in Entity Framework Core

I am trying to update a many-to-many relation in a ASP.NET Core MVC controller using Entity Framework Core. I managed to get this working for adding to the relation, but not updating (leads to a duplicate key error, if I just open/save the entity).

How can I remove the relations from the database before updating/inserting new relations in an efficient way?

public async Task<IActionResult> Edit(int id, [Bind("Id,Name,SalesClerkIds")] Plant plant)
{
        if (id != plant.Id)
        {
            return NotFound();
        }

        if (ModelState.IsValid)
        {
            try
            {
                plant.SalesClerks = new List<PlantSalesClerk>();

                if (plant.SalesClerkIds != null)
                {
                    foreach (var scId in plant.SalesClerkIds)
                    {
                        plant.SalesClerks.Add(new PlantSalesClerk()
                        {
                            Plant = plant,
                            User = _context.Users.FirstOrDefault(u => u.Id == scId)
                        });
                    }
                }

                _context.Update(plant);

                await _context.SaveChangesAsync();
            }
            catch (DbUpdateConcurrencyException)
            {
                if (!PlantExists(plant.Id))
                {
                    return NotFound();
                }
                else
                {
                    throw;
                }
            }
            return RedirectToAction(nameof(Index));
        }

        return View(plant);
  }

Upvotes: 2

Views: 3419

Answers (1)

TanvirArjel
TanvirArjel

Reputation: 32059

Write your Edit post method as follows:

public async Task<IActionResult> Edit(int id, [Bind("Id,Name,SalesClerkIds")] Plant plant)
{
    if (id != plant.Id)
    {
        return NotFound();
    }

    if (ModelState.IsValid)
    {
        try
        {
            Plant plantToBeUpdated = await _context.Plants.Include(p => p.SalesClerks).FirstOrDefaultAsync(p => p.Id == id);

            if (plantToBeUpdated != null)
            {
                 plantToBeUpdated.SalesClerks.Clear(); // Here you have to clear the existing children before adding the new

                 if (plant.SalesClerkIds.Count > 0)
                 {
                      foreach (var scId in plant.SalesClerkIds)
                      {
                         plantToBeUpdated.SalesClerks.Add(new PlantSalesClerk()
                         {
                            PlantId = plantToBeUpdated.Id,
                            UserId = scId
                         });
                     }
                 }

                 plantToBeUpdated.Name = plant.Name;

                // Map other properties here if any

                _context.Plants.Update(plantToBeUpdated);

                await _context.SaveChangesAsync();
           }

        }
        catch (DbUpdateConcurrencyException)
        {
            if (!PlantExists(plant.Id))
            {
                return NotFound();
            }
            else
            {
                throw;
            }
        }
        return RedirectToAction(nameof(Index));
    }

    return View(plant);
}

Note: I didn't see your model classes and edit view. I have assumed everything based on your code. So there may needs to be some adjustment but this is the concept of updating model with children in EF core.

Upvotes: 3

Related Questions