カスタム データ クラス内の変更の報告 (Entity Framework)

Object Services は、データ プロパティに対して行われた変更を報告するためにデータ クラスによって使用される IEntityChangeTracker インターフェイスを提供します。EntityObject は、IEntityWithChangeTrackerSetChangeTracker メソッドを実装します。このメソッドは、変更を報告するためにオブジェクトが使用する IEntityChangeTracker のインスタンスを指定するために Object Services によって呼び出されます。IEntityChangeTracker でサポートされる変更報告モデルでは、プロパティの保留中の変更の報告、プロパティの設定、および変更が完了したことの報告が行われます。

EntityObject を継承しないカスタム データ クラス内の変更を報告するには、それらのクラスに IEntityWithChangeTracker を実装する必要があります。詳細については、「カスタム データ クラス インターフェイスの実装 (Entity Framework)」を参照してください。

変更を報告する際は、次の点に注意してください。

  • プロパティは、プロパティ値を設定する前に変更中として報告し、プロパティ値を設定した後に変更済みとして報告する必要があります。

  • EntityKey プロパティに対する変更を報告する必要があります。EntityKey プロパティを設定した後、このプロパティを変更中として報告するアプリケーション コードによって InvalidOperationException が発生します。しかし、場合によっては、Object Services は、EntityKey プロパティが設定された後に、このプロパティを変更できる必要があります。このプロパティへの変更を報告することによって、このプロパティをいつ設定すべきかを Object Services で決定できます。

  • プロパティが変更されたものとして後で報告することなく、変更中としてプロパティを報告できます。しかし、この場合、変更は追跡されません。

  • 変更中としてプロパティを報告する前に同じプロパティを変更済みとして報告した場合、または無効なプロパティ名が渡された場合、InvalidOperationException が発生します。この例外は、後で変更済みとして報告されることなく、複数のプロパティが変更中として報告されたときに発生します。この理由は、最初に変更中として報告されたプロパティに対して、変更済みのプロパティが検証されるときに認識されるのが最後のプロパティだからです。

EntityObject および ComplexObject を継承する場合のプロパティ変更の報告

カスタム データ クラスが EntityObject または ComplexObject を継承する場合、ReportPropertyChanging および ReportPropertyChanged メソッドを呼び出してプロパティの変更を報告する必要があります。

EntityObject を継承する場合にプロパティの変更を報告するには

  1. EntityObject に対して System.Data.Objects.DataClasses.EntityObject.ReportPropertyChanging(System.String) メソッドを呼び出し、変更するプロパティの名前を渡します。

    この処理によって、プロパティの現在の値がキャッシュされます。この値は、プロパティの元の値として使用されます。

  2. 必要に応じてプロパティの値を設定します。

  3. EntityObject に対して System.Data.Objects.DataClasses.EntityObject.ReportPropertyChanged(System.String) メソッドを呼び出し、変更したプロパティの名前を渡します。

    この処理により、プロパティの保留中の変更が完了したことが Object Services に通知されます。その後、Object Services は、プロパティを変更済みとマークします。

ComplexObject を継承する場合にプロパティの変更を報告するには

  1. ComplexObject に対して System.Data.Objects.DataClasses.ComplexObject.ReportPropertyChanging(System.String) メソッドを呼び出し、変更するプロパティの名前を渡します。この処理によって、プロパティの現在の値がキャッシュされます。この値は、プロパティの元の値として使用されます。

  2. 必要に応じてプロパティの値を設定します。

  3. 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 を実装する場合にプロパティの変更を報告するには

  1. EntityMemberChanging メソッドを呼び出して、変更するプロパティの名前を渡します。この処理によって、プロパティの現在の値がキャッシュされます。この値は、プロパティの元の値として使用されます。

  2. 必要に応じてプロパティの値を設定します。

  3. EntityMemberChanged メソッドを呼び出して、変更したプロパティの名前を渡します。

  4. この処理により、プロパティの保留中の変更が完了したことが Object Services に通知されます。その後、Object Services は、プロパティを変更済みとマークします。

複合型に IEntityWithChangeTracker を実装する場合にプロパティの変更を報告するには

  1. EntityComplexMemberChanging メソッドを呼び出して、変更した最上位レベルのエンティティ プロパティの名前、変更したプロパティを含んでいる複合オブジェクト インスタンス、および複合型に対して変更したプロパティの名前を渡します。この処理によって、プロパティの現在の値がキャッシュされます。この値は、プロパティの元の値として使用されます。

  2. 必要に応じてプロパティの値を設定します。

  3. 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;
            }
        }
    }
}

参照

概念

オブジェクトのカスタマイズ (Entity Framework)