Condividi tramite


Segnalazione delle modifiche nelle classi di dati personalizzate (Entity Framework)

Object Services fornisce l'interfaccia IEntityChangeTracker, utilizzata dalle classi di dati per segnalare le modifiche apportate alle proprietà dei dati. EntityObject implementa il metodo SetChangeTracker di IEntityWithChangeTracker. Questo metodo viene chiamato da Object Services per specificare l'istanza di IEntityChangeTracker utilizzata da un oggetto per segnalare le modifiche. Il modello di segnalazione delle modifiche supportato da IEntityChangeTracker prevede la segnalazione di una modifica in sospeso a una proprietà, l'impostazione della proprietà, quindi la segnalazione del completamento della modifica.

Per segnalare le modifiche nelle classi di dati personalizzate che non ereditano da EntityObject, è necessario che queste classi implementino IEntityWithChangeTracker. Per ulteriori informazioni, vedere Implementazione di interfacce di classi di dati personalizzate (Entity Framework).

Le considerazioni seguenti riguardano la segnalazione delle modifiche:

  • È consigliabile segnalare una proprietà come in fase di modifica prima di impostare il valore della proprietà, quindi segnalare la proprietà come modificata dopo averne impostato il valore.

  • È necessario segnalare le modifiche alla proprietà EntityKey. Dopo che la proprietà EntityKey è stata impostata, il codice dell'applicazione che segnala la proprietà come in fase di modifica provoca la generazione di un'eccezione InvalidOperationException. In alcuni casi, è tuttavia necessario che Object Services sia in grado di modificare la proprietà EntityKey una volta impostata. Segnalando le modifiche a questa proprietà, si consente a Object Services di determinare quando impostare la proprietà.

  • È possibile segnalare una proprietà come in fase di modifica senza successivamente segnalarla come modificata. In questo caso, tuttavia, la modifica non verrà rilevata.

  • Viene generata un'eccezione InvalidOperationException quando si segnala una proprietà come modificata prima di segnalarla come in fase di modifica oppure quando viene passato un nome di proprietà non valido. Questo può verificarsi quando più proprietà vengono segnalate come in fase di modifica senza essere successivamente segnalate come modificate. Ciò accade perché al momento della convalida della proprietà modificata rispetto alla proprietà inizialmente segnalata come in fase di modifica viene riconosciuta solo l'ultima proprietà.

Segnalazione delle modifiche alle proprietà in caso di ereditarietà da EntityObject e da ComplexObject

Quando una classe di dati personalizzata eredita da EntityObject o da ComplexObject, è necessario chiamare i metodi ReportPropertyChanging e ReportPropertyChanged per segnalare le modifiche alle proprietà.

Per segnalare le modifiche a una proprietà in caso di ereditarietà da EntityObject

  1. Chiamare il metodo System.Data.Objects.DataClasses.EntityObject.ReportPropertyChanging(System.String) su EntityObject passando il nome della proprietà in fase di modifica.

    In questo modo verrà memorizzato nella cache il valore corrente della proprietà, utilizzato come valore originale per la proprietà.

  2. Impostare la proprietà in modo appropriato.

  3. Chiamare il metodo System.Data.Objects.DataClasses.EntityObject.ReportPropertyChanged(System.String) su EntityObject passando il nome della proprietà modificata.

    In questo modo verrà notificato a Object Services il completamento della modifica in sospeso nella proprietà. Tramite Object Services la proprietà verrà quindi contrassegnata come modificata.

Per segnalare le modifiche a una proprietà in caso di ereditarietà da ComplexObject

  1. Chiamare il metodo System.Data.Objects.DataClasses.ComplexObject.ReportPropertyChanging(System.String) su ComplexObject passando il nome della proprietà in fase di modifica. In questo modo verrà memorizzato nella cache il valore corrente della proprietà, utilizzato come valore originale per la proprietà.

  2. Impostare la proprietà in modo appropriato.

  3. Chiamare il metodo System.Data.Objects.DataClasses.ComplexObject.ReportPropertyChanged(System.String) su ComplexObject passando il nome della proprietà modificata. In questo modo verrà notificato a Object Services il completamento della modifica in sospeso nella proprietà. Tramite Object Services la proprietà verrà quindi contrassegnata come modificata.

Nell'esempio seguente viene illustrato come segnalare le modifiche quando si imposta la proprietà Status scalare sull'oggetto 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");
        }
    }
}

Segnalazione delle modifiche alle proprietà in caso di implementazione di IEntityWithChangeTracker

Quando una classe di dati personalizzata implementa IEntityWithChangeTracker, è necessario chiamare i metodi di segnalazione delle modifiche su IEntityChangeTracker prima e dopo la modifica della proprietà, affinché la segnalazione venga eseguita correttamente.

Per segnalare le modifiche a una proprietà in caso di implementazione di IEntityWithChangeTracker

  1. Chiamare il metodo EntityMemberChanging passando il nome della proprietà in fase di modifica. In questo modo verrà memorizzato nella cache il valore corrente della proprietà, utilizzato come valore originale per la proprietà.

  2. Impostare la proprietà in modo appropriato.

  3. Chiamare il metodo EntityMemberChanged passando il nome della proprietà modificata.

  4. In questo modo verrà notificato a Object Services il completamento della modifica in sospeso nella proprietà. Tramite Object Services la proprietà verrà quindi contrassegnata come modificata.

Per segnalare le modifiche a una proprietà in caso di implementazione di IEntityWithChangeTracker in un tipo complesso

  1. Chiamare il metodo EntityComplexMemberChanging passando il nome della proprietà dell'entità di livello superiore modificata, l'istanza dell'oggetto complesso contenente la proprietà modificata e il nome della proprietà modificata nel tipo complesso. In questo modo verrà memorizzato nella cache il valore corrente della proprietà, utilizzato come valore originale per la proprietà.

  2. Impostare la proprietà in modo appropriato.

  3. Chiamare il metodo EntityComplexMemberChanged passando il nome della proprietà dell'entità di livello superiore modificata, l'istanza dell'oggetto complesso contenente la proprietà modificata e il nome della proprietà modificata nel tipo complesso. In questo modo verrà notificato a Object Services il completamento della modifica in sospeso nella proprietà. Tramite Object Services la proprietà verrà quindi contrassegnata come modificata.

In alcuni casi potrebbe non essere disponibile un'istanza di IEntityChangeTracker. Ciò si verifica quando un oggetto è disconnesso dal contesto dell'oggetto o quando una query viene eseguita utilizzando l'opzione NoTracking. Prima di chiamare i metodi di segnalazione delle modifiche, è necessario verificare la presenza di un'istanza di IEntityChangeTracker.

Nell'esempio seguente viene illustrata una classe astratta ComplexTypeChangeTracker che è la classe di base per tutti i tipi complessi derivati. Questa classe implementa il rilevamento delle modifiche per i tipi complessi.

' 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);
        }
    }
}

Nell'esempio seguente viene illustrato come utilizzare i metodi dell'esempio precedente per segnalare le modifiche quando si imposta la proprietà Status scalare sull'oggetto 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;
            }
        }
    }
}

Vedere anche

Concetti

Personalizzazione di oggetti (Entity Framework)