Adding, Modifying, and Deleting Objects (Entity Framework)

Objects in an object context are instances of entity types that represent data in the data source. You can modify, create, and delete objects in an object context, and Object Services tracks the changes made to these objects. When the SaveChanges method is called, Object Services generates and executes commands that perform the equivalent insert, update, or delete statements against the data source. For more information, see Saving Changes and Managing Concurrency (Entity Framework).

For example, suppose you execute a query that returns a SalesOrderHeader object and a collection of related SalesOrderDetail objects. You could enumerate through the collection and perform the following operations:

  • Change the ShipDate property of an order.

  • Delete a specific item by calling the DeleteObject method.

  • Add a line item to the order by calling the Add method.

  • Call the SaveChanges method on the object context to save the object changes back to the data source.

The following example shows various changes to objects in an object context:

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 = 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();

Adding Objects

When you want to insert data in the data source, you must create an instance of an entity type and add the object to an object context. Before you can add a new object, you must first set all properties that do not support null values. Consider using the entity type's static CreateObjectName method to create a new instance of an entity type. The Entity Data Model tools include this method in each class when they generate the entity types. This create method is used to create an instance of an object and set all the properties of the class that cannot be null. The method includes a parameter for every property that has the Nullable="false" attribute applied in the CSDL file.

The following example uses the static CreateSalesOrderHeader method to create a new instance of the SalesOrderHeader class.

' 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);

For more information, see How to: Create an Object Using the Static Create Method (Entity Framework).

You can add new objects to an object context by calling the AddObject method or by calling one of the AddToEntitySetName methods on the typed ObjectContext. You can also add an object to an object context by adding it to an existing EntityCollection. When you call the Add method on an EntityCollection that is attached to an object context, the object you are adding is added to the same ObjectContext. In a similar way, you can add an object by setting the new object instance to the Value of an EntityReference.

Navigation properties define relationships between objects. We recommend that you set these properties when the object is related to other objects in the object context. For example, set the SalesOrderHeader relationship property of a new SalesOrderDetail object to the instance of the order to which the line item belongs. When you create a new object that is related to another object in the object context, add the object by using one of the following methods:

  • For a one-to-many or many-to-many relationship, call Add on EntityCollection and specify the related object.

  • For a one-to-one or many-to-one relationship, set the Value property of EntityReference to the related object.

  • Call the AddObject method to add the new object to the object context, and then define the relationship using one of the previous two methods.

The following considerations apply when adding new objects:

  • Before SaveChanges is called, Object Services generates a temporary key value for every new object that is added using the AddObject method. After SaveChanges is called, the key value is replaced by the identity value assigned by the data source when a new row is inserted.

  • If the key value of an entity is not generated by the data source, you should assign a unique value. If two objects have the same user-specified key value, an InvalidOperationException occurs when SaveChanges is called. If this occurs, you should assign unique values and retry the operation.

  • The Entity Framework automatically sets foreign key values in the data source when you define a relationship between objects and call SaveChanges. However, when an entity is mapped to stored procedures that perform inserts, update, and deletes, foreign key values are not automatically set. In this case, you must correctly set the properties that correspond to foreign key to the correct values for the related object. For more information, see Stored Procedure Support (Entity Framework).

Modifying Objects

When you change a scalar, complex, or navigation property of an object and call SaveChanges, updates are sent to the data source. You change relationships between objects by changing navigation properties, such as changing the value of an EntityReference or removing an object from an EntityCollection. For more information, see How to: Change Relationships Between Objects (Entity Framework).

Object Services tracks changes to objects that are attached to an ObjectContext using an instance of IEntityChangeTracker. There is one instance of IEntityChangeTracker for each object being tracked. Queries return objects in an Unchanged state, unless the query is using a MergeOption set to NoTracking. The Entity Data Model tools generate calls to change tracking methods in the property setter of each property of an entity type, as in the following example in the property setter of the Status property in the SalesOrderHeader class.

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();
}

The ReportPropertyChanging method and the ReportPropertyChanged method report the property changes to the IEntityChangeTracker. If you are using custom data classes with an Entity Data Model (EDM), you should also report property changes to enable tracking by Object Services. For more information, see Reporting Changes in Custom Data Classes (Entity Framework).

The state of an object is changed from Unchanged to Modified whenever a property setter is called. This occurs even when the value being set is the same as the current value. After the AcceptAllChanges method is called, the state is returned to Unchanged. By default, AcceptAllChanges is called during the SaveChanges operation.

The Entity Data Model tools also generate a pair of partial methods named OnPropertyChanging and OnPropertyChanged. These methods are called in the property setter. Extend these methods in partial classes to insert custom business logic during property changes. For more information, see How to: Execute Business Logic During Property Changes (Entity Framework).

The following considerations apply when modifying objects:

  • When any scalar or complex property of a complex object is changed, the state of the top-level entity object is changed to Modified.

  • Changes are not tracked when objects are in a Detached state. Objects are in this state when returned by a query that uses the NoTracking merge option or after being detached from an ObjectContext by calling Detach.

  • You can change a relationship between two objects by assigning the EntityReference value to a new object. In this case, the Entity Framework automatically updates foreign key values in the data source when you call SaveChanges. However, when an entity is mapped to stored procedures that perform inserts, update, and deletes, foreign key values are not automatically updated. In this case, you must correctly set the properties that correspond to foreign key to the correct values for the new relationship. For more information, see Stored Procedure Support (Entity Framework).

Deleting Objects

Calling the DeleteObject method on the ObjectContext marks the specified object for deletion. The row is not deleted from the data source until after SaveChanges is called.

The following considerations apply when deleting objects:

  • When an object is deleted, any relationships to other objects are also deleted.

  • When two objects are in a constrained relationship, deleting the parent object also deletes all child objects. This result is the same as enabling the CascadeDelete property on the association for the relationship. For more information, see Referential Constraints (Entity Framework).

  • When an object that is returned by a query is related to one or more other objects, the query always returns some information about those related objects so that it is easier to delete objects. In some cases, this existing information can cause an UpdateException to occur when you attempt to delete an object. For example, you will receive this exception when the association that defines the relationship has the <OnDelete Action="Cascade" /> element specified in the parent End of the Association. When this occurs, explicitly load the related object before you call the DeleteObject method.

  • You can call the DeleteObject method again for an object that has already been deleted.

For more information, see How to: Add, Modify, and Delete Objects (Entity Framework).

Creating Objects in a Specific EntitySet

There might be situations when an entity type belongs to multiple entity sets. For example, consider a situation where a database has two tables with identical schemas. This might be the case if you want to partition the data to produce a more efficient backup process. For example, you might have customer data partitioned between Customer and CustomerArchive tables, where CustomerArchive has the same schema as Customer but is used for customers who have not placed orders for more than six months. Customer might be backed up nightly, while CustomerArchive is only backed up weekly. From a mapping perspective, Customer and CustomerArchive must belong to different entity sets. The Entity Framework supports this scenario by letting an entity type exist in one or more entity sets. For more information, see Entity Sets (EDM).

When an entity type exists in multiple entity sets, Object Services enables you to add new instances of the type to a specific entity set. To do this, you must specify the value of entitySetName when you call the AddObject method to add the object to the object context. For more information, see How to: Add an Object to a Specific Entity Set (Entity Framework).

The Entity Data Model tools also generate AddToEntitySetName methods on ObjectContext, with one method for each entity set that is defined in the conceptual model. These methods call AddObject and pass the EntitySetName value of the specific method. Use these methods to add objects in specific entity sets.

See Also

Tasks

How to: Define a Model with Multiple Entity Sets per Type (Entity Framework)