10

我在使用 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;
    }
4

4 回答 4

5

在将行插入 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" />
于 2015-09-17T14:02:02.557 回答
2

问题是您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();
    }         
于 2013-08-18T13:29:25.517 回答
0

如果您将列指定为唯一列并尝试将相同的值保存到该列,则会显示该错误。如果对您可行,我可以给您提示。为此,您可以在细分表中添加一个名为“id”的新自动递增列,并将此列视为键

table: segment
id- new auto incremented key column
treatment_id
segment_id

entity:
id- key
treatment_id
segment_id

现在做你的添加操作。并根据段的 id 对段实体进行编辑和删除操作。

于 2015-07-01T05:21:42.583 回答
0

我最近遇到了这个问题,这是因为我添加了大量默认 ID 为零的对象,期望数据库和实体框架能够计算正确的 ID,因为我向数据库表添加了序列和触发器。但是,似乎没有,在保存对数据库上下文的更改之前,我必须准备具有正确 ID 序列的对象。

lookupOperation.ID = Sequance.GetSequenceBySequenceName("lo_SEQ");

于 2018-04-04T12:32:44.743 回答