实体框架出错:AcceptChanges无法继续,因为对象的键值与ObjectStateManager中的另一个对象冲突
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了实体框架出错:AcceptChanges无法继续,因为对象的键值与ObjectStateManager中的另一个对象冲突相关的知识,希望对你有一定的参考价值。
我遇到了Entity Framework 4.0的问题。我正在尝试保存一个“处理”对象,该对象具有“段”对象的集合。每当我尝试添加/编辑一个我在添加2个或更多新段的处理对象时,我会收到以下错误:
已成功提交对数据库的更改,但更新对象上下文时发生错误。 ObjectContext可能处于不一致状态。内部异常消息:AcceptChanges无法继续,因为对象的键值与ObjectStateManager中的另一个对象冲突。在调用AcceptChanges之前,请确保键值是唯一的。
这是我正在使用的保存方法。 “SegmentID”列是“Segment”的PK,它是一个在DB中设置为自动递增的整数(MS SQL 2008)。默认情况下,“SegmentID”设置为0,直到从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;
}
将行插入Oracle表时出现相同的错误,解决了将edmx文件编辑为xml(右键单击,使用..,XML编辑器打开)并将StoreGeneratedPattern="Identity"
添加到表定义中。
之前
<Property Name="ID" Type="number" Nullable="false" Precision="38" Scale="0" />
后
<Property Name="ID" Type="number" Nullable="false" Precision="38" Scale="0" StoreGeneratedPattern="Identity" />
问题是你在上下文中分配了两次相同的Segment
密钥,这会破坏ObjectStateManager。
myTreatment
有一系列Segment
实体,所有这些实体都被跟踪。现在,当你循环遍历它们时,你创建另一个Segment
,它最终可能与你的集合中现有的Segment
具有相同的密钥:
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();
}
如果您将列指定为唯一并尝试将相同值保存到该列,则会显示错误。如果可行,我可以给你提示。为此,您可以在segments表中添加名为“id”的新自动递增列,并将此列视为键
table: segment
id- new auto incremented key column
treatment_id
segment_id
entity:
id- key
treatment_id
segment_id
现在进行添加操作。并根据段的ID进行段实体的编辑和删除操作。
我最近遇到了这个问题,因为我添加了大量默认ID为零的对象,期望数据库和实体框架能够计算正确的ID,因为我向数据库表添加了序列和触发器。但是,似乎没有,我必须在保存对数据库上下文的更改之前使用正确的ID序列准备对象。
lookupOperation.ID = Sequance.GetSequenceBySequenceName(“lo_SEQ”);
以上是关于实体框架出错:AcceptChanges无法继续,因为对象的键值与ObjectStateManager中的另一个对象冲突的主要内容,如果未能解决你的问题,请参考以下文章
从 Nuget 安装实体框架 6.0.1 时出错(文档结构不正确)