Добавление, изменение и удаление объектов (платформа Entity Framework)

Объекты в контексте объекта являются экземплярами типов сущностей, которые представляют данные в источнике данных. Можно изменять, создавать и удалять объекты в контексте объекта, а службы объектов отслеживают изменения, внесенные в эти объекты. При вызове метода SaveChanges службы объектов создают и выполняют команды, которые проводят эквивалентные операции вставки, изменения или удаления в источнике данных. Дополнительные сведения см. в разделе Сохранение изменений и управление параллелизмом (платформа Entity Framework).

Например, предположим, выполняется запрос, который возвращает объект SalesOrderHeader и коллекцию связанных объектов SalesOrderDetail. Можно перечислить все элементы этой коллекции и выполнить следующие операции.

  • Изменить свойство ShipDate заказа.

  • Удалить конкретный пункт заказа, вызвав метод DeleteObject.

  • Добавить пункт в заказ, вызвав метод Add.

  • Метод SaveChanges вызывается в контексте объекта, если нужно сохранить сделанные изменения в источнике данных.

В следующем примере кода показаны различные изменения объектов в контексте объекта:

Dim order As SalesOrderHeader = _
context.SalesOrderHeader.Where( _
        "it.SalesOrderID = @id", New ObjectParameter( _
         "id", orderId)).First()

' Change the status and ship date of an existing order.
order.Status = 1
order.ShipDate = DateAndTime.Today

' Load items for the order, if not already loaded.
If Not order.SalesOrderDetail.IsLoaded Then
    order.SalesOrderDetail.Load()
End If

' Delete the first item in the order.
context.DeleteObject(order.SalesOrderDetail.First())

' Create a new item using the static Create method
' and add it to the order.
order.SalesOrderDetail.Add( _
    SalesOrderDetail.CreateSalesOrderDetail( _
    1, 0, 2, 750, 1, CDec(2171.2942), 0, 0, Guid.NewGuid(), _
    DateAndTime.Today))

' Save changes in the object context to the database.
Dim changes As Integer = context.SaveChanges()
SalesOrderHeader order =
    context.SalesOrderHeader.Where
    ("it.SalesOrderID = @id", new ObjectParameter(
     "id", orderId)).First();

// Change the status and ship date of an existing order.
order.Status = 1;
order.ShipDate = DateTime.Today;

// Load items for the order, if not already loaded.
if (!order.SalesOrderDetail.IsLoaded)
{
    order.SalesOrderDetail.Load();
}

// Delete the first item in the order.
context.DeleteObject(order.SalesOrderDetail.First());

// Create a new item using the static Create method 
// and add it to the order.
order.SalesOrderDetail.Add(
    SalesOrderDetail.CreateSalesOrderDetail(0,
    0, 2, 750, 1, (decimal)2171.2942, 0, 0,
    Guid.NewGuid(), DateTime.Today));

// Save changes in the object context to the database.
int changes = context.SaveChanges();

Добавление объектов

Если нужно вставить данные в источник данных, необходимо создать экземпляр типа сущности и добавить объект в контекст объекта. Прежде чем добавить новый объект, необходимо установить все свойства, которые не поддерживают значения null. Попробуйте использовать статический метод CreateObjectName типа сущности для создания нового экземпляра типа сущности. Средства Entity Data Model включают этот метод в каждый класс при создании типов сущностей. Этот метод создания используется, чтобы создать экземпляр объекта и задать все свойства класса, которые не могут иметь значение null. В этом методе для каждого свойства имеется параметр, атрибут Nullable="false" которого применен в CSDL-файле.

В следующем примере метод CreateSalesOrderHeader используется для создания нового экземпляра класса SalesOrderHeader.

' Create a new SalesOrderHeader using the static 
' CreateSalesOrderHeader method.
Dim order As SalesOrderHeader = _
    SalesOrderHeader.CreateSalesOrderHeader( _
    1, Convert.ToByte(1), DateTime.Now, DateTime.Today.AddMonths(2), _
    Convert.ToByte(1), False, String.Empty, customer.ContactID, shipMethod, _
    0, 0, 0, 0, Guid.NewGuid(), DateTime.Now)
// Create a new SalesOrderHeader using the static 
// CreateSalesOrderHeader method.
SalesOrderHeader order = SalesOrderHeader.CreateSalesOrderHeader(0,
    Convert.ToByte(1), DateTime.Now, DateTime.Today.AddMonths(2),
    Convert.ToByte(1), false, string.Empty, customer.ContactID, shipMethod, 
    0, 0, 0, 0, Guid.NewGuid(), DateTime.Now);

Дополнительные сведения см. в разделе Как создать объект с помощью статического метода создания (платформа Entity Framework).

Можно добавить новые объекты в контекст объекта путем вызова метода AddObject, или вызывая один из методов AddToEntitySetName на типизированном классе ObjectContext. Можно также добавить объект к контексту объекта, добавляя его к существующему классу EntityCollection. При вызове метода Add класса EntityCollection, присоединенном к контексту объекта, добавляемый объект добавляется к тому же классу ObjectContext. Аналогично можно добавить объект, назначив новый экземпляр объекта для свойства Value класса EntityReference.

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

  • Для создания связи «один ко многим» или «многие ко многим» вызовите метод Add класса EntityCollection и укажите связанный объект.

  • Для создания связи «один к одному» или «многие к одному» установите свойство Value класса EntityReference на связанный объект.

  • Вызовите метод AddObject, чтобы добавить новый объект к контексту объекта, а затем определите связь с использованием одного из двух предыдущих методов.

При добавлении новых объектов следует принимать во внимание следующие соображения.

  • До вызова метода SaveChanges службы объектов создают временное значение ключа для каждого нового объекта, добавляемого с использованием метода AddObject. После вызова SaveChanges это значение ключа можно заменить значением идентификатора, которое присваивается источником данных при вставке новой строки.

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

  • Entity Framework автоматически задает значения внешних ключей в источнике данных при определении связи между объектами и вызове SaveChanges. Но когда сущность сопоставляется с хранимыми процедурами, которые выполняют вставки, обновления и удаления, значения внешних ключей не устанавливаются автоматически. В этом случае необходимо правильно установить свойства, которые сопоставляют внешнему ключу правильные значения для связанного объекта. Дополнительные сведения см. в разделе Поддержка хранимых процедур (платформа Entity Framework).

Изменение объектов

При изменении скалярного или сложного свойства, а также свойства навигации объекта и при вызове метода SaveChanges обновления пересылаются в источник данных. Связи между объектами изменяются путем изменения свойств навигации, в частности изменением значения EntityReference или удалением объекта из EntityCollection. Дополнительные сведения см. в разделе Как изменить связи между объектами (платформа Entity Framework).

Службы объектов отслеживают изменения объектов, присоединенных к классу ObjectContext с использованием экземпляра IEntityChangeTracker. Существует один экземпляр IEntityChangeTracker для каждого отслеживаемого объекта. Запросы возвращают объекты в состоянии Unchanged, кроме случаев, когда запрос использует объект MergeOption, установленный в состояние NoTracking. Средства Entity Data Model формируют вызовы для методов отслеживания изменений в методе задания свойств для каждого свойства типа сущности, как в следующем примере в методе задания свойств для свойства Status в классе SalesOrderHeader.

Set(ByVal value As Byte)
    Me.OnStatusChanging(value)
    Me.ReportPropertyChanging("Status")
    Me._Status = Global.System.Data.Objects.DataClasses.StructuralObject.SetValidValue(value)
    Me.ReportPropertyChanged("Status")
    Me.OnStatusChanged()
End Set
set
{
    this.OnStatusChanging(value);
    this.ReportPropertyChanging("Status");
    this._Status = global::System.Data.Objects.DataClasses.StructuralObject.SetValidValue(value);
    this.ReportPropertyChanged("Status");
    this.OnStatusChanged();
}

Метод ReportPropertyChanging и метод ReportPropertyChanged сообщают об изменении свойств в IEntityChangeTracker. Если применяются пользовательские классы данных с Entity Data Model (модель EDM), следует также сообщить об изменениях свойств, чтобы включить отслеживание службами объектов. Дополнительные сведения см. в разделе Отчеты об изменениях в пользовательских классах данных (платформа Entity Framework).

Состояние объекта изменяется с Unchanged на Modified при каждом вызове метода задания свойства. Это происходит, даже если задаваемое значение совпадает с текущим значением. После вызова метода AcceptAllChanges состояние возвращается в Unchanged. По умолчанию вызывается метод AcceptAllChanges во время операции SaveChanges.

Средства Entity Data Model создают два разделяемых метода OnPropertyChanging и OnPropertyChanged. Эти методы вызываются в методе задания свойства. Расширьте эти методы в разделяемых классах, чтобы вставить пользовательскую бизнес-логику во время изменения свойств. Дополнительные сведения см. в разделе Как выполнить бизнес-логику при изменении свойств (платформа Entity Framework).

Во время изменения объектов следует принимать во внимание следующие соображения.

  • При изменении любого скалярного или сложного свойства сложного объекта состояние объекта сущности верхнего уровня меняется на Modified.

  • Изменения не отслеживаются, когда объекты находятся в состоянии Detached. Объекты находятся в этом состоянии, если их вернул запрос, который использует параметр слияния NoTracking, а также после отсоединения от объекта ObjectContext путем вызова метода Detach.

  • Можно изменить связь между двумя объектами, назначив значение EntityReference новому объекту. В этом случае Entity Framework автоматически обновляет значения внешних ключей в источнике данных при вызове метода SaveChanges. Однако, когда сущность сопоставляется с хранимыми процедурами, которые выполняют вставки, обновления и удаления, значения внешних ключей не обновляются автоматически. В этом случае необходимо правильно установить свойства, которые сопоставляют внешнему ключу правильные значения для новой связи. Дополнительные сведения см. в разделе Поддержка хранимых процедур (платформа Entity Framework).

Удаление объектов

Вызов метода DeleteObject класса ObjectContext отмечает указанный объект для удаления. Строка не удаляется из источника данных, пока не будет вызван метод SaveChanges.

Во время удаления объектов следует принимать во внимание следующие соображения.

  • Когда объект удаляется, удаляются также любые связи с другими объектами.

  • Если между двумя объектами существует связь, к которой применяется ограничение, то удаление родительского объекта приводит к удалению всех дочерних объектов. Результат этого действия такой же, как включение свойства CascadeDelete ассоциации для связи. Дополнительные сведения см. в разделе Ссылочные ограничения (платформа Entity Framework).

  • Когда объект, возвращенный запросом, связан с одним или несколькими другими объектами, запрос всегда возвращает некоторые сведения о связанных объектах, чтобы упростить удаление объектов. В некоторых случаях существующие сведения могут привести к возникновению UpdateException при попытке удалить объект. Например, это исключение будет выдано, если ассоциация, которая определяет связь, имеет элемент <OnDelete Action="Cascade" /> в родительском элементе этой ассоциации. Если это происходит, явно загрузите связанный объект перед вызовом метода DeleteObject.

  • Метод DeleteObject можно вызвать снова для объекта, который уже был удален.

Дополнительные сведения см. в разделе Как добавить, изменить и удалить объекты (платформа Entity Framework).

Создание объектов в конкретном наборе EntitySet

В некоторых ситуациях тип сущности принадлежит нескольким наборам сущностей. Например, в базе данных имеются две таблицы с одинаковыми схемами. Это может случиться, если данные были секционированы для повышения эффективности резервного копирования. Например, можно секционировать данные заказчиков на две таблицы, Customer и CustomerArchive, где CustomerArchive имеет ту же схему, что и Customer, но хранит информацию о заказчиках, не размещавших заказов в течение последних 6 месяцев. Резервное копирование таблицы Customer нужно проводить раз в сутки, в то время как для таблицы CustomerArchive достаточно создавать резервную копию раз в неделю. С точки зрения сопоставления, таблицы Customer и CustomerArchive должны принадлежать различным наборам сущностей. Платформа Entity Framework поддерживает такой сценарий, допуская принадлежность типа сущности одному или нескольким наборам сущностей. Дополнительные сведения см. в разделе Наборы сущностей (модель EDM).

Если тип сущности принадлежит нескольким наборам сущностей, службы объектов позволяют добавлять новые экземпляры этого типа к конкретному набору сущностей. Для этого нужно указать имя набора сущностей entitySetName при вызове метода AddObject для добавления объекта к контексту объекта. Дополнительные сведения см. в разделе Как добавить объект к конкретному набору сущностей (платформа Entity Framework).

Средства Entity Data Model также формируют методы AddToEntitySetName в ObjectContext (по одному методу для каждого набора сущностей, определенного в концептуальной модели). Эти методы вызывают метод AddObject и передают значение EntitySetName конкретного метода. Используйте эти методы для добавления объектов в конкретные наборы сущностей.

См. также

Задачи

Как определить модель с несколькими наборами сущностей на тип (платформа Entity Framework)