Notificar los cambios en clases de datos personalizadas (Entity Framework)

Servicios de objeto proporciona la interfaz IEntityChangeTracker, que las clases de datos usan para notificar los cambios realizados en las propiedades de datos. EntityObject implementa el método SetChangeTracker de IEntityWithChangeTracker. Servicios de objeto llama a este método para especificar la instancia de IEntityChangeTracker que un objeto usa para notificar los cambios. El modelo de notificación de cambios que admite IEntityChangeTracker implica notificar un cambio pendiente en una propiedad, establecer la propiedad y notificar a continuación que el cambio se ha completado.

Para notificar los cambios en las clases de datos personalizadas que no heredan de EntityObject, estas clases deben implementar IEntityWithChangeTracker. Para obtener más información, vea Implementar interfaces de clases de datos personalizadas (Entity Framework).

Al notificar los cambios deben tenerse en cuenta las consideraciones siguientes:

  • Debería notificar que una propiedad está cambiando antes de establecer su valor y, a continuación, notificar que la propiedad ha cambiado después de establecer su valor.

  • Debe notificar los cambios en la propiedad EntityKey. Después de establecer la propiedad EntityKey, el código de la aplicación que notifica que esta propiedad está cambiando ocasiona una InvalidOperationException. Sin embargo, en algunos casos, Servicios de objeto debe poder cambiar la propiedad EntityKey una vez establecida. Al notificar los cambios de esta propiedad, Servicios de objeto puede determinar cuándo establecerla.

  • Puede notificar que una propiedad está cambiando sin notificar después que ha cambiado. Sin embargo, en este caso el cambio no se someterá a seguimiento.

  • Al notificar que una propiedad ha cambiado antes de notificar que estaba cambiando o al pasar un nombre de propiedad no válido, se inicia una InvalidOperationException. Esto puede ocurrir cuando se notifica que varias propiedades están cambiando sin notificar después que han cambiado. Esto se debe a que sólo se reconoce la última propiedad cuando la propiedad cambiada se valida con respecto a la propiedad de la que se notificó primero que estaba cambiando.

Notificar los cambios de propiedad al heredar de EntityObject y ComplexObject

Cuando una clase de datos personalizada hereda de EntityObject o ComplexObject, debe llamar a los métodos ReportPropertyChanged y ReportPropertyChanging para notificar los cambios de propiedad.

Para notificar los cambios de propiedad al heredar de EntityObject

  1. Llame al método System.Data.Objects.DataClasses.EntityObject.ReportPropertyChanging(System.String) en EntityObject y pase el nombre de la propiedad que está cambiando.

    De este modo se almacena en memoria caché el valor actual de la propiedad, que se utiliza como valor original de la misma.

  2. Establezca la propiedad según corresponda.

  3. Llame al método System.Data.Objects.DataClasses.EntityObject.ReportPropertyChanged(System.String) en EntityObject y pase el nombre de la propiedad que ha cambiado.

    De este modo se notifica a Servicios de objeto que el cambio pendiente en la propiedad está completado ahora. A continuación, Servicios de objeto marca la propiedad como modificada.

Para notificar los cambios en una propiedad al heredar de ComplexObject

  1. Llame al método System.Data.Objects.DataClasses.ComplexObject.ReportPropertyChanging(System.String) en ComplexObject y pase el nombre de la propiedad que está cambiando. De este modo se almacena en memoria caché el valor actual de la propiedad, que se utiliza como valor original de la misma.

  2. Establezca la propiedad según corresponda.

  3. Llame al método System.Data.Objects.DataClasses.ComplexObject.ReportPropertyChanged(System.String) en ComplexObject y pase el nombre de la propiedad que ha cambiado. De este modo se notifica a Servicios de objeto que el cambio pendiente en la propiedad está completado ahora. A continuación, Servicios de objeto marca la propiedad como modificada.

En el ejemplo siguiente, se muestra cómo notificar los cambios al establecer la propiedad Status escalar en el objeto Order:

<EdmScalarPropertyAttribute(IsNullable:=False)> _
Public Property Status() As Byte
    Get
        Return _status
    End Get
    Set(ByVal value As Byte)
        If _status <> value Then
            ReportPropertyChanging("Status")
            _status = value
            ReportPropertyChanged("Status")
        End If
    End Set
End Property
[EdmScalarPropertyAttribute(IsNullable = false)]
public byte Status
{
    get 
    {
        return _status;
    }
    set
    {
        if (_status != value)
        {
            ReportPropertyChanging("Status");
            _status = value;
            ReportPropertyChanged("Status");
        }
    }
}

Notificar los cambios de propiedad al implementar IEntityWithChangeTracker

Cuando una clase de datos personalizada implementa IEntityWithChangeTracker, debe llamar a los métodos de notificación de cambios en IEntityChangeTracker antes y después de cambiar la propiedad para notificar correctamente el cambio de la propiedad.

Para notificar los cambios de propiedad al implementar IEntityWithChangeTracker

  1. Llame al método EntityMemberChanging y pase el nombre de la propiedad que está cambiando. De este modo se almacena en memoria caché el valor actual de la propiedad, que se utiliza como valor original de la misma.

  2. Establezca la propiedad según corresponda.

  3. Llame al método EntityMemberChanged y pase el nombre de la propiedad que ha cambiado.

  4. De este modo se notifica a Servicios de objeto que el cambio pendiente en la propiedad está completado ahora. A continuación, Servicios de objeto marca la propiedad como modificada.

Para notificar los cambios de propiedad al implementar IEntityWithChangeTracker en un tipo complejo

  1. Llame al método EntityComplexMemberChanging y pase el nombre de la propiedad de entidad de nivel superior que ha cambiado, la instancia de objeto complejo que contiene la propiedad que cambió y el nombre de la propiedad que cambió en el tipo complejo. De este modo se almacena en memoria caché el valor actual de la propiedad, que se utiliza como valor original de la misma.

  2. Establezca la propiedad según corresponda.

  3. Llame al método EntityComplexMemberChanged y pase el nombre de la propiedad de entidad de nivel superior que ha cambiado, la instancia de objeto complejo que contiene la propiedad que cambió y el nombre de la propiedad que cambió en el tipo complejo. De este modo se notifica a Servicios de objeto que el cambio pendiente en la propiedad está completado ahora. A continuación, Servicios de objeto marca la propiedad como modificada.

En algunas situaciones, podría no estar disponible una instancia de IEntityChangeTracker. Esto puede pasar cuando un objeto se desasocia del contexto del objeto o cuando una consulta se ejecuta utilizando la opción NoTracking. Debe comprobar si hay una instancia de IEntityChangeTracker antes de llamar a los métodos de notificación de cambios.

En el ejemplo siguiente se muestra una clase abstracta ComplexTypeChangeTracker que es la clase base para todos los tipos complejos derivados. Esta clase implementa el seguimiento de cambios para los tipos complejos.

' Base class for complex types that implements change tracking.
Public MustInherit Class ComplexTypeChangeTracker
    Protected _complexChangeTracker As IEntityChangeTracker = Nothing
    Private _rootComplexPropertyName As String

    ' Gets an IEntityChangeTracker to call for properties change. 
    ' You must do this in order to track changes.
    Public Overridable Sub SetComplexChangeTracker( _
        ByVal rootComplexPropertyName As String, _
        ByVal complexChangeTracker As IEntityChangeTracker)
        _rootComplexPropertyName = rootComplexPropertyName
        _complexChangeTracker = complexChangeTracker
    End Sub

    ' Protected method that is called before the change for change tracking 
    ' each of the scalar properties in the complex type.
    Protected Sub ReportMemberChanging(ByVal scalarPropertyName As String)
        If Not _complexChangeTracker Is Nothing Then
            _complexChangeTracker.EntityComplexMemberChanging( _
                _rootComplexPropertyName, Me, scalarPropertyName)
        End If
    End Sub

    ' Protected method that is called after the change for change tracking 
    ' each of the scalar properties in the complex type.
    Protected Sub ReportMemberChanged(ByVal scalarPropertyName As String)
        If Not _complexChangeTracker Is Nothing Then
            _complexChangeTracker.EntityComplexMemberChanged( _
                _rootComplexPropertyName, Me, scalarPropertyName)
        End If
    End Sub
End Class
// Base class for complex types that implements change tracking.
public abstract class ComplexTypeChangeTracker
{
    protected IEntityChangeTracker _complexChangeTracker = null;
    private string _rootComplexPropertyName;

    // Gets an IEntityChangeTracker to call for properties change. 
    // You must do this in order to track changes.
    virtual public void SetComplexChangeTracker(string rootComplexPropertyName, IEntityChangeTracker complexChangeTracker)
    {
        _rootComplexPropertyName = rootComplexPropertyName;
        _complexChangeTracker = complexChangeTracker;
    }

    // Protected method that is called before the change for change tracking 
    // each of the scalar properties in the complex type.
    protected void ReportMemberChanging(string scalarPropertyName)
    {
        if (null != _complexChangeTracker)
        {
            _complexChangeTracker.EntityComplexMemberChanging(_rootComplexPropertyName,
                                                       this, scalarPropertyName);
        }
    }

    // Protected method that is called after the change for change tracking 
    // each of the scalar properties in the complex type.
    protected void ReportMemberChanged(string scalarPropertyName)
    {
        if (null != _complexChangeTracker)
        {
            _complexChangeTracker.EntityComplexMemberChanged(_rootComplexPropertyName,
                                                      this, scalarPropertyName);
        }
    }
}

En el ejemplo siguiente, se muestra la forma de usar los métodos del ejemplo anterior para notificar los cambios cuando la propiedad escalar Status se establece en el objeto Order:

<EdmScalarPropertyAttribute()> _
Public Property Comment() As String
    Get
        Return _comment
    End Get
    Set(ByVal value As String)
        ' Validate the value before setting it.
        If (value <> Nothing) AndAlso value.Length > 128 Then
            Throw New ApplicationException(String.Format( _
                      My.Resources.propertyNotValidString, _
                      "Comment", "128"))
        End If
        If _comment <> value Then
            ' Report the change if the change tracker exists.
            If Not _complexChangeTracker Is Nothing Then
                ReportMemberChanging("Comment")
                _comment = value
                ReportMemberChanged("Comment")
            Else
                _comment = value
            End If
        End If
    End Set
End Property
[EdmScalarPropertyAttribute()]
public string Comment
{
    get
    {
        return _comment;
    }
    set
    {
        // Validate the value before setting it.
        if ((value != null) && value.Length > 128)
        {
            throw new ApplicationException(string.Format(
                      Properties.Resources.propertyNotValidString,
                      new string[3] { value, "Comment", "128" }));
        }
        if (_comment != value)
        {
            // Report the change if the change tracker exists.
            if (_complexChangeTracker != null)
            {
                ReportMemberChanging("Comment");
                _comment = value;
                ReportMemberChanged("Comment");
            }
            else
            {
                _comment = value;
            }
        }
    }
}

Vea también

Conceptos

Personalizar objetos (Entity Framework)