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

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

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

Давайте предположим, что мое имя сущности Book.

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

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

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

modelContainer.SaveChanges()

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

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

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

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

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

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

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

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

var trainer = Trainer.CreateTrainer(Id)

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

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

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

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

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

Что я должен сделать здесь, чтобы иметь возможность добавить в контекст эту новую Result?

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

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

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

Ответы [ 2 ]

21 голосов
/ 20 апреля 2011

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

  • Добавлена ​​
  • Удалено
  • Частный
  • Модифицированный
  • Без изменений

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

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

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

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

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

Из статьи:

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

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

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

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