Entity Framework 4-AddObject vs Attach
Я недавно работал с Entity Framework 4 и немного запутался в том, когда использовать ObjectSet.Прикрепить и ObjectSet.AddObject.
в моем понимании:
- используйте "прикрепить", когда объект уже существует в системе
- используйте "AddObject" при создании нового объекта
Итак, если я создание нового человека, Я делаю это.
var ctx = new MyEntities();
var newPerson = new Person { Name = "Joe Bloggs" };
ctx.Persons.AddObject(newPerson);
ctx.SaveChanges();
Если я изменение существующего человека, Я делаю это:
var ctx = new MyEntities();
var existingPerson = ctx.Persons.SingleOrDefault(p => p.Name = "Joe Bloggs" };
existingPerson.Name = "Joe Briggs";
ctx.SaveChanges();
имейте в виду, это очень просто пример. На самом деле я использую чистый POCO (без генерации кода), шаблон репозитория (не занимайтесь ctx.Лица), и единица работы (не занимайтесь ctx.SaveChanges). Но" под покровом", выше то, что происходит в моей реализации.
Итак, мой вопрос - Я еще не нашел сценарий, где мне пришлось использовать прикрепить.
чего мне здесь не хватает? Когда нам нужно использовать приложение?
EDIT
просто чтобы уточнить, я ищу примеры когда использовать Attach over AddObject (или наоборот).
EDIT 2
ниже Ответ правильный (который я принял), но подумал, что я бы добавил еще один пример, где прикрепление было бы полезно.
В моем примере выше для изменение существующего человека, фактически выполняются два запроса.
один, чтобы получить человека (.SingleOrDefault), а другой для выполнения обновления (.SaveChanges).
Если (по какой-то причине) я уже знал, что "Joe Bloggs" существует в системе, зачем делать дополнительный запрос, чтобы получить его первым? Я мог бы сделать это:
var ctx = new MyEntities();
var existingPerson = new Person { Name = "Joe Bloggs" };
ctx.Persons.Attach(existingPerson);
ctx.SaveChanges();
это приведет к выполнению только инструкции UPDATE.
4 ответа:
ObjectContext.AddObject и ObjectSet.AddObject:
Элемент AddObject метод предназначен для добавления вновь созданных объектов, которые делают не существуют в базе данных. Сущность получит автоматически сгенерированный временный EntityKey и его EntityState будет установлен в добавил. Когда SaveChanges вызывается, EF будет ясно, что эта сущность нужно вставить в базу данных.ObjectContext.Прикрепить и ObjectSet.Прикрепить:
С другой стороны, прикрепить используется для объектов, которые уже в базе данных. Вместо того, чтобы устанавливать EntityState для добавления, прикрепите результаты в без изменений EntityState, что означает, что он не изменился с момента его присоединения к контексту. Предполагается, что присоединяемые объекты существуют в базе данных. Если вы изменяете объекты после того, как они были присоединены, при вызове SaveChanges значение EntityKey используется для обновления (или удаления) соответствующей строки, находя ее соответствующий идентификатор в таблице БД.
Кроме того, используя метод Attach, вы можете определить отношения между сущностями, которые уже существуют в ObjectContext, но которые имеют не автоматически подключен. В основном основной целью Attach, является подключение сущностей, которые уже прикреплены к ObjectContext и являются не новый, поэтому вы не можете использовать Attach для присоединения объектов, EntityState которых добавляется. Вы должны использовать добавить() в этом случае.
Например, предположим, что ваше физическое лицо имеет свойство навигации с именем адреса это коллекция адрес сущности. Допустим, вы прочитали оба объекта из контексте, но они не связаны друг с другом, и вы хотите сделать это так:var existingPerson = ctx.Persons.SingleOrDefault(p => p.Name = "Joe Bloggs" }; var myAddress = ctx.Addresses.First(a => a.PersonID != existingPerson.PersonID); existingPerson.Addresses.Attach(myAddress); // OR: myAddress.PersonReference.Attach(existingPerson) ctx.SaveChanges();
это поздний ответ, но это может помочь другим, которые находят это.
в принципе, "отключенная" сущность может произойти, когда вы управляете сущностью вне области "использования".
Employee e = null; using (var ctx = new MyModelContainer()) { e = ctx.Employees.SingleOrDefault(emp => emp .....); } using (var ctx2 = new MyModelContainer()) { e; // This entity instance is disconnected from ctx2 }
Если вы введете другую область "using", то переменная "e" будет отключена, потому что она принадлежит к предыдущей области "using", а поскольку предыдущая область "using" уничтожена, то " e " отключается.
вот как я это понимаю.
Это цитата из Программирование Entity Framework: DbContext
вызов метода Remove для объекта, который не отслеживается контекстом вызовет исключение InvalidOperationException. Этот Entity Framework создает это исключение, потому что неясно, является ли сущность вы пытаются удалить существующий объект, который должен быть помечен для удаления или новый сущность, которую нужно просто игнорировать. По этой причине, мы не можем использовать просто Удалить пометить отключенный объект как удаленный; нам нужно сначала прикрепить его.
private static void TestDeleteDestination() { Destination canyon; using (var context = new BreakAwayContext()) { canyon = (from d in context.Destinations where d.Name == "Grand Canyon" select d).Single(); } DeleteDestination(canyon); } private static void DeleteDestination(Destination destination) { using (var context = new BreakAwayContext()) { context.Destinations.Attach(destination); context.Destinations.Remove(destination); context.SaveChanges(); } }
метод TestDeleteDestination имитирует клиентское приложение, извлекающее существующий Назначение с сервера, а затем передача его методу DeleteDestination on сервер. Метод DeleteDestination использует метод Attach, чтобы разрешить контекст знайте, что это существующее место назначения. Затем метод Remove используется для регистрации существующий Пункт назначения для удаления
Как насчет только ссылки на первичный ключ вместо присоединения?
Я.е:
var existingPerson = ctx.Persons.SingleOrDefault(p => p.Name = "Joe Bloggs" }; var myAddress = ctx.Addresses.First(a => a.PersonID != existingPerson.PersonID); existingPerson.AddressId = myAddress.Id // not -> existingPerson.Addresses.Attach(myAddress); // OR: myAddress.Person.Id = existingPerson.Id // not -> myAddress.PersonReference.Attach(existingPerson); ctx.SaveChanges();