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

Joh*_*ohn 7 entity-framework dbcontext entity-framework-5 dbset

我正在使用EF 5编写一个C#ASP.NET MVC 5 Web应用程序.使用EF映射我的数据库表会生成一个DbContext类和一个.edmx文件.今天,我正在阅读一篇关于创建泛型DAL类的好文章,但我停止了以下句子:

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

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

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

根据我的测试,我得出结论,使用System.Data.EntityState.Added将通过图表级联,与DBset.Add案例相同.这篇文章是错的,还是我的考试和问答?

Evk*_*Evk 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;
    }
    
    Run Code Online (Sandbox Code Playgroud)

这叫InternalSet<T>.Add(object)方法.

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

    public EntityState State
    {
        get { return _internalEntityEntry.State; }
        set { _internalEntityEntry.State = value; }
    }
    
    Run Code Online (Sandbox Code Playgroud)

哪里_internalEntityEntryInternalEntityEntry类型.

InternalEntityEntry.Stateproperty(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;
                }
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

您会看到如果实体已分离(您的情况)并且状态已添加 - 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);                
}
Run Code Online (Sandbox Code Playgroud)


Ger*_*old 5

我不知道那个博客的作者.我确实知道DbContext本书的作者(虽然不是亲自).他们知道EF内外.因此,当他们在第80页写作时

调用DbSet.Add和设置State,以Added双方实现完全一样的东西.

我知道自己要做什么.他们完全一样,这是:

如果实体未被上下文跟踪,则它将开始被Added状态中的上下文跟踪.二者DbSet.Add并设置StateAdded是图形操作-这意味着在未被由上下文跟踪和任何其它实体是从根实体可到达也将被标记为Added.

我也从经验中知道它的工作原理.但是为了消除任何疑问,在EF的源代码中,两者DbSet.AddDbEntityEntry.State(当设置为Added)达到ObjectContext实际工作时的相同点:

public virtual void AddObject(string entitySetName, object entity)
Run Code Online (Sandbox Code Playgroud)

这是一个继续欺骗开始使用EF的开发人员的功能,从StackOverflow上的大量问题中可以看出,他们提出了"我的实体是如何重复的?".Julie Lerman写了一篇完整的博客,解释了为什么会这样.

这种持续的错觉使EF团队决定在EF7中改变这种行为.

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