I have a SPA ASP.NET WebAPI application that uses EF6. The application has two parent child entities that I am having a problem updating. The intent of the code is that when a user changes code on the front end then the Objectives and their details will be sent to the controller. The controller then check to see if any details have changed and processes these. Right now I have commented this part of the code out as I cannot even get the simplest update to work. Here is the error that I get:
{"Attaching an entity of type 'Entities.Models.Core.ObjectiveDetail' failed because another entity of the same type already has the same primary key value. This can happen when using the 'Attach' method or setting the state of an entity to 'Unchanged' or 'Modified' if any entities in the graph have conflicting key values. This may be because some entities are new and have not yet received database-generated key values. In this case use the 'Add' method or the 'Added' entity state to track the graph and then set the state of non-new entities to 'Unchanged' or 'Modified' as appropriate."}
Here are the two classes that I have:
public class Objective
{
public Objective()
{
this.ObjectiveDetails = new HashSet<ObjectiveDetail>();
}
public int ObjectiveId { get; set; }
public string Text { get; set; }
public virtual ICollection<ObjectiveDetail> ObjectiveDetails { get; set; }
}
public partial class ObjectiveDetail
{
public int ObjectiveDetailId { get; set; }
public int ObjectiveId { get; set; }
public string Text { get; set; }
public virtual Objective Objective { get; set; }
}
My Controller looks like this:
// PUT: api/Objective/5 Updating
[ResponseType(typeof(void))]
public async Task<IHttpActionResult> Put(int id, Objective objective)
{
try
{
// I get an exception when I uncomment the following line
//
//
// var oldObj = db.ObjectiveDetails.Where(t => t.ObjectiveId == id).ToList();
var newObj = objective.ObjectiveDetails.ToList();
//var upd = newObj
// .Where(wb => oldObj
// .Any(db1 =>
// (db1.ObjectiveDetailId == wb.ObjectiveDetailId) &&
// (db1.Number != wb.Number || !db1.Text.Equals(wb.Text))))
// .ToList();
//var add = newObj
// .Where(wb => oldObj
// .All(db2 => db2.ObjectiveDetailId != wb.ObjectiveDetailId))
// .ToList();
//var del = oldObj
// .Where(db2 => newObj
// .All(wb => wb.ObjectiveDetailId != db2.ObjectiveDetailId))
// .ToList();
//foreach (var objectiveDetail in upd)
//{
// db.Entry(objectiveDetail).State = EntityState.Modified;
//}
//foreach (var objectiveDetail in add)
//{
// db.ObjectiveDetails.Add(objectiveDetail);
//}
//del.ForEach(_obj => db.ObjectiveDetails.Remove(_obj));
// I tried the following but it did not work
//
//db.Objectives.Attach(objective);
//db.Entry(objective).State = EntityState.Modified;
DbEntityEntry dbEntityEntry = db.Entry(objective);
if (dbEntityEntry.State == EntityState.Detached)
{
db.Objectives.Attach(objective);
}
dbEntityEntry.State = EntityState.Modified;
await db.SaveChangesAsync();
return Ok(objective);
}
catch (Exception e)
{
return NotFound();
}
}
If I remove the line:
var oldObj = db.ObjectiveDetails.Where(t => t.ObjectiveId == id).ToList();
Then I am able to do an update to the database. If I add in this line (which I need for later) then I get the exception.
Can someone give me some advice on what I am doing wrong?