カスタム データ クラス内の変更の報告 (Entity Framework)
Object Services は、データ プロパティに対して行われた変更を報告するためにデータ クラスによって使用される IEntityChangeTracker インターフェイスを提供します。EntityObject は、IEntityWithChangeTracker の SetChangeTracker メソッドを実装します。このメソッドは、変更を報告するためにオブジェクトが使用する IEntityChangeTracker のインスタンスを指定するために Object Services によって呼び出されます。IEntityChangeTracker でサポートされる変更報告モデルでは、プロパティの保留中の変更の報告、プロパティの設定、および変更が完了したことの報告が行われます。
EntityObject を継承しないカスタム データ クラス内の変更を報告するには、それらのクラスに IEntityWithChangeTracker を実装する必要があります。詳細については、「カスタム データ クラス インターフェイスの実装 (Entity Framework)」を参照してください。
変更を報告する際は、次の点に注意してください。
プロパティは、プロパティ値を設定する前に変更中として報告し、プロパティ値を設定した後に変更済みとして報告する必要があります。
EntityKey プロパティに対する変更を報告する必要があります。EntityKey プロパティを設定した後、このプロパティを変更中として報告するアプリケーション コードによって InvalidOperationException が発生します。しかし、場合によっては、Object Services は、EntityKey プロパティが設定された後に、このプロパティを変更できる必要があります。このプロパティへの変更を報告することによって、このプロパティをいつ設定すべきかを Object Services で決定できます。
プロパティが変更されたものとして後で報告することなく、変更中としてプロパティを報告できます。しかし、この場合、変更は追跡されません。
変更中としてプロパティを報告する前に同じプロパティを変更済みとして報告した場合、または無効なプロパティ名が渡された場合、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) メソッドを呼び出し、変更したプロパティの名前を渡します。
この処理により、プロパティの保留中の変更が完了したことが Object Services に通知されます。その後、Object Services は、プロパティを変更済みとマークします。
ComplexObject を継承する場合にプロパティの変更を報告するには
ComplexObject に対して System.Data.Objects.DataClasses.ComplexObject.ReportPropertyChanging(System.String) メソッドを呼び出し、変更するプロパティの名前を渡します。この処理によって、プロパティの現在の値がキャッシュされます。この値は、プロパティの元の値として使用されます。
必要に応じてプロパティの値を設定します。
ComplexObject に対して System.Data.Objects.DataClasses.ComplexObject.ReportPropertyChanged(System.String) メソッドを呼び出し、変更したプロパティの名前を渡します。この処理により、プロパティの保留中の変更が完了したことが Object Services に通知されます。その後、Object Services は、プロパティを変更済みとマークします。
次の例は、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 メソッドを呼び出して、変更したプロパティの名前を渡します。
この処理により、プロパティの保留中の変更が完了したことが Object Services に通知されます。その後、Object Services は、プロパティを変更済みとマークします。
複合型に IEntityWithChangeTracker を実装する場合にプロパティの変更を報告するには
EntityComplexMemberChanging メソッドを呼び出して、変更した最上位レベルのエンティティ プロパティの名前、変更したプロパティを含んでいる複合オブジェクト インスタンス、および複合型に対して変更したプロパティの名前を渡します。この処理によって、プロパティの現在の値がキャッシュされます。この値は、プロパティの元の値として使用されます。
必要に応じてプロパティの値を設定します。
EntityComplexMemberChanged メソッドを呼び出して、変更した最上位レベルのエンティティ プロパティの名前、変更したプロパティを含んでいる複合オブジェクト インスタンス、および複合型に対して変更したプロパティの名前を渡します。この処理により、プロパティの保留中の変更が完了したことが Object Services に通知されます。その後、Object Services は、プロパティを変更済みとマークします。
状況によっては、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;
}
}
}
}