R4VANG3R
R4VANG3R

Reputation: 415

Update, create or delete EF Core

I have an API where I want to be able to do a PUT request where I post a Plan with an array of Blocks. Right now, it automatically adds new Block entries and updates existing entries, but it doesn't delete entries if they're missing in the post.

These are the models:

public class Plan
{
    public int Id { get; set; }
    public string Name { get; set; }

    public ICollection<Block> Blocks { get; set; }
}

public class Block
{
    public int Id { get; set; }
    public string Name { get; set; }

    public int PlanId { get; set; }
    public Plan Plan { get; set; }
}

And the controller action:

[HttpPut]
public ActionResult Update(Plan plan)
{
    if (plan?.Id == null) return BadRequest();

    var plans = _context.Plans.Count(p => p.Id == plan.Id);
    if (plans != 1) return NotFound();

    _context.Update(plan);

    _context.SaveChanges();

    return NoContent();
}

How would I go about implementing this? Is there a setting in EF to enable this?

I'm looking for a generic solution as there will be more collections and models which require the same functionality. I don't want to have to program this for every controller / action.

I'm using Entity Framework Core on .net core 2.2

Upvotes: 0

Views: 331

Answers (2)

Wijitha
Wijitha

Reputation: 1389

Following solution is much cleaner.

[HttpPut]
public ActionResult Update(Plan plan)
{
    if (plan?.Id == null) return BadRequest();

    var oldPlan = _context.Plans
     .Where(p => p.Id == plan.Id)
     .Include(p => p.Blocks)
     .FirstOrDefault();

    if (oldPlan == null) return NotFound(); 

    oldPlan.Name = plan.Name;
    oldPlan.Blocks = plan.Blocks; //This will wipe out all the existing blocks and replace with new ones. If blocked are null it will just deleted all the existing blocks.

    _context.SaveChanges(); //No need of _context.Update(plan);

    return NoContent();
}

Upvotes: 0

Fourat
Fourat

Reputation: 2447

Since you're keeping the principal entity (the Plan in your case) you should delete the deleted the child entities manually (the Blocks) :

[HttpPut]
public ActionResult Update(Plan plan)
{
    if (plan?.Id == null) return BadRequest();

    var plans = _context.Plans.Count(p => p.Id == plan.Id);
    if (plans != 1) return NotFound();

    var oldBlocks = _context.Blocks.Where(b => b.PlanId == plan.Id);
    foreach(var block in oldBlocks)
    {
        if (!plan.Blocks.Any(b => b.Id == block.Id))
            _context.Entry(block).State = EntityState.Deleted;
    }

    _context.Update(plan);

    _context.SaveChanges();

    return NoContent();
}

Upvotes: 1

Related Questions