Запутанные статьи и документация о различиях (если таковые имеются) между системой.Данные.EntityState.Добавить & В Dbset.Добавлять

Я работаю над C# ASP.NET веб-приложение MVC 5 с EF 5. Отображение моих таблиц базы данных с помощью EF генерирует DbContext класс а . Сегодня я читал отличная статья о создании общих классов DAL, но я остановился на следующей фразе:

обратите внимание, что использование метода ввода для изменения состояния объекта будет влияет только на фактическую сущность, которую вы передаете методу. Это не каскад через график и задать состояние всех связанных объектов, в отличие от в dbset.Метод add.

, что противоречит тому, что упоминается в этих вопросах:

в ответах на все вышеперечисленные вопросы все пользователи упомянули, что с помощью System.Data.EntityState.Added точно так же, как с помощью DbSet.Add. Но в статье, которую я упомянул сначала, говорится, что использование System.Data.EntityState.Added не будет каскадировать через график.

основываясь на моем тесте, я заключаю, что использование System.Data.EntityState.Added будет каскадировать через график так же, как в DBset.Add случае. Статья неправильная, или это мой тест и Q&A?

2 ответов


эти методы те же, которые вы можете проверить регулярным тестированием, или, если вы хотите быть полностью уверены - некоторым исследованием кода 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) метод.

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

здесь _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);                
}

Я не знаю автора этого блога. Я знаю писателей книга DbContext хотя (хотя и не лично). Они знают EF наизнанку. Поэтому, когда на странице 80 они пишут

вызов DbSet.Add и параметр State to Added оба достижения точно то же самое.

Я знаю, что делаю. Они делают то же самое, которая составляет:

если сущность не отслеживается контекст, он начнет отслеживаться контекстом в the Added государство. Оба!--1--> и параметр State to Added операции с графами- это означает, что любые другие объекты, которые не отслеживаются контекстом и доступны от корневого объекта также будет отмечен как Added.

Я также знаю по опыту, что это работает именно так. Но чтобы устранить любые сомнения, в исходном коде EF оба DbSet.Add и DbEntityEntry.State (когда установлено значение Added) приехать в то же самое точка в ObjectContext это делает фактическую работу:

public virtual void AddObject(string entitySetName, object entity)

это функция, которая продолжает обманывать разработчиков, которые начинают работать с EF, как видно из большого количества вопросов в StackOverflow, задавая что-то вроде "как мои сущности дублируются?". Джули Лерман написала весь блог объясняя, почему это может произойти.

это продолжающееся заблуждение заставило команду EF принять решение изменить это поведение in ЭФ7.

возможно, автор блога, на который вы ссылаетесь, был одним из тех обманутых разработчиков.