麻烦EF“保存”方法,修改了子实体的集合

时间:2011-11-15 18:36:39

标签: c# .net entity-framework

我有一个父实体(治疗),其中包含一组子实体(细分)。我有一个save方法接受处理,确定它是新的还是现有的,然后将它添加到objectContext或根据它是新的还是现有的方法将它附加到对象上下文。

它与主要实体中的孩子做同样的事情。它迭代子实体的集合,然后根据需要添加或更新。

我试图让它做的是删除任何丢失的子对象。问题是,当我更新父对象然后将其附加到对象上下文时,父对象则具有来自DB的子对象的集合。不是我最初传入的集合。所以如果我有一个3段的治疗,我从集合中删除一个段,然后将治疗传递给我的保存方法,一旦将治疗对象附加到objectcontext,它拥有的段数从2变为3。

我做错了什么?

以下是我的保存方法的代码:

public bool Save(Treatment myTreatment, modelEntities myObjectContext)
        {
            bool result = false;

            if (myObjectContext != null)
            {
                if (myTreatment.Treatment_ID == 0)
                {
                    myObjectContext.Treatments.AddObject(myTreatment);
                }
                else
                {
                    if (myTreatment.EntityState == System.Data.EntityState.Detached)
                    {
                        myObjectContext.Treatments.Attach(myTreatment);
                    }
                    myObjectContext.ObjectStateManager.ChangeObjectState(myTreatment, System.Data.EntityState.Modified);
                    myObjectContext.Treatments.ApplyCurrentValues(myTreatment);
                }

                foreach (Segment mySegment in myTreatment.Segments)
                {
                    if (mySegment.SegmentID == 0)
                    {
                        myObjectContext.ObjectStateManager.ChangeObjectState(mySegment, System.Data.EntityState.Added);
                        myObjectContext.Segments.AddObject(mySegment);
                    }
                    else
                    {
                        if (mySegment.EntityState == System.Data.EntityState.Detached)
                        {
                            myObjectContext.Segments.Attach(mySegment);
                        }
                        myObjectContext.ObjectStateManager.ChangeObjectState(mySegment, System.Data.EntityState.Modified);
                        myObjectContext.Segments.ApplyCurrentValues(mySegment);
                    }
                }
            }

            result = (myObjectContext.SaveChanges(SaveOptions.None) != 0);


            return result;
        }

*编辑* * ** 基于下面的一些反馈,我修改了“保存”方法。新方法实现如下。但是,它仍然不会删除已从myTreatments.Segments集合中删除的细分。

public bool Save(Treatment myTreatment, tamcEntities myObjectContext)
        {
            bool result = false;

            if (myObjectContext != null)
            {
                if (myTreatment.Treatment_ID == 0)
                {
                    myObjectContext.Treatments.AddObject(myTreatment);
                }
                else
                {
                    if (myTreatment.EntityState == System.Data.EntityState.Detached)
                    {
                        myObjectContext.Treatments.Attach(myTreatment);
                    }
                    myObjectContext.ObjectStateManager.ChangeObjectState(myTreatment, System.Data.EntityState.Modified);
                }

                foreach (Segment mySegment in myTreatment.Segments)
                {
                    if (mySegment.SegmentID == 0)
                    {
                        myObjectContext.ObjectStateManager.ChangeObjectState(mySegment, System.Data.EntityState.Added);
                    }
                    else
                    {
                        myObjectContext.ObjectStateManager.ChangeObjectState(mySegment, System.Data.EntityState.Modified);
                    }
                }
            }

            result = (myObjectContext.SaveChanges(SaveOptions.None) != 0);


            return result;
        }

最终编辑 我终于得到了它的工作。这是更新的Save方法,它正常工作。我必须在局部变量中保存Segments的初始列表,然后在将其附加到数据库后将其与myTreatments.Segments列表进行比较,以确定要删除的Segments列表,然后迭代该列表并删除匹配来自新附加的myTreatment.Segments列表的细分。我还根据以下几个响应者的建议删除了objectcontext的传入。

public bool Save(Treatment myTreatment)
        {
            bool result = false;


            List<Segment> myTreatmentSegments = myTreatment.Segments.ToList<Segment>();

            using (tamcEntities myObjectContext = new tamcEntities())
            {
                if (myTreatment.Treatment_ID == 0)
                {
                    myObjectContext.Treatments.AddObject(myTreatment);
                }
                else
                {
                    if (myTreatment.EntityState == System.Data.EntityState.Detached)
                    {
                        myObjectContext.Treatments.Attach(myTreatment);
                    }
                    myObjectContext.ObjectStateManager.ChangeObjectState(myTreatment, System.Data.EntityState.Modified);
                }

                // Iterate over all the segments in myTreatment.Segments and update their EntityState to force
                // them to update in the DB.
                foreach (Segment mySegment in myTreatment.Segments)
                {
                    if (mySegment.SegmentID == 0)
                    {
                        myObjectContext.ObjectStateManager.ChangeObjectState(mySegment, System.Data.EntityState.Added);
                    }
                    else
                    {
                        myObjectContext.ObjectStateManager.ChangeObjectState(mySegment, System.Data.EntityState.Modified);
                    }
                }

                // Create list of "Deleted" segments
                List<Segment> myDeletedSegments = new List<Segment>();
                foreach (Segment mySegment in myTreatment.Segments)
                {
                    if (!myTreatmentSegments.Contains(mySegment))
                    {
                        myDeletedSegments.Add(mySegment);
                    }
                }
                // Iterate over list of "Deleted" segments and delete the matching segment from myTreatment.Segments
                foreach (Segment mySegment in myDeletedSegments)
                {
                    myObjectContext.ObjectStateManager.ChangeObjectState(mySegment, System.Data.EntityState.Deleted);
                }

                result = (myObjectContext.SaveChanges(SaveOptions.None) != 0);
            }
            return result;
        }

2 个答案:

答案 0 :(得分:1)

好的,再试一次。

当您说“删除”时,您的意思是标记为已删除。

您正在调用ChangeObjectState以将状态更改为已修改。

所以如果你发送3,一个删除,一个修改,一个不变;然后在调用保存更改之前,所有内容都会被标记为已修改。

答案 1 :(得分:1)

也许我错过了一些东西,但对我来说这段代码看起来过于繁琐。 如果我在这里错误的轨道并误解了你,请耐心等待我。

关于应删除的对象,我建议您将这些对象存储在仅包含已删除项目的单独集合中。您可以从ObjectContext删除它们。

我会调用myObjectContext.SaveChanges()而不是调用ApplyCurrentValues。在这种情况下,ApplyCurrentValues的缺点是它不会处理与您正在保存的实体有关系的任何其他实体。

MSDN documentation:

  

标量值从提供的对象复制到对象中   具有相同键的ObjectContext。

由于其他Segments已经通过使用SaveChanges()附加到您的Treatment,它们将自动添加到上下文中,或者如果已经添加,则会更新。

这应该使得对EntityStates的所有手动处理都不必要。

修改 现在我看到这是怎么回事......

在你的某个地方你编码 - 在这个Save()方法之外 - 你正在删除Segment实例。麻烦在于你的ObjectContext 完全没有意识到这个问题。怎么应该......?

您可能已销毁某个Segment实体的实例,但由于实体已分离,这意味着它们与ObjectContext的无连接。因此,上下文完全不知道你做了什么。

因此,当您附加处理时,上下文仍然认为所有段都存在,因为它不知道删除并将它们再次添加到处理,就像从未发生过一样。

<强>解决方案: 就像我上面已经说过的那样,你需要跟踪你删除的实体。

在那些删除细分的地方,不要删除它们,但是:

    来自治疗实例的
  1. Remove()
  2. 将“已删除”细分移动到一个集合中,例如List<Segment>。我们称之为deletedSegments。
  3. 将deletedSegments集合传递到Save()方法
  4. 循环浏览此集合并ObjectContect.Delete()
  5. 根据需要执行剩余的剩余保存逻辑。
  6. 此外,与Tomas Voracek提到的一样,最好使用更多本地的上下文。仅在save方法中创建它,而不是将其作为参数传递。