Reputation: 415
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
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
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