How to: Change Relationships Between Objects (Entity Framework)

This topic shows how to use the EntityReference object to change a relationship between two objects in the object context. When the SaveChanges method is called, the relationship change is persisted to the database as a change to the foreign key in the related table. This topic also shows how to handle the AssociationChanged event. This event provides a way to raise the PropertyChanged event when an association is changed.

The example in this topic is based on the Adventure Works Sales Model. To run the code in this example, you must have already added the AdventureWorks Sales Model to your project and configured your project to use the Entity Framework. To do this, complete the procedures in How to: Manually Configure an Entity Framework Project and How to: Manually Define an Entity Data Model (Entity Framework). You must also add the following using statement (Imports in Visual Basic) to your code:

using System.ComponentModel;

Example

This example shows how to use the EntityReference object to change a relationship between a SalesOrderHeader object and a related Address object that represents the shipping address for the order.


// Define the order and new address IDs.
int orderId = 43669;
int newAddressId = 26;

using (AdventureWorksEntities context 
    = new AdventureWorksEntities())
{
    try
    {
        // Get the billing address to change to.
        Address newAddress = context.Address
            .Where("it.AddressID = @addressId",
            new ObjectParameter("addressId", newAddressId))
            .First();

        // Get the order being changed.
        SalesOrderHeader order = context.SalesOrderHeader
            .Where("it.SalesOrderID = @orderId",
            new ObjectParameter("orderId", orderId)).First();

        // Load the current billing address.
        if (!order.Address1Reference.IsLoaded)
        {
            order.Address1Reference.Load();
        }

        // Write the current billing street address.
        Console.WriteLine("Current street: " 
            + order.Address1.AddressLine1);

        // Change the billing address.
        if (!order.Address1.Equals(newAddress))
        {
            order.Address1 = newAddress;

            // Write the changed billing street address.
            Console.WriteLine("Changed street: "
                + order.Address1.AddressLine1);
        }
        
        // If the address change succeeds, save the changes.
        context.SaveChanges();

        // Write the current billing street address.
        Console.WriteLine("Current street: "
            + order.Address1.AddressLine1);
    }
    catch (ApplicationException ex)
    {
        // Handle the exception raised in the ShippingAddress_Changed 
        // handler when the status of the order prevents the 
        // shipping address from being changed. Don't retry because
        // the relationship is in an inconsistent state and calling 
        // SaveChanges() will result in an UpdateException.
        Console.WriteLine(ex.ToString());
    }
    catch (InvalidOperationException ex)
    {
        Console.WriteLine(ex.ToString());
    }
}

This example extends the previous example and shows how to check the order status when the shipping address is changed by handling the AssociationChanged event on the EntityReference for the Address object that represents the shipping address. If the order status is greater than 3, the order cannot be changed and an exception is raised. The delegate is defined in the constructor for the SalesOrderHeader partial class, and the handler for this event is also implemented in this partial class. This ensures that the order status is checked whenever the shipping address is changed for an order.

The OnPropertyChanging and OnPropertyChanged methods are also called to raise the PropertyChanging and PropertyChanged events, respectively. These events notify client controls of the association changes.

To validate changes at the other end of the SalesOrderHeader-Address relationship, a similar technique could be used to register the AssociationChanged event on the EntityCollection of SalesOrderHeader objects related to a shipping address.

public partial class SalesOrderHeader
{
    // SalesOrderHeader default constructor.
    public SalesOrderHeader()
    {
        // Register the handler for changes to the 
        // shipping address (Address1) reference.
        this.Address1Reference.AssociationChanged
            += new CollectionChangeEventHandler(ShippingAddress_Changed);
    }

    // AssociationChanged handler for the relationship 
    // between the order and the shipping address.
    private void ShippingAddress_Changed(object sender,
        CollectionChangeEventArgs e)
    {
        // Check for a related reference being removed. 
        if (e.Action == CollectionChangeAction.Remove)
        {
            // Check the order status and raise an exception if 
            // the order can no longer be changed.
            if (this.Status > 3)
            {
                throw new ApplicationException(
                    "The shipping address cannot "
                + "be changed because the order has either "
                + "already been shipped or has been cancelled.");
            }
            // Call the OnPropertyChanging method to raise the PropertyChanging event.
            // This event notifies client controls that the association is changing.
            this.OnPropertyChanging("Address1");
        }
        else if (e.Action == CollectionChangeAction.Add)
        {
            // Call the OnPropertyChanged method to raise the PropertyChanged event.
            // This event notifies client controls that the association has changed.
            this.OnPropertyChanged("Address1");
        }            
    }
}

See Also

Community Additions

Show: