Cómo ejecutar la lógica de negocios durante los cambios de propiedades (Entity Framework)

Entity Framework permite ejecutar una lógica de negocios propia personalizada para realizar acciones personalizadas cuando se realizan cambios en propiedades generadas. Las herramientas de Entity Data Model (EDM) generan clases de datos que representan las entidades en un modelo EDM. Aunque estas clases generadas no se deben modificar directamente, para cada propiedad generada, las herramientas generan también un par de métodos parciales denominados OnPropertyChanging y OnPropertyChanged, donde Property es el nombre de la propiedad. Estos métodos son invocados por Servicios de objeto antes y después de cambiar una propiedad, y se pueden extender en clases de datos parciales para implementar código personalizado. Para obtener más información acerca de cómo personalizar clases generadas, vea Personalizar objetos (Entity Framework).

El ejemplo de este tema se basa en el modelo AdventureWorks Sales. Para ejecutar el código de este ejemplo, se debe haber agregado ya 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).

Para implementar la validación personalizada en los cambios de propiedades

  1. En el proyecto, defina una clase parcial personalizada para la validación de cada clase de datos.

  2. En esta clase parcial, defina uno o ambos de los métodos siguientes, donde Property es el nombre de la propiedad que se desea validar:

    • OnPropertyChanging: incluya el código que se ha de ejecutar antes de que se produzca el cambio, por ejemplo, la validación de la propiedad. El parámetro value es el valor con el que se cambia la propiedad. Implemente este método para validar un cambio de propiedad antes de que se produzca. Para evitar que se realice el cambio, debe producir una excepción.

    • OnPropertyChanged: incluya el código que se ha de ejecutar después de que se produzca el cambio, por ejemplo, el registro del cambio.

Ejemplo

En este ejemplo se comprueba el valor de SalesOrderHeader.Status para asegurarse de que se puede cambiar el orden antes de realizar un cambio en SalesOrderDetail.OrderQty y el cambio pendiente se registre en un archivo. Esta acción se realiza en el método parcial OnOrderQtyChanging. Si el cambio no se puede realizar, se produce una excepción. A continuación, una vez efectuado correctamente el cambio, el valor de SalesOrderHeader.Status se restablece en 1 y se registra el cambio completado. Estas acciones se realizan en el método parcial OnOrderQtyChanged.

Partial Public Class SalesOrderDetail
    Inherits EntityObject
    Private Sub OnOrderQtyChanging(ByVal value As Short)
        ' Only handle this change for existing SalesOrderHeader 
        ' objects that are attached to an object context. If the item
        ' is detached then we cannot access or load the related order.
        If EntityState <> EntityState.Detached Then
            Try
                ' Ensure that the referenced SalesOrderHeader is loaded.
                If Not SalesOrderHeaderReference.IsLoaded Then
                    SalesOrderHeaderReference.Load()
                End If

                Dim order As SalesOrderHeader = SalesOrderHeader

                ' Cancel the change if the order cannot be modified.
                If SalesOrderHeader.Status > 3 Then
                    Throw New ApplicationException("The quantity cannot be changed " _
                    + "or the item cannot be added because the order has either " _
                    + "already been shipped or has been cancelled.")
                End If

                ' Log the pending order change.
                File.AppendAllText(LogFile, "Quantity of item '" _
                    + SalesOrderDetailID.ToString() + "' in order '" _
                    + order.SalesOrderID.ToString() _
                    + "' changing from '" + OrderQty.ToString() _
                    + "' to '" + value.ToString() + "'." + Environment.NewLine _
                    + "Change made by user: " + Environment.UserName _
                    + Environment.NewLine)
            Catch ex As InvalidOperationException
                Throw New ApplicationException("The quantity could not be changed " _
                + " because the order information could not be retrieved. " _
                + "The following error occurred:" + ex.Message)
            End Try
        End If
    End Sub
    Private Sub OnOrderQtyChanged()
        ' Only handle this change for existing SalesOrderHeader 
        ' objects that are attached to an object context.
        If EntityState <> EntityState.Detached Then
            Try
                ' Ensure that the SalesOrderDetail is loaded.
                If Not SalesOrderHeaderReference.IsLoaded Then
                    SalesOrderHeaderReference.Load()
                End If

                ' Reset the status for the order related to this item.
                SalesOrderHeader.Status = 1

                ' Log the completed order change.
                File.AppendAllText(LogFile, "Quantity of item '" _
                    + SalesOrderDetailID.ToString() + "' in order '" _
                    + SalesOrderHeader.SalesOrderID.ToString() _
                    + "' successfully changed to '" + OrderQty.ToString() _
                    + "'." + Environment.NewLine _
                    + "Change made by user: " + Environment.UserName _
                    + Environment.NewLine)
            Catch ex As InvalidOperationException
                Throw New ApplicationException("An error occurred " _
                + "the data could be in an inconsistent state. " _
                + Environment.NewLine + ex.Message)
            End Try
        End If
    End Sub
End Class
public partial class SalesOrderDetail : EntityObject
{
    partial void OnOrderQtyChanging(short value)
    {
        // Only handle this change for existing SalesOrderHeader 
        // objects that are attached to an object context. If the item
        // is detached then we cannot access or load the related order.
        if (EntityState != EntityState.Detached)
        {
            try
            {
                // Ensure that the referenced SalesOrderHeader is loaded.
                if (!this.SalesOrderHeaderReference.IsLoaded)
                {
                    this.SalesOrderHeaderReference.Load();
                }

                // Cancel the change if the order cannot be modified.
                if (this.SalesOrderHeader.Status > 3)
                {
                    throw new ApplicationException("The quantity cannot be changed "
                    + "or the item cannot be added because the order has either "
                    + "already been shipped or has been cancelled.");
                }

                // Log the pending order change.
                File.AppendAllText(LogFile, "Quantity of item '"
                    + this.SalesOrderDetailID.ToString() + "' in order '"
                    + this.SalesOrderHeader.SalesOrderID.ToString()
                    + "' changing from '" + this.OrderQty.ToString()
                    + "' to '" + value.ToString() + "'." + Environment.NewLine
                    + "Change made by user: " + Environment.UserName
                    + Environment.NewLine);
            }
            catch (InvalidOperationException ex)
            {
                throw new ApplicationException("The quantity could not be changed "
                + " because the order information could not be retrieved. "
                + "The following error occurred:" + ex.Message);
            }
        }
    }
    partial void OnOrderQtyChanged()
    {
        // Only handle this change for existing SalesOrderHeader 
        // objects that are attached to an object context.
        if (EntityState != EntityState.Detached)
        {
            try
            {
                // Ensure that the SalesOrderDetail is loaded.
                if (!SalesOrderHeaderReference.IsLoaded)
                {
                    SalesOrderHeaderReference.Load();
                }

                // Reset the status for the order related to this item.
                this.SalesOrderHeader.Status = 1;

                // Log the completed order change.
                File.AppendAllText(LogFile, "Quantity of item '"
                    + SalesOrderDetailID.ToString() + "' in order '"
                    + SalesOrderHeader.SalesOrderID.ToString()
                    + "' successfully changed to '" + OrderQty.ToString()
                    + "'." + Environment.NewLine
                    + "Change made by user: " + Environment.UserName
                    + Environment.NewLine);
            }
            catch (InvalidOperationException ex)
            {
                throw new ApplicationException("An error occurred; "
                + "the data could be in an inconsistent state. "
                + Environment.NewLine + ex.Message);
            }
        }
    }
}

Vea también

Otros recursos

Herramientas de Entity Data Model