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
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.
Establezca la propiedad según corresponda.
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
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.
Establezca la propiedad según corresponda.
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
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.
Establezca la propiedad según corresponda.
Llame al método EntityMemberChanged 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 de propiedad al implementar IEntityWithChangeTracker en un tipo complejo
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.
Establezca la propiedad según corresponda.
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;
}
}
}
}