В 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.
И особенно посмотрите последний раздел на этой странице:
Вставить или обновить шаблон:. Обычным шаблоном для некоторых приложений является либо добавление объекта как нового (в результате чего происходит вставка базы данных), либо добавление сущности как существующего и маркировка его как измененного (в результате обновление базы данных) в зависимости от значения первичного ключа.