Freigeben über


Nachverfolgen von Objektänderungen und vollständige Parallelität

Letzte Änderung: Donnerstag, 4. März 2010

Gilt für: SharePoint Foundation 2010

Inhalt dieses Artikels
Entitätsidentität
Vollständige Parallelität und Abweichungen
Kritische Ereignisse, Methoden und Eigenschaften

In Listenelementen können Sie mit dem LINQ to SharePoint-Anbieter Listenelemente und bestimmte Felder hinzufügen, löschen und bearbeiten. Der Anbieter verfolgt die Änderungen nach, die vom Code an Objekten vorgenommen werden, die Entitäten in der Inhaltsdatenbank darstellen. Vor dem Schreiben der Änderungen wird außerdem zuerst bestimmt, ob die Entitäten von anderen Benutzern geändert wurden, nachdem sie durch den Code abgerufen wurden. In diesem Thema wird das System zur Nachverfolgung von Objektänderungen beschrieben. Weitere Informationen zum Vornehmen von Änderungen an Microsoft SharePoint Foundation-Daten finden Sie unter How to: Write to the Content Databases Using LINQ to SharePoint.

Entitätsidentität

Vom LINQ to SharePoint-Anbieter werden alle Entitäten, die von Abfragen zurückgegeben werden, und alle Änderungen an diesen Entitäten nachverfolgt. Wenn eine angegebene Entität mehrmals zurückgegeben wird, gibt der Anbieter stets dieselbe Entitätsinstanz zurück, die beim ersten Mal zurückgegeben wurde. Dadurch wird sichergestellt, dass eine Anwendung stets dieselbe Instanz einer angegebenen Entität verwendet und niemals eine Entität verwendet, die von einer anderen Anwendung geändert wurde.

Vollständige Parallelität und Abweichungen

Wenn DataContext.SubmitChanges() ausgeführt wird, wird der aktuelle Status der Entität in der Datenbank mit dem Status der Entität verglichen, als sie zum ersten Mal vom LINQ to SharePoint-Anbieter zurückgegeben wurde (nach dem letzten Aufruf der DataContext.SubmitChanges()-Methode). Falls eine Abweichung besteht, wurde die Entität nach dem ersten Abruf von einer anderen Anwendung geändert. Anwendungsentwickler können das Verhalten von SubmitChanges() so konfigurieren, dass das Schreiben weiterer Änderungen beendet wird, wenn die erste Abweichung gefunden wird, oder dass das Schreiben von Änderungen in die Datenbank fortgesetzt wird und alle gefundenen Konflikte aufgezeichnet werden. Für Änderungen im Zusammenhang mit einem Feld, das in einen Konflikt involviert ist, wird kein Commit für die Datenbank ausgeführt. Der aufrufende Code muss Abweichungen beheben, bevor die DataContext.SubmitChanges()-Methode erneut aufgerufen werden kann. In einem Szenario mit vollständiger Parallelität müssen dazu in der Regel dem Benutzer Informationen zu der Abweichung angezeigt werden, und es muss ihm ermöglicht werden, zu entscheiden, ob die Änderungen storniert und die Änderungen des anderen Benutzers beibehalten werden sollen oder ob die Änderungen des anderen Benutzers überschrieben werden sollen.

Kritische Ereignisse, Methoden und Eigenschaften

Die folgenden Abschnitte liefern eine Übersicht über die wichtigsten Klassen und Member, mit denen das System zur Nachverfolgung von Objektänderungen genutzt und das Schreiben in die Inhaltsdatenbank mit vollständiger Parallelität implementiert wird.

Nachverfolgen von Entitätsstatus und ursprünglichen Werten

Der Status einer Entität im Hinblick darauf, ob und wie diese geändert wurde, wird in der EntityState-Eigenschaft der Klasse gespeichert, die die Entität repräsentiert. Diese Entität wird in der ITrackEntityState-Schnittstelle deklariert, welche Sie in jeder Klasse implementieren müssen, die Entitäten repräsentiert, die Sie in das System zur Nachverfolgung von Objektänderungen einschließen möchten. Im Allgemeinen sollte von Klassen, die Inhaltstypen repräsentieren, ITrackEntityState interface implementiert werden. Denn jedes Objekt einer solchen Klasse repräsentiert ein bestimmtes Listenelement, und in der Klasse gibt es Eigenschaften, die die Felder des Listenelements repräsentieren.

Vom Code müssen möglicherweise Änderungen storniert werden, falls ein Parallelitätskonflikt erkannt wird. Deshalb müssen in denselben Inhaltstypklassen auch die ursprünglichen Werte der Felder gespeichert werden. Dies stellen Sie sicher, indem für diese Klassen die ITrackOriginalValues-Schnittstelle implementiert wird. Diese Schnittstelle definiert eine OriginalValues-Eigenschaft, die ein Wörterbuch mit den Eigenschaftsnamen und Werten darstellt. Wenn eine Eigenschaft eines Objekts, das die Klasse instanziiert, geändert wird, wird dem Wörterbuch ein Eintrag hinzugefügt, in dem der ursprüngliche Wert der Eigenschaft aufgezeichnet wird.

Alle Inhaltstypen erben vom Item-Basisinhaltstyp von SharePoint Foundation. Deshalb werden ITrackEntityState und ITrackOriginalValues in der Regel nur von der Klasse implementiert, die den Item-Inhaltstyp repräsentiert.

Es wird empfohlen, die Entitätsklassendeklarationen mit dem SPMetal-Tool zu generieren. Dieses Tool generiert standardmäßig eine Deklaration einer Item-Klasse, um den Item-Inhaltstyp zu repräsentieren, und konfiguriert die Implementierung von ITrackEntityState und ITrackOriginalValues. Es folgt ein Beispiel, in dem belanglose Details entfernt wurden, um die Lesbarkeit zu erhöhen:

[Microsoft.SharePoint.Linq.ContentTypeAttribute(Name="Item", Id="0x01")]
public partial class Item : ITrackEntityState, ITrackOriginalValues, INotifyPropertyChanged, INotifyPropertyChanging
{
    private EntityState _entityState;
    
    private IDictionary<string, object> _originalValues;

    EntityState EntityState { 
        get {
            return this._entityState;
        }
        set {
            this._entityState = value;
        }
    }

    IDictionary<string, object> OriginalValues {
        get {
            return this._originalValues;
        }
        set {
            this._originalValues = value;
        }
    }
    
    public Item() {
        this._entityState = EntityState.Unchanged;
        this.OnCreated();
    }

    // Other member declarations suppressed for readability.
}

Schließlich müssen für diese Inhaltstypklassen (oder die Item-Klasse, von der sie erben) INotifyPropertyChanged und INotifyPropertyChanging implementiert werden. Der folgende Code veranschaulicht, wie mit SPMetal diese Schnittstellen in der Item-Klasse implementiert werden.

[Microsoft.SharePoint.Linq.ContentTypeAttribute(Name="Item", Id="0x01")]
public partial class Item : ITrackEntityState, ITrackOriginalValues, INotifyPropertyChanged, INotifyPropertyChanging
{
    // Material omitted.

    public event PropertyChangedEventHandler PropertyChanged;
    
    public event PropertyChangingEventHandler PropertyChanging;
    
    protected virtual void OnPropertyChanged(string propertyName) {
        if ((EntityState.Unchanged == this._entityState)) {
            this._entityState = EntityState.ToBeUpdated;
        }
        if ((this.PropertyChanged != null)) {
            this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
    
    protected virtual void OnPropertyChanging(string propertyName, object value) {
        if ((null == _originalValues)) {
            this._originalValues = new Dictionary<string, object>();
        }
        if ((false == _originalValues.ContainsKey(propertyName))) {
            _originalValues.Add(propertyName, value);
        }
        if ((this.PropertyChanging != null)) {
            this.PropertyChanging(this, new PropertyChangingEventArgs(propertyName));
        }
    }

    // Other member declarations suppressed for readability.
}

Wie Sie sehen, hat die OnPropertyChanging-Methode den Zweck, den ursprünglichen Wert einer Eigenschaft aufzuzeichnen, deren Wert geändert wird, und anschließend das PropertyChanging()-Ereignis auszulösen. Die OnPropertyChanged-Methode hat dagegen den Zweck, das PropertyChanged()-Ereignis auszulösen, nachdem der Entitätsstatus des Listenelementobjekts auf ToBeUpdated festgelegt wurde. Dieser Wert bedeutet, dass mindestens eine der Eigenschaften des Objekts geändert wurde, sodass durch das Verhindern von Parallelitätskonflikten beim nächsten Aufruf von SubmitChanges() diese Änderung in das entsprechende Feld in der Inhaltsdatenbank geschrieben wird. Diese beiden Methoden sollen vom set-Accessor einer Eigenschaft aufgerufen werden, die ein Feld im Listenelement repräsentiert. Beispielsweise veranschaulicht das folgende Beispiel, wie von SPMetal die Eigenschaft der Item-Klasse erstellt wird, die das Feld Title eines Listenelements repräsentiert. Diese Version des generierten Codes wurde aus Gründen der Lesbarkeit vereinfacht.

[Column(Name="Title", Storage="_title", Required=true, FieldType="Text")]
public string Title {
    get {
        return this._title;
    }
    set {
         if ((this._title != value)) {
            this.OnPropertyChanging("Title", this._title);
            this._title = value;
            this.OnPropertyChanged("Title");
         }
    }
}

DataContext-Klasse

Die DataContext-Klasse repräsentiert die Listen und Listenelemente einer SharePoint Foundation-Website. Deshalb kann man sich diese Klasse als eine Teilmenge der Inhaltsdatenbank vorstellen. Sie weist drei Member auf, die für das System zur Nachverfolgung von Objektänderungen eine wichtige Rolle spielen:

  • ObjectTrackingEnabled – diese Eigenschaft muss auf true festgelegt werden, damit von Code Änderungen an den SharePoint Foundation-Daten vorgenommen werden können.

  • SubmitChanges() – mit dieser Methode werden alle nach dem letzten Aufruf dieser Methode vorgenommenen Änderungen in die Inhaltsdatenbank geschrieben, vorausgesetzt es werden keine Parallelitätskonflikte gefunden. Falls ein Konflikt gefunden wird, hängt das Verhalten dieser Methode von den übergebenen Parametern ab. Diese Methode kann angewiesen werden, ein ChangeConflictException-Ereignis auszulösen, sobald ein Konflikt gefunden wird, und das Schreiben von Änderungen zu beenden. Oder sie kann angewiesen werden, das Auslösen der Ausnahme zu verschieben, das Schreiben von Änderungen, die keinen Einfluss auf ein an einem Konflikt beteiligtes Feld haben, in die Inhaltsdatenbank fortzusetzen. In beiden Fällen wird mindestens ein Objekt gespeichert, das Konflikte in der ChangeConflicts-Eigenschaft repräsentiert.

  • ChangeConflicts – in dieser Eigenschaft werden Objekte gespeichert, welche Parallelitätskonflikte repräsentieren, die beim letzten Aufruf von SubmitChanges() gefunden wurden und wobei mindestens ein Parallelitätskonflikt erkannt wurde.

EntityList<T>-Klasse

Die EntityList<TEntity>-Klasse repräsentiert eine Liste auf der Website. Sie weist mehrere Methoden zum Schreiben in die Inhaltsdatenbank auf. Dies sind die beiden wichtigsten Methoden:

  • InsertOnSubmit(TEntity) – mit dieser Methode wird ein angegebenes Listenelement gekennzeichnet, das der Liste hinzugefügt werden soll.

  • DeleteOnSubmit(TEntity) – mit dieser Methode wird ein angegebenes Listenelement gekennzeichnet, das aus der Liste entfernt werden soll.

MemberChangeConflict-Klasse

Die MemberChangeConflict-Klasse repräsentiert einen möglichen Parallelitätskonflikt im Hinblick auf ein bestimmtes Feld in einem bestimmten Listenelement. Dies sind die wichtigsten Member:

  • OriginalValue – diese Eigenschaft repräsentiert den Wert im Feld, als er zuletzt aus der Inhaltsdatenbank abgerufen wurde oder unmittelbar nach der letzten erfolgreichen Ausführung von SubmitChanges().

  • DatabaseValue – diese Eigenschaft repräsentiert den aktuellen Wert des Felds in der Inhaltsdatenbank. Wenn dieser Wert nicht mit OriginalValue identisch ist, wurde das Feld von einem anderen Benutzerprozess geändert, und MemberChangeConflict stellt einen Parallelitätskonflikt dar.

  • CurrentValue – diese Eigenschaft repräsentiert den neuesten Wert des Felds im Prozess Ihres Codes. (Dies wird auch als "Clientwert" bezeichnet, wobei sich jedoch "Client" in diesem Fall auf den Front-End-Webserver bezieht). Falls der Feldwert mit dem Code geändert wurde, ist CurrentValue nicht mit OriginalValue identisch.

  • Resolve() – mit dieser Methode wird ein Konflikt behoben, indem ausgewählt wird, welcher Wert beim nächsten Aufruf von SubmitChanges() auf das Feld angewendet werden sollte.

MemberChangeConflict-Objekte werden in der MemberConflicts-Eigenschaft eines ObjectChangeConflict-Objekts gespeichert.

Wichtiger HinweisWichtig

Falls bei einem Feld in einem Listenelement ein Parallelitätskonflikt gemeldet wird (d. h., DatabaseValue ist nicht mit OriginalValue identisch), wird ein MemberChangeConflict-Element nicht nur für dieses Feld instanziiert, sondern auch für jedes Feld, bei dem DatabaseValue nicht mit CurrentValue identisch ist. Dies ist darauf zurückzuführen, dass Änderungen an Feldern in einem Listenobjekt oft entweder an allen Feldern oder an keinen Feldern vorgenommen werden müssen. Wenn z. B. ein Parallelitätskonflikt bei einem PLZ-Feld vorhanden ist und die Lösung darin besteht, die Änderungen des anderen Benutzers beizubehalten, dann sollten auch andere Adressfelder, wie z. B. der Ort, ebenfalls nicht geändert werden. Aus diesem Grund müssen alle Abweichungen zwischen Client- und Datenbankwerten für die Behebung repräsentiert werden.

ObjectChangeConflict-Klasse

Die ObjectChangeConflict-Klasse repräsentiert ein Listenelement, für das ein Parallelitätskonflikt bei mindestens einem der Felder vorhanden ist. Dies sind die beiden wichtigsten Member:

ChangeConflictCollection-Klasse

Ein ChangeConflictCollection-Objekt ist eine Sammlung aller ObjectChangeConflict-Objekte, die durch einen Aufruf von SubmitChanges() generiert werden und durch den mindestens ein Parallelitätskonflikt gefunden wurde. Der wichtigste Member ist die ResolveAll()-Methode, mit der Code zum Beheben aller untergeordneter Konflikte mithilfe eines einzigen Methodenaufrufs aufgerufen wird.

ChangeConflictCollection-Objekte werden in der DataContext.ChangeConflicts-Eigenschaft gespeichert.

Siehe auch

Weitere Ressourcen

How to: Write to the Content Databases Using LINQ to SharePoint