0

我有一个实体假设 [MainEntity]。这个主实体有一些子实体,如下所示:

MainEntity:
          -> ChildEntity1
          -> ChildEntity2
          -> ChildEntity3
          -> ChildEntity4
          -> ChildEntity5

所有子实体与主实体具有一对多的关系。

在 UI 用户更新主实体和前 3 个子实体的数据。在 UI 中 ChildEntity1、ChildEntity2、ChildEntity3 分别由 GridView、ListBox 和 CheckListBox 表示。用户可以通过这些控件添加/更新子记录。插入/更新数据的示例代码如下:

BL class:
========
public class EntityManager
 {
      public EntityManager ()
      {
            MainEntityData = new MainEntity();
      }
      public MainEntity MainEntityData= { get; set; }

      public void InsertUpdate()
      {
            DAL.InsertMainEntityData(MainEntityData);

      }
}


UI Codes:
=========

EntityManager objEntityManager = new EntityManager();

if (lnkInsertUpdate.CommandArgument == "Update")
   objEntityManager.MainEntity.ID =                        
                         int.Parse(Request.QueryString["ID"].ToString());

objEntityManager.MainEntity.Name = txtName.Text;
objEntityManager.MainEntity.Description = txtDescription.Text;
-----------------------------------------
-----------------------------------

ChildEntity1 objChildEntity1 = null;
foreach (ListItem item in lstSelectedProduct.Items)
{
  objChildEntity1 = new ChildEntity();
  objChildEntity1.ClientProductID = int.Parse(item.Value);
  objChildEntity1.IsActive = true;
  objChildEntity1.CreatedBy = "Admin";
  objChildEntity1.CreatedDate = DateTime.Now;
  objEntityManager.MainEntity.ChildEntitys1.Add(objChildEntity1);
}

-----------------------------------
codes for childentity2,childentity3
--------------------------------
objEntityManager.InsertUpdate()


DALCodes:
=========
public static void InsertMainEntityData(MainEntity objMainEntity)
{
    using (TransactionScope ts = new TransactionScope())
    {
      try
      {
        using (DBEntities context = DatabaseFactory.GetContext())
        {
        if (objMainEntity.ID > 0)
        {
         MainEntity mainEntityToUpdate = 
 context.MainEntitys.Include("ChildEntity1").Include("ChildEntity2").Include("ChildEntity3").First(o => o.ID == objMainEntity.ID);

          mainEntityToUpdate = objMainEntity;
          context.MainEntitys.Attach(mainEntityToUpdate);
         context.ObjectStateManager.ChangeObjectState(mainEntityToUpdate, 
                       EntityState.Modified);
        }
       else
        {
                context.AddToMainEntitys(objMainEntity);
                context.SaveChanges();
                 ts.Complete();
           }
          catch (Exception ex)
          {
            ts.Dispose();
          }
           finally
           {
        }
}

Insert new reord 工作正常,但在更新它时给出以下错误:

ObjectStateManager 中已存在具有相同键的对象。ObjectStateManager 无法跟踪具有相同键的多个对象。

请指导如何解决这个问题??

谢谢,

保罗

4

1 回答 1

1

您有此错误,因为您在此行中mainEntityToUpdate使用 detached覆盖加载:objMainEntity

mainEntityToUpdate = objMainEntity;

然后你附加这个对象:

context.MainEntitys.Attach(mainEntityToUpdate);

因为mainEntityToUpdate仍然附加到上下文(加载后),所以您有两个对象具有相同的键附加到上下文,这是被禁止的并导致异常。

您可以改为使用以下方法更新实体的标量属性:

MainEntity mainEntityToUpdate = context.MainEntitys
    .First(o => o.ID == objMainEntity.ID);

context.MainEntitys.ApplyCurrentValues(objMainEntity);

但它只更新标量属性,而不是您的子集合 - 因为将状态设置为Modified也不会导致子集合的更新。

更新包含所有子集合的主实体实际上并不容易。您必须加载原始实体,包括数据库中的所有子集合(您开始加载主实体Include("ChildX")是正确的),然后将其与分离objMainEntity的集合及其更新的集合进行比较。“比较”意味着:您必须检测用户添加了哪些集合项,哪些已被删除,哪些仍然存在(但可能具有更改的属性值),然后相应地在原始集合中添加或删除项目。更改检测将跟踪这些更改,并在您调用时将相应的 SQL 语句写入数据库SaveChanges

如何做到这一点的草图(对于DbContext/EF >= 4.1)在这里:https ://stackoverflow.com/a/5540956/270591

于 2012-05-29T16:12:00.147 回答