令人困惑的文章和文档有关System.Data.EntityState.Add&之间的差异(如果有的话)。 DbSet.Add

时间:2016-04-15 16:58:25

标签: entity-framework entity-framework-5 dbcontext dbset

我正在使用EF 5编写一个C#ASP.NET MVC 5 Web应用程序。使用EF映射我的数据库表会生成DbContext类和.edmx文件。今天,我正在阅读a great article about creating generic DAL classes,但我停止了下面的句子:

  

请注意,使用Entry方法更改实体的状态   仅影响您传入方法的实际实体。它不会   通过图形级联并设置所有相关对象的状态,   与DbSet.Add方法不同。

这与这些问题中提到的内容相矛盾:

在上述所有问题的答案中,所有用户都提到使用System.Data.EntityState.Added与使用DbSet.Add完全相同。但我之前提到的文章指出,使用System.Data.EntityState.Added不会在图表中级联。

根据我的测试,我得出结论,使用System.Data.EntityState.Added将在DBset.Add案例中与图表级联。该文章是错误的,还是我的测试和Q& A?

2 个答案:

答案 0 :(得分:5)

这些方法是相同的,你可以通过常规测试来验证,或者,如果你想完全确定 - 通过对EF 6代码的一些探索。

  1. DbSet.Add方法(http://entityframework.codeplex.com/SourceControl/latest#src/EntityFramework/DbSet.cs

    public virtual TEntity Add(TEntity entity)
    {
        Check.NotNull<TEntity>(entity, "entity");
        this.GetInternalSetWithCheck("Add").Add((object) entity);
        return entity;
    }
    
  2. 这会调用InternalSet<T>.Add(object)方法。

    1. DbEntityEntry<T>.State属性(http://entityframework.codeplex.com/SourceControl/latest#src/EntityFramework/Infrastructure/DbEntityEntry.cs

      public EntityState State
      {
          get { return _internalEntityEntry.State; }
          set { _internalEntityEntry.State = value; }
      }
      
    2. _internalEntityEntry属于InternalEntityEntry类型。

      InternalEntityEntry.State属性(http://entityframework.codeplex.com/SourceControl/latest#src/EntityFramework/Internal/EntityEntries/InternalEntityEntry.cs

          public virtual EntityState State
          {
              get { return IsDetached ? EntityState.Detached : _stateEntry.State; }
              set
              {
                  if (!IsDetached)
                  {
                      if (_stateEntry.State == EntityState.Modified
                          && value == EntityState.Unchanged)
                      {
                          // Special case modified to unchanged to be "reject changes" even
                          // ChangeState will do "accept changes".  This keeps the behavior consistent with
                          // setting modified to false at the property level (once that is supported).
                          CurrentValues.SetValues(OriginalValues);
                      }
                      _stateEntry.ChangeState(value);
                  }
                  else
                  {
                      switch (value)
                      {
                          case EntityState.Added:
                              _internalContext.Set(_entityType).InternalSet.Add(_entity);
                              break;
                          case EntityState.Unchanged:
                              _internalContext.Set(_entityType).InternalSet.Attach(_entity);
                              break;
                          case EntityState.Modified:
                          case EntityState.Deleted:
                              _internalContext.Set(_entityType).InternalSet.Attach(_entity);
                              _stateEntry = _internalContext.GetStateEntry(_entity);
                              Debug.Assert(_stateEntry != null, "_stateEntry should not be null after Attach.");
                              _stateEntry.ChangeState(value);
                              break;
                      }
                  }
              }
          }
      

      您会看到如果实体已分离(您的情况)且状态已添加 - 则会调用相同的InternalSet<T>.Add(object)

      关于通过测试验证:

      using (var ctx = new TestDBEntities()) {
          // just some entity, details does not matter
          var code = new Code();
          // another entity
          var error = new Error();
          // Code has a collection of Errors
          code.Errors.Add(error);
          var codeEntry = ctx.Entry(code);
          // modify code entry and mark as added
          codeEntry.State = EntityState.Added;
          // note we did not do anything with Error
          var errorEntry = ctx.Entry(error);
          // but it is marked as Added too, because when marking Code as Added -
          // navigation properties were also explored and attached, just like when
          // you do DbSet.Add
          Debug.Assert(errorEntry.State == EntityState.Added);                
      }
      

答案 1 :(得分:5)

我不知道那篇博客的作者。我确实知道book DbContext的作者(虽然不是亲自)。他们知道EF内外。因此,当他们在第80页写下

  

致电DbSet.Add并将State设置为Added,两者完全相同。

我知道自己在做什么。他们完全相同的事情,即:

  

如果上下文没有跟踪实体,它将开始被上下文跟踪   Added州。DbSet.AddState和将Added设置为Added都是图表操作 -   意味着没有被上下文跟踪并且可以访问的任何其他实体   来自根实体的也将标记为DbSet.Add

我也从经验中知道它的工作原理。但是为了消除任何疑问,在EF的源代码中,DbEntityEntry.StateAdded(设置为ObjectContext时)到达实际工作的public virtual void AddObject(string entitySetName, object entity) 中的相同点:

{{1}}

这是一个继续欺骗开始使用EF的开发人员的功能,这从StackOverflow上的大量问题可以看出,他们提出了“为什么我的实体会被重复?”的问题。 Julie Lerman写了entire blog解释为什么会发生这种情况。

这种持续的妄想使EF团队决定在EF7中change this behavior

也许您所引用的博客的作者是那些被迷惑的开发者之一。