Поделиться через


Отчеты об изменениях в пользовательских классах данных (платформа Entity Framework)

Службы объектов предоставляют интерфейс IEntityChangeTracker, который используется классами данных для отчета об изменениях свойств данных. EntityObject реализует метод SetChangeTracker для IEntityWithChangeTracker. Этот метод вызывается службами объектов для указания экземпляра IEntityChangeTracker, который объект использует для отчета об изменениях. Модель отчета об изменениях, поддерживаемая IEntityChangeTracker, предполагает отчет об отложенном изменении свойства, задание свойства и последующий отчет о завершении изменения.

Для отчета об изменениях в пользовательских классах данных, не наследуемых от EntityObject, эти классы должны реализовать интерфейс IEntityWithChangeTracker. Дополнительные сведения см. в разделе Реализация интерфейсов пользовательских классов данных (платформа Entity Framework).

При отчете об изменениях следует принимать во внимание следующие соображения.

  • Отчет об изменении свойства следует предоставлять как перед, так и после задания значения этого свойства.

  • Необходимо создавать отчет об изменении свойства EntityKey. После задания значения свойства EntityKey код приложения, создающий отчет об изменении этого свойства, вызывает исключение InvalidOperationException. Но в некоторых случаях службы объектов должны иметь возможность изменять свойство EntityKey после его установки. Создавая отчет об изменениях этого свойства, службы объектов могут определить, когда следует задавать это свойство.

  • Можно создавать отчет об изменении свойства без последующего создания отчета об изменении его значения. Однако в этом случае изменение не будет отслеживаться.

  • Исключение InvalidOperationException вызывается, если создается отчет о завершении изменения свойства до того, как предоставляется отчет об изменении этого свойства или передается недопустимое имя свойства. Это происходит, если создается отчет об изменении нескольких свойств без последующего создания отчета о завершении изменения. Это объясняется тем, что распознается изменение только последнего свойства, если измененное свойство сравнивается со свойством, отчет об изменении которого был предоставлен первоначально.

Отчет об изменениях свойств при наследовании от базовых классов EntityObject и ComplexObject

Если пользовательский класс данных наследуется от EntityObject или ComplexObject, для отчета об изменении свойств необходимо вызвать методы ReportPropertyChanging и ReportPropertyChanged.

Отчет об изменении свойств при наследовании от класса EntityObject

  1. Вызовите метод System.Data.Objects.DataClasses.EntityObject.ReportPropertyChanging(System.String) для EntityObject, передав имя изменяемого свойства.

    В результате текущее значение свойства, которое используется в качестве исходного, будет помещено в кэш.

  2. Установите нужное значение свойства.

  3. Вызовите метод System.Data.Objects.DataClasses.EntityObject.ReportPropertyChanged(System.String) для EntityObject, передав имя измененного свойства.

    В результате службы объектов получают уведомление о том, что выполнено отложенное изменение свойства. Затем службы объектов помечают свойство как измененное.

Отчет об изменении свойств при наследовании от класса ComplexObject

  1. Вызовите метод System.Data.Objects.DataClasses.ComplexObject.ReportPropertyChanging(System.String) для ComplexObject, передав имя изменяемого свойства. В результате текущее значение свойства, которое используется в качестве исходного, будет помещено в кэш.

  2. Установите нужное значение свойства.

  3. Вызовите метод System.Data.Objects.DataClasses.ComplexObject.ReportPropertyChanged(System.String) для ComplexObject, передав имя измененного свойства. В результате службы объектов получат уведомление о том, что выполнено отложенное изменение свойства. Затем службы объектов помечают свойство как измененное.

В следующем примере показано, как передавать уведомления об изменениях, если задается скалярное свойство Status для объекта 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");
        }
    }
}

Отчет об изменении свойств при реализации интерфейса IEntityWithChangeTracker

Если пользовательский класс данных реализует интерфейс IEntityWithChangeTracker, для правильного создания отчета об изменении в методе IEntityChangeTracker необходимо вызвать методы отчета об изменениях до и после изменения свойства.

Отчет об изменении свойств при реализации интерфейса IEntityWithChangeTracker

  1. Вызовите метод EntityMemberChanging, передав имя изменяемого свойства. В результате текущее значение свойства, которое используется в качестве исходного, будет помещено в кэш.

  2. Установите нужное значение свойства.

  3. Вызовите метод EntityMemberChanged, передав имя измененного свойства.

  4. В результате службы объектов получат уведомление о том, что выполнено отложенное изменение свойства. Затем службы объектов помечают свойство как измененное.

Отчет об изменении свойств при реализации интерфейса IEntityWithChangeTracker для сложного типа

  1. Вызовите метод EntityComplexMemberChanging, передав имя измененной сущности верхнего уровня, экземпляр сложного объекта, содержащий измененное свойство, и имя свойства, изменившегося в сложном типе. В результате текущее значение свойства, которое используется в качестве исходного, будет помещено в кэш.

  2. Установите нужное значение свойства.

  3. Вызовите метод 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);
        }
    }
}

В следующем примере показано, как использовать методы из предыдущего примера для уведомления об изменениях при установке скалярного свойства Status объекта 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;
            }
        }
    }
}

См. также

Основные понятия

Настройка объектов (платформа Entity Framework)