Cómo cambiar las relaciones entre objetos (Entity Framework)

En este tema se muestra cómo utilizar el objeto EntityReference para cambiar una relación entre dos objetos en el contexto del objeto. Cuando se llama al método SaveChanges, el cambio de relaciones se conserva en la base de datos como un cambio en la clave externa de la tabla relacionada. También se muestra cómo controlar el evento AssociationChanged.

El ejemplo de este tema se basa en el modelo AdventureWorks Sales. Para ejecutar el código de este ejemplo, debe haber agregado el modelo AdventureWorks Sales al proyecto y haber configurado el proyecto para usar Entity Framework. Para ello, complete los procedimientos de Cómo configurar manualmente un proyecto de Entity Framework y Cómo definir manualmente un modelo Entity Data Model (Entity Framework). También debe agregar la siguiente instrucción using (Imports en Visual Basic) al código:

Imports System.ComponentModel
using System.ComponentModel;

Ejemplo

En este ejemplo se muestra cómo utilizar el objeto EntityReference para cambiar una relación entre un objeto SalesOrderHeader y un objeto Address relacionado que representa la dirección de envío del pedido.

'Define the order and new address IDs.
Dim orderId As Integer = 43669
Dim newAddressId As Integer = 26

Using context As New AdventureWorksEntities()
    Try
        ' Get the billing address to change to.
        Dim newAddress As Address = context.Address _
            .Where("it.AddressID = @addressId", _
            New ObjectParameter("addressId", newAddressId)) _
        .First()

        ' Get the order being changed.
        Dim order As SalesOrderHeader = context.SalesOrderHeader _
            .Where("it.SalesOrderID = @orderId", _
            New ObjectParameter("orderId", orderId)).First()

        ' Load the current billing address.
        If Not order.Address1Reference.IsLoaded Then
            order.Address1Reference.Load()
        End If

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

        ' Change the billing address.
        If Not order.Address1.Equals(newAddress) Then
            order.Address1 = newAddress

            ' Write the changed billing street address.
            Console.WriteLine("Changed street: " _
                + order.Address1.AddressLine1)
        End If

        ' If the address change succeeds, save the changes.
        context.SaveChanges()

        ' Write the current billing street address.
        Console.WriteLine("Current street: " _
            + order.Address1.AddressLine1)
    Catch ex As ApplicationException
        ' 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 ex As InvalidOperationException
        Console.WriteLine(ex.ToString())
    End Try
End Using
// 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());
    }
}

Este ejemplo amplía el ejemplo anterior y muestra cómo comprobar el estado del pedido cuando la dirección de envío se cambia controlando el evento AssociationChanged en EntityReference para el objeto Address que representa la dirección de envío. Si el estado del pedido es mayor que 3, no se puede cambiar el pedido y se produce una excepción. El delegado se define en el constructor para la clase parcial SalesOrderHeader y el controlador para este evento también se implementa en esta clase parcial. De esta forma se garantiza que el estado del pedido se comprueba siempre que la dirección de envío se cambia para un pedido.

Para validar los cambios en el otro extremo de la relación SalesOrderHeader-Address, se puede usar una técnica similar para registrar el evento AssociationChanged en el elemento EntityCollection de los objetos SalesOrderHeader relacionados con una dirección de envío.

Partial Public Class SalesOrderHeader
    ' SalesOrderHeader default constructor.
    Public Sub New()
        ' Register the handler for changes to the 
        ' shipping address (Address1) reference.
        AddHandler Me.Address1Reference.AssociationChanged, _
        AddressOf ShippingAddress_Changed
    End Sub

    ' AssociationChanged handler for the relationship 
    ' between the order and the shipping address.
    Private Sub ShippingAddress_Changed(ByVal sender As Object, _
        ByVal e As CollectionChangeEventArgs)
        ' Check for a related reference being removed. 
        If e.Action = CollectionChangeAction.Remove Then
            ' Check the order status and raise an exception if 
            ' the order can no longer be changed.
            If Me.Status > 3 Then
                Throw New ApplicationException( _
                    "The shipping address cannot " _
                + "be changed because the order has either " _
                + "already been shipped or has been cancelled.")
            End If
        End If
    End Sub
End Class
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.");
            }
        }
    }
}

Vea también

Otros recursos

Trabajar con objetos (tareas de Entity Framework)