Удаление данных entity framework
В Entity Framework Core (EF Core) связи представлены с помощью внешних ключей. Сущность с внешним ключом является дочерней или зависимой в связи. Значение внешнего ключа этой сущности должно соответствовать значению первичного ключа (или альтернативному значению ключа) связанной основной или родительской сущности.
Если основная или родительская сущность удалена, значения внешних ключей зависимых и дочерних сущностей больше не соответствуют первичному или альтернативному ключу какой-либо основной или родительской сущности. Это недопустимое состояние, которое в большинстве баз данных приведет к нарушению ссылочного ограничения.
Избежать этого нарушения можно двумя способами.
- Присвоить внешним ключам значения NULL.
- Удалить соответствующие зависимые или дочерние сущности.
Первый способ подходит только для необязательных связей, в которых свойство внешнего ключа (и столбец базы данных, с которым оно сопоставлено), должно допускать значения NULL.
Второй вариант допустим для любого типа связи и называется каскадным удалением.
В этом документе описывается каскадное удаление (и удаление потерянных объектов) в контексте обновления базы данных. При этом активно используются концепции, представленные в разделах Отслеживание изменений в EF Core и Изменение внешних ключей и свойств навигации. Прежде чем приступать к изучению этого документа, обязательно ознакомьтесь с ними.
Вы можете запустить и отладить весь код, используемый в этой документации, скачав пример кода из GitHub.
Настройка каскадной реакции на события
Прежде чем переходить к этому разделу, ознакомьтесь с приведенными выше. Для понимания параметров конфигурации потребуется знание представленных ранее материалов.
Настройка каскадной реакции на события для отдельных связей осуществляется с помощью метода OnDelete в OnModelCreating. Пример:
() .HasOne(e => e.Owner) .WithOne(e => e.OwnedBlog) .OnDelete(DeleteBehavior.ClientCascade); > -->
Дополнительные сведения о настройке связей между типами сущностей см. в разделе Связи.
Метод OnDelete принимает значение из перечисления DeleteBehavior, с использованием которого связаны определенные сложности. В этом перечислении определяется поведение EF Core для отслеживаемых сущностей и задается конфигурация каскадного удаления в базе данных в случаях, когда для создания схемы используется EF.
Ручное удаление связанных объектов
Возможно, простейший способ удаления связанных объектов состоит в простой передаче каждого из них методу ObjectContext.DeleteObject. При этом необходимо соблюдать осторожность. Во-первых, следует убедиться, что порядок их удаления не нарушает ограничений схемы. Например, если требуется удалить Order, то сначала следует удалить связанные объекты Order_Detail, а только потом удалять Order. Если сделать наоборот, получится исключение вроде того, что видели ранее.
Во-вторых, нужно убедиться, что они удалены все — что-то оставлять нельзя, иначе будет получено исключение или появится несколько строк "висячих" данных.
Наконец, необходимо убедиться, что связанные объекты не имеют других зависимых объектов. Сложные базы данных могут иметь множество отношений внешнего ключа, и придется разобрать их все досконально, чтобы получить возможность корректно удалить граф объектов.
Таким образом, чтобы вручную удалить Order, сначала понадобится удалить все связанные с ним объекты Order_Detail. Ниже показано, как это делается:
В этом примере запрашивается объект Order со значением свойства OrderID, равным 10248. Он выбран именно потому, что в базе данных с ним связано более одного Order_Detail. Перед удалением собственно Order объекты Order Detail перечисляются и удаляются один за другим.
Обратите внимание на вызов метода ToArray на Order_Details EntityCollection и перечисление результата. Если этого не сделать, пришлось бы удалять объекты из обрабатываемого перечисления и тогда после удаления первого объекта Order_Details возникло бы исключение.
Добавление
Для добавления объекта используется метод Add , определенный у класса DbSet, в который передается добавляемый объект:
Метод Add устанавливает значение Added в качестве состояния нового объекта. Поэтому метод db.SaveChanges() сгенерирует выражение INSERT для вставки модели в таблицу.
Если нам надо добавить сразу несколько объектов, то мы можем воспользоваться методом AddRange() :
Каскадное удаление связанных объектов
Другой способ обработки связанных объектов предусматривает применение каскадного удаления. Каскадное удаление означает, что в случае удаления из базы данных записи, такой как Order, связанные записи, имеющие с ней отношение внешнего ключа, вроде записей из таблицы Order Details, также будут удалены автоматически.
Для каждого отношения внешнего ключа, которое необходимо изменить, должно быть включено каскадное удаление в базе данных и в сущностной модели данных.
в мире реляционных баз данных позволяет удалять связанные данные из зависимой таблицы, при удалении данных из основной таблицы. В случае модели, которую мы использовали в предыдущих примерах (две связанные таблицы Customer и Order), при использовании каскадного удаления, удаление данных покупателя будет вести к удалению всех связанных с ним заказов. В SQL Server и T-SQL каскадное удаление реализовано в виде опций ON DELETE CASCADE и ON UPDATE CASCADE, которые указываются при объявлении внешнего ключа таблицы.
По умолчанию Code-First включает каскадное удаление для внешних ключей, не поддерживающих значение NULL, используя соответствующий SQL-код при создании таблицы. В предыдущей статье мы описали, как указать Code-First на то, что внешний ключ должен обязательно использоваться (т.е. поддерживать ограничение NOT NULL). Давайте вспомним, как это сделать:
Можно явно указать свойство внешнего ключа, тогда Code-First по умолчанию использует для него значение NOT NULL в базе данных. В примерах мы использовали внешние ключи CustomerId и UserId.
Если внешний ключ не указан в классе модели, тогда Code-First автоматически генерирует его, разрешая использовать NULL. Чтобы это изменить, можно использовать атрибут Required к навигационному свойству модели.
В этой форме используются две кнопки для удаления и сохранения данных. В коде обработчика Save_Click происходит создание произвольного объекта Customer с тремя связанными объектами Order, после чего эти данные вставляются в базу. В коде обработчика Delete_Click мы сначала извлекаем данные нужного заказчика из базы данных, а затем удаляем его. Обратите внимание, что здесь используется "жадная загрузка" (eager loading), т.к. мы вызываем метод Include(). Это означает, что помимо данных покупателя, будут извлечены все данные связанных с ним заказов. Фактически каскадное удаление в данном случае не нужно, т.к. мы уже извлекли все связанные заказы.
Модель данных на текущий момент выглядит следующим образом:
Запустите наш пример и откройте в браузере веб-форму CascadeDelete.aspx и щелкните по кнопке “Сохранить”. Entity Framework воссоздаст базу данных (если модель изменилась) и добавит новые данные в таблицы Customers и Orders. Чтобы в этом убедиться, используйте средства Visual Studio или SQL Server Management Studio для просмотра данных:
Нажмите на кнопку “Удалить”, чтобы убедиться, что данные покупателя и связанные с ним заказы удаляются корректно. При этом Entity Framework отправит четыре запроса DELETE базе данных (три для каждого заказа и один для покупателя). Давайте теперь отключим использование жадной загрузки и явно используем каскадное удаление. Ниже показан измененный код обработчика Delete_Click:
Здесь мы удалили вызов метода Include() и теперь Code-First не известно о связанных с покупателем заказов. В отличие от предыдущего примера, здесь Entity Framework отправит один запрос DELETE для удаления покупателя. При выполнении этого запроса сработает средство каскадного удаления и SQL Server найдет связанные заказы, удалит сначала их, а уже потом удалит покупателя.
Добавление
Для добавления объекта используется метод Add , определенный у класса DbSet, в который передается добавляемый объект:
Метод Add устанавливает значение Added в качестве состояния нового объекта. Поэтому метод db.SaveChanges() сгенерирует выражение INSERT для вставки модели в таблицу.
Если нам надо добавить сразу несколько объектов, то мы можем воспользоваться методом AddRange() :
Когда происходит каскадная реакция на события
Каскадное удаление требуется в тех случаях, когда зависимая или дочерняя сущность теряет связь со своей текущей основной или родительской сущностью. Это может произойти в результате удаления основной или родительской сущности, а также в случае разрыва связи между ней и зависимой или дочерней сущностью.
Каскадное удаление в базе данных
Многие системы баз данных также реализуют каскадную реакцию на события, которая активируется при удалении сущности в базе данных. EF Core определяет конфигурацию такой реакции на основе настроек каскадного удаления в модели EF Core при создании базы данных с использованием метода EnsureCreated или миграций EF Core. Например, в представленной выше модели при использовании SQL Server для записей создается следующая таблица.
Обратите внимание, что ограничение внешнего ключа, определяющее связь между блогами и записями, настраивается с использованием ON DELETE CASCADE .
Если мы знаем, что база данных настроена таким образом, можно удалить блог без предварительной загрузки записей. В этом случае база данных автоматически удалит все связанные с ним записи. Пример:
e.Name).First(); context.Remove(blog); context.SaveChanges(); -->
Обратите внимание, что для записей не используется Include , поэтому они не загружаются. В этом случае метод SaveChanges удаляет только блог, поскольку это единственная отслеживаемая сущность.
Если ограничение внешнего ключа в базе данных не настроено для каскадного удаления, это приведет к возникновению исключения. Тем не менее в этом случае записи будут удалены базой данных, так как при ее создании была задана настройка ON DELETE CASCADE .
Как правило, базы данных не поддерживают автоматическое удаление потерянных объектов. Это связано с тем, что в базах данных используются только внешние ключи и нет свойств навигации, тогда как в EF Core связи представляются с использованием и внешних ключей, и свойств навигации. Это значит, что в большинстве случаев для разрыва связи обе ее стороны должны быть загружены в DbContext.
Выполняющаяся в памяти база данных EF Core в настоящее время не поддерживает каскадное удаление в базе данных.
Не следует настраивать каскадное удаление в базе данных при обратимом удалении сущностей. Это может привести к случайному полному (вместо обратимого) удалению сущностей.
Удаление
Удаление производится с помощью метода Remove :
Данный метод установит статус объекта в Deleted, благодаря чему Entity Framework при выполнении метода db.SaveChanges() сгенерирует SQL-выражение DELETE.
Если необходимо удалить сразу несколько объектов, то можно использовать метод RemoveRange() :
Разрыв связи
Вместо удаления блога можно разорвать связь между ним и каждой его записью. Это можно сделать, установив значение NULL для свойства навигации по ссылке Post.Blog для каждой записи:
e.Name).Include(e => e.Posts).First(); foreach (var post in blog.Posts) < post.Blog = null; >context.SaveChanges(); -->
Связь также можно разорвать, удалив каждую запись из свойства навигации по коллекции Blog.Posts .
e.Name).Include(e => e.Posts).First(); blog.Posts.Clear(); context.SaveChanges(); -->
В обоих случаях будет достигнут одинаковый результат, то есть записи, которые больше не связаны ни с одним блогом, удаляются, а сам блог остается.
Удаление сущностей, которые больше не связаны ни с одной основной или родительской сущностью, называется удалением потерянных объектов.
Концепции каскадного удаления и удаления потерянных объектов тесно взаимосвязаны. В обоих случаях при разрыве связи с основной или родительской сущностью ее зависимые и дочерние сущности удаляются. При каскадном удалении это происходит вследствие удаления самой основной или родительской сущности. При удалении потерянных объектов основная или родительская сущность по-прежнему существует, но при этом больше не связана с зависимыми и дочерними сущностями.
Отключение каскадного удаления данных
Возможно вам понадобиться отключить использование каскадного удаления в базе данных. Как описывалось выше, чтобы сделать это, можно удалить явное определение первичного ключа из класса модели и положиться на автоматическую генерацию первичного ключа с помощью Code-First (при этом Code-First указывает поддержку NULL для этого ключа). Также можно воспользоваться средствами Fluent API для явного отключения каскадного удаления, если, например, требуется сохранить объявление первичного ключа в классе модели.
Важно помнить, что при отключении каскадного удаления в вашем приложении могут возникать ошибки, если вы не позаботитесь об извлечении связанных данных перед удалением, как мы это делали в первом примере с использованием “жадной загрузки”.
Отключить или включить каскадное удаление в Fluent API позволяет метод WillCascadeOnDelete(), которому передается логический параметр. Использование этого метода показано в примере ниже:
Если вы запустите приложение и попробуете удалить данные, используя второй пример обработчика Delete_Click, то возникнет исключение, показанное на рисунке ниже:
Как уже описывалось ранее, при удалении данных из родительской таблицы, необходимо позаботиться об удалении данных из производной таблицы. Мы забыли извлечь данные связанных заказов из таблицы Orders и поэтому SQL Server вернул ошибку при попытке удаления данных только покупателя. Если вы теперь включите “жадную загрузку” с помощью метода Include() в обработчике Delete_Click, то эта ошибка исчезнет, но возникнет новая – как описывалось выше, в этом случае Code-First отправит четыре запроса на удаление и при удалении первого заказа Code-First установит для свойства Order.Customer значение NULL, а т.к. наша модель содержит внешний ключ, который не может иметь значение NULL возникнет ошибка.
Из этого описания можно сделать вывод, что для данного примера отключение каскадного удаления нельзя применить, но тогда возникает вопрос, зачем вообще отменять каскадное удаление? По своему опыту скажу, что отключение каскадного удаления используется в основном при получении циклической ссылки между таблицами в сложных базах данных. Такая ссылка может возникнуть, если между несколькими таблицами используется отношение “родительская-дочерняя” и последняя зависимая таблица неожиданно ссылается на одну из родительских таблиц. Проблема циклических ссылок проявляется не только при удалении данных, а также при их обновлении (операция UPDATE в T-SQL).
Также отключение каскадного удаления требуется для таблиц, которые определяют несколько отношений между собой. Некоторые базы данных (в том числе SQL Server) не поддерживают несколько отношений, которые определяют каскадное удаление, указываемое на одной таблице.
Большинство операций с данными так или иначе представляют собой CRUD операции (Create, Read, Update, Delete), то есть создание, получение, обновление и удаление. Entity Framework Core позволяет легко выполнять все эти действия.
Затем добавим в проект класс User, объекты которого будут храниться в базе данных:
И добавим класс контекста данных ApplicationContext:
Далее в файле Program.cs определим все базовые операции с данными:
И после выполнения мы получим следующий консольный вывод:
Ограничения для каскадной реакции на события в базе данных
Некоторые базы данных, особенно SQL Server, устанавливают ограничения для каскадных операций, которые приводят к возникновению циклов. Рассмотрим следующую модель.
В этой модели устанавливаются три связи, каждая из которых является обязательной и по соглашению настраивается для каскадного удаления.
- При удалении блога происходит каскадное удаление всех связанных с ним записей.
- При удалении автора записей происходит каскадное удаление созданных им записей.
- При удалении владельца блога происходит каскадное удаление самого блога.
Это вполне разумный, хотя и достаточно строгий подход к управлению блогом. Тем не менее при попытке создать базу данных SQL Server с этими настройками каскадной реакции на событий возникнет следующее исключение.
Microsoft.Data.SqlClient.SqlException (0x80131904): Введение ограничения внешнего ключа (FOREIGN KEY) FK_Posts_Person_AuthorId для таблицы Posts может привести к появлению циклов или множественных каскадных путей. Укажите ON DELETE NO ACTION или ON UPDATE NO ACTION либо измените другие ограничения внешнего ключа (FOREIGN KEY).
Эту проблему можно решить двумя способами.
- Изменить одну связь или несколько, отключив их каскадное удаление.
- Настроить базу данных, отключив одно или несколько из этих действий каскадного удаления, после чего убедиться, что все зависимые сущности загружены, чтобы позволить EF Core реализовывать каскадную реакцию на события.
Применение первого подхода в нашем примере позволяет сделать связь между блогом и его владельцем необязательной, предоставив свойство внешнего ключа, допускающее значение NULL.
Поскольку эта связь не является обязательной, блог может существовать без владельца, то есть каскадное удаление больше не будет настроено по умолчанию. Это значит, что каскадная реакция на события больше не будет приводить к возникновению циклов, благодаря чему база данных может быть создана в SQL Server без ошибок.
Если использовать второй подход, связь между блогом и владельцем можно оставить обязательной и настроить для каскадного удаления, но при этом задать применение этой конфигурации только к отслеживаемым сущностям, а не к базе данных.
() .HasOne(e => e.Owner) .WithOne(e => e.OwnedBlog) .OnDelete(DeleteBehavior.ClientCascade); > -->
Что произойдет, если загрузить владельца блога и сам блог, а затем удалить владельца?
e.Name == "ajcvickers"); var blog = context.Blogs.Single(e => e.Owner == owner); context.Remove(owner); context.SaveChanges(); -->
EF Core выполнит каскадное удаление владельца и принадлежащего ему блога.
Тем не менее, если блог не был загружен, при удалении его владельца происходит следующее.
e.Name == "ajcvickers"); context.Remove(owner); context.SaveChanges(); -->
После этого возникает исключение из-за нарушения ограничения внешнего ключа в базе данных.
Microsoft.Data.SqlClient.SqlException: Конфликт инструкции DELETE с ограничением REFERENCE FK_Blogs_People_OwnerId. Конфликт произошел в базе данных Scratch, таблица dbo.Blogs, столбец OwnerId. Выполнение данной инструкции было прервано.
Каскадное удаление отслеживаемых сущностей
EF Core всегда применяет к отслеживаемым сущностям каскадную реакцию на события. Это значит, что, если приложение загружает все соответствующие зависимые или дочерние сущности в DbContext (как показано в приведенных выше примерах), каскадная реакция на события будет корректно применяться, независимо конфигурации базы данных.
Точное время, когда происходит каскадная реакция для отслеживаемых сущностей, можно контролировать с помощью свойств ChangeTracker.CascadeDeleteTiming и ChangeTracker.DeleteOrphansTiming. Дополнительные сведения см. в разделе Изменение внешних ключей и свойств навигации.
Где происходит каскадная реакция на события
Каскадная реакция на события может применяться к следующим сущностям.
- Сущности, которые отслеживаются текущим экземпляром DbContext.
- Сущности в базе данных, которые не были загружены в контекст.
Редактирование
При изменении объекта Entity Framework сам отслеживает все изменения, и когда вызывается метод SaveChanges() , будет сформировано SQL-выражение UPDATE для данного объекта, которое обновит объект в базе данных.
Но надо отметить, что в данном случае действие контекста данных ограничивается пределами конструкции using, которая определяет область действия объекта ApplicationContext. Но рассмотрим другой пример. Мы получаем объект в одном месте,а обновляем в другом. Например:
Несмотря на то, что объект user не равен null, имеется в базе данных, но во втором блоке using обновления соответствующего объекта в БД не произойдет. Потому что объект User больше не отслеживается контекстом данных. И в этом случае во второй конструкции using, где происходит редактирование, нам надо использовать метод Update:
При необходимости обновить одновременно несколько объектов, применяется метод UpdateRange() :
Удаление основной или родительской сущности
Рассмотрим простую модель, в которой Blog является основной или родительской сущностью в связи с дочерней или зависимой сущностью Post . В качестве внешнего ключа используется свойство Post.BlogId , значение которого должно соответствовать первичному ключу Blog.Id блога, которому принадлежит запись.
По соглашению эта связь настроена как обязательная, поскольку свойство внешнего ключа Post.BlogId не допускает значения NULL. Для обязательных связей по умолчанию используется каскадное удаление. Дополнительные сведения о моделировании связей см. в разделе Связи.
При удалении блога происходит каскадное удаление всех его записей. Пример:
e.Name).Include(e => e.Posts).First(); context.Remove(blog); context.SaveChanges(); -->
Метод SaveChanges создает следующий код SQL (на примере SQL Server).
Удаление связанных объектов
Удаление сущностного объекта в Entity Framework приводит к удалению автоматически связанных с ним объектом. При удалении сущностного объекта, имеющего связанные с ним объекты, следует проявлять осторожность: в зависимости от схемы базы данных, могут либо появиться "висячие" данные (данные, внешний ключ которых ссылается на более несуществующий первичный ключ), либо произойти исключение о нарушении ограничения схемы.
Ниже демонстрируется то, что случится, когда объект удаляется без обработки связанных с ним объектов. В данном случае предпринимается попытка удалить сущностный объект Order:
Компиляция и запуск этого кода приведет к генерации следующего исключения:
Что же произошло? Было нарушено ограничение схемы базы данных. Исключение сообщает о том, что в таблице Order Details имеется ограничение по имени FK Order Details_Orders. Опция Enforce Foreign Key Constraint (Навязывать ограничение внешнего ключа) установлена в Yes (Да), а это означает, что удалить Order не получится, пока есть связанные с ним записи в таблице Order Details.
Существуют два подхода к безопасному удалению связанных объектов. Это можно сделать вручную или воспользоваться каскадным удалением в базе данных, и тогда сущностная модель данных обработает их автоматически. Мы предпочитаем автоматический подход, но поскольку бывают случаи, когда невозможно модифицировать схему базы данных, приходится применять ручной подход. Ниже продемонстрированы оба метода.
Удаление
Удаление производится с помощью метода Remove :
Данный метод установит статус объекта в Deleted, благодаря чему Entity Framework при выполнении метода db.SaveChanges() сгенерирует SQL-выражение DELETE.
Если необходимо удалить сразу несколько объектов, то можно использовать метод RemoveRange() :
Влияние на схему базы данных
В следующей таблице показан результат применения каждого значения метода OnDelete для ограничения внешнего ключа, создаваемого с помощью миграций EF Core или метода EnsureCreated.
Значение перечисления DeleteBehavior | Влияние на схему базы данных |
---|---|
Cascade | ON DELETE CASCADE |
Ограничение | ON DELETE RESTRICT |
NoAction | database default |
SetNull | ON DELETE SET NULL |
ClientSetNull | database default |
ClientCascade | database default |
ClientNoAction | database default |
Действия ON DELETE NO ACTION (база данных по умолчанию) и ON DELETE RESTRICT в реляционных базах данных, как правило, идентичны или очень близки. Несмотря на название NO ACTION , оба эти параметра приводят к принудительному применению ссылочных ограничений. Единственное различие между ними заключается в том, когда база данных выполняет проверку ограничений. Сведения о конкретных различиях между параметрами ON DELETE NO ACTION и ON DELETE RESTRICT в вашей системе базы данных следует искать в документации по ней.
SQL Server не поддерживает ON DELETE RESTRICT , поэтому используйте ON DELETE NO ACTION .
Каскадная реакция на события в базе данных реализуется только при использовании значений Cascade и SetNull . При любых других значениях каскадное распространение изменений в базе данных не осуществляется.
Асинхронный API
Вместо метода SaveChanges() для асинхронного выполнения зароса к бд можно использовать его асинхронный двойник - SaveChangesAsync() . Также, для добавления данных определены асинхронные методы AddAsync и AddRangeAsync . Пример применения асинхронного API:
Большинство операций с данными так или иначе представляют собой CRUD операции (Create, Read, Update, Delete), то есть создание, получение, обновление и удаление. Entity Framework Core позволяет легко выполнять все эти действия.
Затем добавим в проект класс User, объекты которого будут храниться в базе данных:
И добавим класс контекста данных ApplicationContext:
Далее определим в классе Program все базовые операции с данными:
И после выполнения мы получим следующий консольный вывод:
Каскадное распространение значений NULL
Для необязательных связей свойства внешнего ключа, допускающие значения NULL, сопоставлены со столбцами базы данных, также допускающими такие значения. Это означает, что внешнему ключу может быть присвоено значение NULL, если текущая основная или родительская сущность удаляется или разрывается ее связь с зависимой или дочерней сущностью.
Еще раз возьмем примеры из раздела Когда происходит каскадная реакция на события. На этот раз рассмотрим необязательную связь, которая представлена допускающим значение NULL свойством внешнего ключа Post.BlogId :
Этому свойству внешнего ключа будет присваиваться значение NULL для каждой записи при удалении связанного с ней блога. Например, следующий код аналогичен приведенному ранее.
e.Name).Include(e => e.Posts).First(); context.Remove(blog); context.SaveChanges(); -->
Тем не менее теперь при вызове метода SaveChanges будут выполнены следующие обновления базы данных.
Аналогичным образом, при разрыве связи в любом из приведенных выше примеров:
e.Name).Include(e => e.Posts).First(); foreach (var post in blog.Posts) < post.Blog = null; >context.SaveChanges(); -->
Или сделайте так:
e.Name).Include(e => e.Posts).First(); blog.Posts.Clear(); context.SaveChanges(); -->
При вызове метода SaveChanges записи будут обновлены с присвоением внешнему ключу значения NULL.
Дополнительные сведения о том, как EF Core управляет внешними ключами и свойствами навигации при изменении их значений, см. в разделе Изменение внешних ключей и свойств навигации.
По умолчанию, начиная с первой версии Entity Framework 2008 года, выполнялась адресная привязка таких связей. До появления EF Core у такого подхода не было своего названия и его нельзя было изменить. Сейчас он называется ClientSetNull и описывается в следующем разделе.
Базы данных также можно настроить для подобного каскадного распространения значений NULL при удалении основной или родительской сущности в необязательной связи. Тем не менее этот подход применяется гораздо реже операций каскадного удаления в базе данных. Одновременное выполнение каскадного удаления и каскадного распространения значений NULL в базе данных SQL Server почти всегда будет приводить к возникновению циклов связей. Дополнительные сведения о настройке каскадного распространения значений NULL см. в следующем разделе.
Влияние на поведение метода SaveChanges
В следующих разделах приводятся таблицы, в которых описывается, что происходит с зависимыми или дочерними сущностями при удалении основной или родительской сущности, а также при разрыве ее связи с зависимой или дочерней сущностью. Каждая таблица описывает одну из следующих ситуаций.
Чтобы удалить запись из базы данных, необходимо просто передать сущностный объект, представляющий эту запись, в качестве аргумента методу DeleteObject. Пример использования этого метода приведен в примере ниже:
В этом коде запрашиваются все сущностные объекты Order_Detail со значением OrderID, равным 10248. Затем с помощью метода First первый из них выбирается и передается в качестве аргумента методу ObjectContext.DeleteObject. Для сохранения изменений вызывается метод ObjectContext.SaveChanges, который отправляет команду удаления в базу данных.
Класс EntitySet также имеет метод DeleteObject, а это значит, что можно получить тот же эффект, что и в предыдущем примере, с использованием сущностного объекта, представляющего таблицу, из которой нужно удалить запись:
В этом коде выполняется тот же запрос, что и в предыдущем примере, но здесь используется метод EntitySet.DeleteObject. Компиляция и запуск кода этих примеров даст одинаковый результат:
Редактирование
При изменении объекта Entity Framework сам отслеживает все изменения, и когда вызывается метод SaveChanges() , будет сформировано SQL-выражение UPDATE для данного объекта, которое обновит объект в базе данных.
Но надо отметить, что в данном случае действие контекста данных ограничивается пределами конструкции using. Но рассмотрим другой пример. Мы получаем объект в одном месте,а обновляем в другом. Например:
Несмотря на то, что объект user не равен null, имеется в базе данных, но во втором блоке using обновления соответствующего объекта в БД не произойдет. И в этом случае нам надо использовать метод Update:
При необходимости обновить одновременно несколько объектов, применяется метод UpdateRange() :
Читайте также: