I am having a problem with Entity Framework 4.0. I am trying to save a "Treatment" object that has a collection of "Segment" objects. Whenever I try to add/edit a Treatment object where I am adding 2 or more new Segments, I get the following error:
The changes to the database were committed successfully, but an error occurred while updating the object context. The ObjectContext might be in an inconsistent state. Inner exception message: AcceptChanges cannot continue because the object's key values conflict with another object in the ObjectStateManager. Make sure that the key values are unique before calling AcceptChanges.
Here is the save method I am using. The "SegmentID" column is the PK for a "Segment" and it is an integer that is set to auto increment in the DB (MS SQL 2008). By default, the "SegmentID" is set to 0 until it gets the updated segment from the DB.
public bool Save(Treatment myTreatment)
{
bool result = false;
using (tamcEntities db = new tamcEntities())
{
// IF NEW TREATMENT, CREATE IT AND ADD TO DB
if (myTreatment.Treatment_ID == 0)
{
db.Treatments.AddObject(myTreatment);
result = (db.SaveChanges() != 0);
}
// IF EXISTING TREATMENT, FIND EXISTING TREATMENT IN DB, AND UPDATE IT
else
{
List<string> treatmentIncludes = new List<string>();
treatmentIncludes.Add("Segments");
Treatment myTmt = (from x in db.Treatments
where x.Treatment_ID == myTreatment.Treatment_ID
select x).WithIncludes(treatmentIncludes).FirstOrDefault();
if (myTmt != null)
{
myTmt.Comment = myTreatment.Comment;
myTmt.Cost = myTreatment.Cost;
myTmt.CostItemDrain = myTreatment.CostItemDrain;
myTmt.CostItemE2E = myTreatment.CostItemE2E;
myTmt.CostItemEnhan = myTreatment.CostItemEnhan;
myTmt.CostItemEnv = myTreatment.CostItemEnv;
myTmt.CostItemGuard = myTreatment.CostItemGuard;
myTmt.CostItemOther = myTreatment.CostItemOther;
myTmt.CostItemPed = myTreatment.CostItemPed;
myTmt.CostItemSub = myTreatment.CostItemSub;
myTmt.CostItemTraffic = myTreatment.CostItemTraffic;
myTmt.CostItemUtl = myTreatment.CostItemUtl;
myTmt.Create_DateTime = myTreatment.Create_DateTime;
myTmt.Create_Entity = myTreatment.Create_Entity;
myTmt.Create_User = myTreatment.Create_User;
myTmt.Description = myTreatment.Description;
myTmt.Improvement_Type = myTreatment.Improvement_Type;
myTmt.Jurisdiction = myTreatment.Jurisdiction;
myTmt.Last_Update_DateTime = myTreatment.Last_Update_DateTime;
myTmt.Last_Update_Entity = myTreatment.Last_Update_Entity;
myTmt.Last_Update_User = myTreatment.Last_Update_User;
myTmt.Life_Expectancy = myTreatment.Life_Expectancy;
myTmt.MDOTJobID = myTreatment.MDOTJobID;
myTmt.Planned = myTreatment.Planned;
myTmt.Project_Classification = myTreatment.Project_Classification;
myTmt.ProjectID = myTreatment.ProjectID;
myTmt.Quantity = myTreatment.Quantity;
myTmt.SurfaceTypeAfter = myTreatment.SurfaceTypeAfter;
myTmt.tmp_treat = myTreatment.tmp_treat;
myTmt.Treatment_Date = myTreatment.Treatment_Date;
myTmt.Unit_of_Measure = myTreatment.Unit_of_Measure;
// DELETE MISSING SEGMENTS THAT ARE NO LONGER PART OF THE TREATMENT
List<int> segmentIDsToKeep = myTreatment.Segments.Select(x => x.SegmentID).ToList();
myTmt.Segments.Where(x => !segmentIDsToKeep.Contains(x.SegmentID)).ToList().ForEach(x => db.Segments.DeleteObject(x));
// ITERATE OVER EACH SEGMENT AND INSERT OR UPDATE IT
foreach (Segment s in myTreatment.Segments)
{
if (!string.IsNullOrWhiteSpace(s.PR) && !string.IsNullOrWhiteSpace(s.BMP.ToString()) && !string.IsNullOrWhiteSpace(s.EMP.ToString()))
{
Segment mySegment = new Segment();
// IF EXISTING SEGMENT, FIND EXISTING SEGMENT IN DB, AND UPDATE IT
if (s.SegmentID != 0)
{
mySegment = (from x in myTmt.Segments
where x.SegmentID == s.SegmentID
select x).FirstOrDefault();
}
mySegment.ActualLength = s.ActualLength;
mySegment.BMP = s.BMP;
mySegment.Create_DateTime = s.Create_DateTime;
mySegment.Create_Entity = s.Create_Entity;
mySegment.Create_User = s.Create_User;
mySegment.EMP = s.EMP;
mySegment.HasRequiredHPMS = s.HasRequiredHPMS;
mySegment.Lanes = s.Lanes;
mySegment.Last_Update_DateTime = s.Last_Update_DateTime;
mySegment.Last_Update_Entity = s.Last_Update_Entity;
mySegment.Last_Update_User = s.Last_Update_User;
mySegment.PASER_Rating = s.PASER_Rating;
mySegment.PR = s.PR;
mySegment.RoadName = s.RoadName;
mySegment.SurfaceType = s.SurfaceType;
mySegment.Treatment_ID = s.Treatment_ID;
mySegment.Version = s.Version;
// If the BMP is greater than the EMP, swap them.
if (mySegment.BMP > mySegment.EMP)
{
decimal tempBMP = mySegment.BMP;
decimal tempEMP = mySegment.EMP;
mySegment.BMP = tempEMP;
mySegment.EMP = tempBMP;
}
// IF NEW SEGMENT, ADD IT
if (s.SegmentID == 0)
{
myTmt.Segments.Add(mySegment);
}
}
}
result = (db.SaveChanges(SaveOptions.AcceptAllChangesAfterSave) != 0);
}
}
}
return result;
}
I have same error when inserting rows into Oracle table, solved editing edmx file as xml (right click, open with.., XML Editor) and added StoreGeneratedPattern="Identity"
to table definition.
Before
<Property Name="ID" Type="number" Nullable="false" Precision="38" Scale="0" />
After
<Property Name="ID" Type="number" Nullable="false" Precision="38" Scale="0" StoreGeneratedPattern="Identity" />
The issue is you are assigning the same Segment
key twice in your context, which mucks up the ObjectStateManager.
myTreatment
has a collection of Segment
entities, all of which are being tracked. Now, as you loop through them, you create another Segment
which could end up having the same key as an existing Segment
in your collection:
foreach (Segment s in myTreatment.Segments){
....
Segment mySegment = new Segment(); //NEW OBJECT
if (s.SegmentID != 0)
{
//IN HERE YOU ASSIGN THE SAME KEY TO THE NEW OBJECT
//s.SegmentID == mySegment.SegmentID **CONFLICT**
mySegment = (from x in myTmt.Segments
where x.SegmentID == s.SegmentID
select x).FirstOrDefault();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With