实体框架5问题删除 - 对象状态管理器问题

时间:2014-02-28 21:54:36

标签: c# entity-framework

当我尝试删除实体时,我收到以下错误:

  

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

我已阅读此处与此错误相关的其他帖子,并尝试分离过滤器,没有运气。也许我错过了一些简单的东西,或者应该使用不同的方法来删除这些过滤器(我已经尝试过删除方法)?任何帮助将不胜感激。

以下是代码:我使用的是ASP.NET 4.5和EF 5.这个简单的存储库类在存储库构造函数中初始化了一个私有dbContext,并在析构函数中被销毁。

namespace AuditLog.Repositories
{
    public class FilterSetRepository : IFilterSetRepository
    {
        private readonly AuditLogEntities _ctx;

        /// <summary>
        /// Default constructor
        /// </summary>
        public FilterSetRepository()
        {
            _ctx = new AuditLogEntities();
        }

        /// <summary>
        /// Destructor
        /// </summary>
        ~FilterSetRepository()
        {
            _ctx.Dispose();
        }

在foreach循环中有_ctx.Entry(filter).State = EntityState.Deleted;的行(下面)抛出错误。名为FilterSet的实体有一个Filter实体列表,在我删除FilterSet之前必须从它们的表中删除它们。如有必要,我可以提供显示它们的类代码。 在违规行的上方是我尝试分离方法的地方,但是它说它无法分离,因为还没有附加密钥。

/// <summary>
/// Delete a particular filter set and its filters.
/// </summary>
/// <param name="filterSet">The filter set to be deleted.</param>
public void DeleteFilterSet(FilterSet filterSet)
{
    // First delete the child elements
    var filterRepository = new FilterRepository();
    foreach (var filter in filterRepository.GetFiltersBySets(filterSet))
    {
        _ctx.Entry(filter).State = EntityState.Deleted;
        _ctx.SaveChanges();
    }

    // ...then delete the filter set
    _ctx.Entry(filterSet).State = EntityState.Deleted;
    _ctx.SaveChanges();
}

提前感谢您的帮助!

3 个答案:

答案 0 :(得分:2)

再次阅读此post后,我能够修改我的DeleteFilterSet代码,以查找和处理对象状态管理器已经跟踪密钥的对象。以下是有效的代码:

/// <summary>
/// Delete a particular filter set and its filters.
/// </summary>
/// <param name="filterSet">The filter set to be deleted.</param>
public void DeleteFilterSet(FilterSet filterSet)
{
  // First delete the child elements
  var filterRepository = new FilterRepository();

  foreach (var filter in filterRepository.GetFiltersBySets(filterSet))
  {
      var entry = _ctx.Entry(filter);

      if (entry.State==EntityState.Detached)
      {
          var set = _ctx.Set<Filter>();
          Filter attachedEntity = set.Local.SingleOrDefault(e => e.FilterId == filter.FilterId);

          if (attachedEntity!=null)
          {
              var attachedEntry = _ctx.Entry(attachedEntity);
              attachedEntry.State=EntityState.Deleted;
          }
          else
          {
              entry.State = EntityState.Deleted;
          }
      }
       _ctx.SaveChanges();
  }

   // ...then delete the filter set
   _ctx.FilterSets.Remove(filterSet);
   _ctx.SaveChanges();
}

我希望这个解决方案可以帮助其他人。

答案 1 :(得分:1)

_ctx.Entry(filter).State = EntityState.Deleted;会对状态进行大量额外检查。

如果您已经拥有过滤器对象,则可能需要使用:

_ctx.Attach(filter);
_ctx.Filter.Remove(filter);
_ctx.SaveChanges();

答案 2 :(得分:1)

我曾经遇到过这个异常并用它来修复它,当你想要一个对象添加到上下文(附加)并且dbcontext中已经存在另一个具有相同主键值的对象时,它就会发生。 我建议你在你的sql存储库中添加一个Attach方法,如下所示:

  public void Attach(T itemToBeAttached)
    {
        T old = _objectSet.Local.FirstOrDefault(i => i.Id == itemToBeAttached.Id);
        if (old != null)
        {
            _context.Entry<T>(old).State = EntityState.Detached;
        }
        _objectSet.Attach(itemToBeAttached);
    }

这里的关键是objectSet的加载属性。

当你想要删除一个实体并且实体dosnt存在于对象上下文中时,它首先检查是否附加了对象的状态,如果它没有附加,那么ef将附加到db那些如果另一个对象已经存在则抛出exceptin的地方具有相同密钥的上下文。