2016-04-15 27 views
7

我正在使用EF 5處理C#ASP.NET MVC 5 Web應用程序。使用EF映射我的數據庫表生成一個DbContext類和一個.edmx文件。今天,我讀a great article about creating generic DAL classes,但我停在下面的句子:混淆關於System.Data.EntityState.Add和DbSet.Add之間差異(如果有)的文章和文檔

注意,使用輸入方法來改變實體的狀態將 只會影響您在傳遞給該方法的實際實體。與DbSet.Add方法不同,它不會通過圖形級聯 並設置所有相關對象的狀態,即 。

違背什麼是在這些問題中提到:

在上述所有問題的答案,所有用戶提到使用System.Data.EntityState.Added與使用DbSet.Add完全相同。但是我首先提到的文章指出,使用System.Data.EntityState.Added將不會級聯通過圖表。

根據我的測試,我得出結論,使用System.Data.EntityState.Added將通過與DBset.Add案例相同的圖表級聯。這篇文章是錯誤的,還是它是我的測試和Q & A?

回答

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; 
    } 
    

這要求InternalSet<T>.Add(object)方法。

  • 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; } 
    } 
    
  • 哪裏_internalEntityEntryInternalEntityEntry類型。

    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);     
    } 
    
    +0

    所以你說使用EntityState.Added和使用DBset.Add是完全一樣的? –

    +1

    是的,如果你的實體沒有被上下文跟蹤,這兩個方法將做同樣的事情,具有完全相同的結果,這通過測試例子和源代碼探索來證實。 – Evk

    +0

    因此假設實體正在被上下文跟蹤,那麼它們會不同?正如你所說的「如果你的實體沒有被跟蹤...」 –

    5

    我不知道該博客的作者。我知道book DbContext的作者雖然(儘管不是親自)。他們知道EF內外。所以,當80頁上他們寫

    調用DbSet.Add並設置StateAdded都達到同樣的事情。

    我知道我在做什麼。他們這樣做同樣的事情,那就是:

    如果實體沒有被上下文跟蹤,它將開始被在 的Added狀態的情況下跟蹤。 DbSet.AddState設置爲Added都是圖表操作- 這意味着任何其他實體沒有被上下文跟蹤並且從根實體可到達 也將被標記爲Added

    我也通過經驗知道它的工作方式。但要消除任何疑慮,在EF的源代碼,無論是DbSet.AddDbEntityEntry.State(當設置爲Added)在ObjectContext,做實際工作,在到達同一個點:

    public virtual void AddObject(string entitySetName, object entity) 
    

    就這麼繼續欺騙開發商的功能,開始與EF一起工作,從StackOverflow的大量問題可以看出,問題是「我的實體如何複製?」。朱莉勒曼寫了一個entire blog解釋爲什麼會發生這種情況。

    這種持續的妄想使EF團隊決定在EF7中使用change this behavior

    也許你提到的博客的作者是那些被欺騙的開發者之一。