报告自定义数据类中的更改(实体框架)
对象服务提供了 IEntityChangeTracker 接口,数据类使用它来报告对数据属性进行的更改。EntityObject 实现了 IEntityWithChangeTracker 的 SetChangeTracker 方法。此方法由对象服务调用,以指定对象用于报告更改的 IEntityChangeTracker 实例。IEntityChangeTracker 所支持的更改报告模型涉及报告对属性的挂起更改、设置属性以及随后报告更改已完成。
若要在报告不从 EntityObject 继承的自定义数据类的更改,这些类必须实现 IEntityWithChangeTracker。有关更多信息,请参见实现自定义数据类接口(实体框架)。
在报告更改时,需要考虑下列注意事项:
您应该在设置属性值之前将该属性报告为正在更改,然后在设置属性值之后将该属性报告为已更改。
您必须报告对 EntityKey 属性的更改。在设置 EntityKey 属性后,将该属性报告为正在更改的应用程序代码将引发 InvalidOperationException。但是,在某些情况下,对象服务必须能够在 EntityKey 属性设置之后更改该属性。通过报告对该属性的更改,对象服务能够确定何时设置该属性。
在将某个属性报告为正在更改后,无需将该属性报告为已更改。但是,在这种情况下,将不会跟踪更改。
在将某个属性报告为正在更改之前将相同属性报告为已更改时,或者在传递了无效的属性名时,将引发 InvalidOperationException。在将多个属性报告为正在更改,而随后没有将其报告为已更改时,可能发生这种情况。这是因为在根据被首先报告为正在更改的属性验证已更改的属性时,只有最后一个属性被识别。
在从 EntityObject 和 ComplexObject 继承时报告属性更改
当自定义数据类从 EntityObject 或 ComplexObject 更改时,必须调用 ReportPropertyChanging 和 ReportPropertyChanged 方法来报告属性更改。
在从 EntityObject 继承时报告对属性的更改
调用 EntityObject 上的 System.Data.Objects.DataClasses.EntityObject.ReportPropertyChanging(System.String) 方法,并且传递正在更改的属性的名称。
这会缓存该属性的当前值,该值将用作该属性的原始值。
将该属性设置为适当的值。
调用 EntityObject 上的 System.Data.Objects.DataClasses.EntityObject.ReportPropertyChanged(System.String) 方法,并且传递已更改的属性的名称。
这会通知对象服务对该属性的挂起更改现在已完成。对象服务随后会将该属性标记为已修改。
在从 ComplexObject 继承时报告对属性的更改
调用 ComplexObject 上的 System.Data.Objects.DataClasses.ComplexObject.ReportPropertyChanging(System.String) 方法,并且传递正在更改的属性的名称。这会缓存该属性的当前值,该值将用作该属性的原始值。
将该属性设置为适当的值。
调用 ComplexObject 上的 System.Data.Objects.DataClasses.ComplexObject.ReportPropertyChanged(System.String) 方法,并且传递已更改的属性的名称。这会通知对象服务对该属性的挂起更改现在已完成。对象服务随后会将该属性标记为已修改。
下面的示例演示如何在设置 Order 对象上的标量 Status 属性时报告更改:
<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");
}
}
}
在实现 IEntityWithChangeTracker 时报告属性更改
当自定义数据类实现 IEntityWithChangeTracker 时,您必须在更改属性之前和之后调用 IEntityChangeTracker 上的更改报告方法,以便正确地报告更改。
在实现 IEntityWithChangeTracker 时报告对属性的更改
调用 EntityMemberChanging 方法,并且传递正在更改的属性的名称。这会缓存该属性的当前值,该值将用作该属性的原始值。
将该属性设置为适当的值。
调用 EntityMemberChanged 方法,并且传递已更改的属性的名称。
这会通知对象服务对该属性的挂起更改现在已完成。对象服务随后会将该属性标记为已修改。
在实现复杂类型上的 IEntityWithChangeTracker 时报告对属性的更改
调用 EntityComplexMemberChanging 方法,并且传递已经更改的顶级实体属性的名称、包含已更改属性的复杂对象实例以及复杂类型上的已更改属性的名称。这会缓存该属性的当前值,该值将用作该属性的原始值。
将该属性设置为适当的值。
调用 EntityComplexMemberChanged 方法,并且传递已经更改的顶级实体属性的名称、包含已更改属性的复杂对象实例以及复杂类型上的已更改属性的名称。这会通知对象服务对该属性的挂起更改现在已完成。对象服务随后会将该属性标记为已修改。
在某些情况下,IEntityChangeTracker 的实例可能不可用。当对象从对象上下文中分离,或者当使用 NoTracking 选项执行查询时,可能发生这种情况。在调用更改报告方法之前,必须检查是否存在 IEntityChangeTracker 的实例。
下面的示例演示一个抽象类 ComplexTypeChangeTracker,该类是所有派生的复杂类型的基类。此类用于实现复杂类型的更改跟踪。
' 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);
}
}
}
下面的示例演示如何使用上例中的方法报告在设置 Order 对象的标量属性 Status 时所发生的更改:
<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;
}
}
}
}