В Entity Framework, в чем разница между Add и Attach и как я могу решить свою проблему?

Недавно я начал использовать Entity Framework, и было больно проверить, действительно ли мне нужно добавлять новые записи в базу данных или нет.

Если объект, который мне нужно добавить в базу данных, уже на нем, я буду знать, потому что я делаю запрос перед его вставкой, и если он существует, то я сохраняю этот экземпляр, потому что мне нужно использовать его в некоторых отношениях.

Предположим, что мое имя объекта Book.

Проблема возникает, когда объект не находится в базе данных, и я делаю:

Book b = //...
modelContainer.AddToBooks(b);

Я мог бы легко сделать:

modelContainer.SaveChanges()

каждый раз, когда я добавляю новый объект (независимо от того, какой он объект), и это будет работать нормально, потому что, когда я вставляю один вид записи одновременно и проверяя, уже ли он в базе данных, я выиграл У меня проблемы с дублированием.

Но что, если я хочу так часто не звонить SaveChanges()?

В этом вопросе: Можно ли проверить, прикреплен ли объект к контексту данных в Entity Framework?, автор вопроса предоставляет метод, который мне помогает в моем случае, но это не работает, если я Add объект в контексте вместо Attaching его.

Мой вопрос (возможно, два, но очень связанные): в чем разница между Add и Attach и как я могу решить свою проблему?

Edit:
Вот пример проблемы, с которой я столкнулся.

У меня есть сущность Result, которая имеет отношение с двумя другими объектами: Trainer и Horse.

Я получаю данные от внешнего источника, поэтому мне нужно вручную создать все объекты.

Каждый раз, когда мне нужно вставить новый Trainer, я:

var trainer = Trainer.CreateTrainer(Id)

Затем я запрашиваю базу данных, чтобы узнать, есть ли в этой базе тренера с этим Id. Если это так, я заменяю переменную Trainer той, что находится в базе данных.

Если это не так, я могу сделать здесь две вещи:

  • Прикрепите тренера к контексту (я могу проверить, существует ли он с помощью ключа)
  • Добавьте тренера в контекст (используя AddToTrainers(...))

Тот же процесс для Horse.

Теперь, когда мне нужно создать новый Result (содержащий Trainer и Horse), я назначил предыдущий тренер и лошадь этому экземпляру результата.

Что мне делать, чтобы добавить в контекст новый Result?

  • Если я присоединяю тренера/лошади, тогда, когда я присоединяю результат, я получаю InvalidOperationException, сообщая мне, что тренер уже находится в контексте объекта.
  • Если я добавлю тренера вместо его присоединения, я получаю еще одну ошибку (не могу вспомнить ее прямо сейчас, но она говорила мне, что трейнер уже был в базе данных).

Важно:
Первая ошибка указана при прикреплении результата, а вторая при выполнении SaveChanges().

То, что я хочу избежать здесь, вызывает SaveChanges() каждый раз, когда я добавляю новый результат.

Ответы

Ответ 1

ObjectContext внутренне отслеживает все объекты, которые были либо загружены контекстом, либо добавлены, либо добавлены. Только те объекты могут быть изменены в базе данных при вызове SaveChanges. Каждый такой объект имеет ObjectStateEntry в ObjectStateManager. Одним из основных свойств ObjectStateEntry является a State. Состояние имеет тип перечисления EntityState, который предлагает следующие значения:

  • Добавлен
  • Удалено
  • Отдельно
  • Modified
  • Unchanged

Каждый объект, загруженный из базы данных, находится в состоянии Unchanged. Отдельно - особое состояние. Вы не найдете ObjectStateEntry с отдельным состоянием в ObjectStateManager. Но если вы спросите ObjectStateManager для ObjectStateEntry для сущности, не отслеживаемой контекстом, она создаст новое состояние ObjectStateEntry с Detached.

Теперь разница между Attach и AddObject:

  • Attach - если вы вызываете этот метод, ObjectContext начнет отслеживать весь граф объекта (основной объект и все связанные объекты). Все объекты, которые не были отслежены, будут установлены в состояние Unchanged.
  • AddObject - если вы вызываете этот метод, ObjectContext также начнет отслеживать весь граф объекта (основной объект и все связанные объекты). Разница в том, что все объекты, которые еще не были отслежены, будут установлены в Added state (= новые объекты, которые должны быть установлены в базу данных).

Ответ 2

Я знаю, что немного опоздал на этот пост, но искал подобное решение... и тогда я нашел эту статью Microsoft, которая может кратко ответить на большинство вопросов OP и может помочь будущим SO зрителям?:

Добавить/Присоединить и сущности > (http://msdn.microsoft.com/en-us/data/jj592676.aspx)

Из статьи:

В этом разделе рассказывается, как добавлять и присоединять объекты к контексту и как Entity Framework обрабатывает их во время SaveChanges.

И особенно посмотрите последний раздел на этой странице:

Вставить или обновить шаблон:. Обычным шаблоном для некоторых приложений является либо добавление объекта как нового (в результате чего происходит вставка базы данных), либо добавление сущности как существующего и маркировка его как измененного (в результате обновление базы данных) в зависимости от значения первичного ключа.