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


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

Дата последнего изменения: 4 марта 2010 г.

Применимо к: SharePoint Foundation 2010

В этой статье
Удостоверение сущности
Оптимистичный параллелизм и несоответствия
Критические события, методы и свойства

С помощью поставщика LINQ для SharePoint можно добавлять, удалять и редактировать элементы списка и определение поля в элементах списка. Поставщик отслеживает изменения, которые код совершает по отношению к объектам, представляющим сущности в базе данных контекста. Также перед записью изменений он определяет, изменялись ли сущности другими пользователями после того, как они были запрошены кодом. В данном разделе описывается система отслеживания изменения объектов. Дополнительные сведения об изменении данных Microsoft SharePoint Foundation см. в разделе How to: Write to the Content Databases Using LINQ to SharePoint.

Удостоверение сущности

Поставщик LINQ для SharePoint отслеживает все сущности, возвращаемые запросами, и все изменения этих сущностей. Когда определенная сущность возвращается более одного раза, поставщик всегда возвращает такой же экземпляр сущности, какой возвращался первый раз. Это поведение обеспечивает то, что приложение всегда работает с тем же экземпляром определенной сущности и что оно никогда не работает с сущностью, измененной другим приложением.

Оптимистичный параллелизм и несоответствия

При выполнении метода DataContext.SubmitChanges() он проверяет текущее состояние сущности в базе данных с состоянием сущности, когда поставщик LINQ для SharePoint первый раз возвращал ее (после последнего вызова метода DataContext.SubmitChanges() mетода). Если существует несоответствие, то какое-то другое приложение изменило сущность после первого запроса. Разработчики приложений могут настроить поведение метода SubmitChanges(), чтобы запретить запись других изменений при обнаружении первого несоответствия, или он может быть настроен на продолжение записи изменений в базу данных и записи обнаруженных конфликтов. Изменения, включающие поле, включенное в конфликт, не сохраняются в базе данных. Вызывающий код должен разрешить несоответствия до того, как метод DataContext.SubmitChanges() сможет быть вызван снова. В оптимистичном сценарии конкуренции решение обычно включает выдачу запроса пользователю с данными о несоответствии и разрешение пользователю решать, отменить или сохранить изменения другого пользователя или перезаписать изменения другого пользователя.

Критические события, методы и свойства

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

Отслеживание состояния сущности и исходных значений

Состояние сущности с данными о том, где и как она была изменена, сохраняется в свойстве EntityState класса, представляющего сущность. Это свойство объявлено в интерфейсе ITrackEntityState интерфейс, который необходимо реализовать в любом классе, представляющем сущности, которые требуется включить в систему отслеживания изменений объектов. В общем случае нужны классы, представляющие типы контента, чтобы реализовать интерфейс ITrackEntityState, так как каждый объект такого класса представляет определенный элемент списка и существуют свойства в классе, представляющем поля элемента списка.

Коду может потребоваться отменить изменения при обнаружении конфликта конкуренции, поэтому эти же классы типа контента также требуются для сохранения исходных значений их полей. Это обеспечивается реализацией в этих классах интерфейса ITrackOriginalValues. Последний определяет свойство OriginalValues, являющееся словарем имен и значений свойства. При изменении свойства объекта, который создает экземпляр, запись добавляется в словарь, предназначенный для исходных значений свойства.

Все классы типов контента наследуются от базового типа контента ItemSharePoint Foundation. Поэтому обычно только класс, представляющий тип контента Item, реализует ITrackEntityState и ITrackOriginalValues.

Рекомендуется использовать средство SPMetal для создания деклараций класса сущностей. Это средство создает по умолчанию объявление класса Item, чтобы представлять тип контента Item, и настраивает его для реализации ITrackEntityState и ITrackOriginalValues. Далее приводится пример, в котором излишние подробности удалены для читаемости.

[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.
}

Наконец, эти классы типа контента (или класс Item, от которого они наследуются) должны реализовать интерфейсы INotifyPropertyChanged и INotifyPropertyChanging. В следующем коде показано, как в SPMetal реализуются эти интерфейсы в классе Item.

[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.
}

Как можно заметить, назначение метода OnPropertyChanging заключается в записи исходного значения свойства, чье значение изменяется, а затем в вызове PropertyChanging() события; а назначение метода OnPropertyChanged заключается в вызове события PropertyChanged() после того, как он задает состояние сущности объекта элемента списка в значение ToBeUpdated. Это значение означает, что минимум одно свойство объекта было изменено, поэтому следующий вызов SubmitChanges() записывает изменение в соответствующее поле в базу данных контекста, устраняя конфликт параллелизма. Требуется вызвать эти два метода посредством метода доступа set свойства, представляющего поле в элементе списка. Например, в следующем примере демонстрируется, как SPMetal создает свойство класса Item, представляющее поле Title элемента списка. Эта версия созданного кода упрощена для читаемости.

[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

Класс DataContextпредставляет списки и элементы списков веб-сайта SharePoint Foundation. Поэтому он может рассматриваться как подмножество элементов базы данных контекста. Он имеет три члена, являющихся критичными для системы отслеживания изменений объектов:

  • ObjectTrackingEnabled. Это свойство должно быть задано в значение true до того, как код сможет производить какие-либо изменения данных SharePoint Foundation.

  • SubmitChanges(). Этот метод записывает в базу данных все изменения, сделанные после того, как он последний раз вызывался, в случае отсутствия конфликтов параллелизма. В случае обнаружения конфликтов его поведение меняется в зависимости от переданных ему параметров. Он может вызвать исключение ChangeConflictException в случае обнаружения конфликта и остановить запись изменений. Или он может отложить вызов исключения и продолжить запись в базу данных всех изменений, которые не влияют на включенное в конфликт поле. В обоих случаях он сохраняет один или несколько объектов, представляющих конфликт, в свойстве ChangeConflicts.

  • ChangeConflicts. Это свойство содержит объекты, представляющие конфликты параллелизма, обнаруженные при последнем вызове SubmitChanges(), в случае если обнаружен минимум один конфликт.

Класс EntityList<T>

Класс EntityList<TEntity>представляет список веб-сайта. Он имеет несколько методов для записи контента в базу данных контента. Следующие два являются наиболее критичными:

  • InsertOnSubmit(TEntity). Этот метод отмечает определенные элементы списка для добавления в список.

  • DeleteOnSubmit(TEntity). Этот метод помечает определенные элементы списка для удаления из списка.

Класс MemberChangeConflict

Класс MemberChangeConflict представляет возможный конфликт параллелизма по отношению к определенному полю в определенном элементе списка. Его наиболее важные члены включают следующие:

  • OriginalValue. Это свойство представляет значение поля, когда оно было последний раз запрошено из базы данных контента или сразу после того, как последний раз успешно выполнялся перегруженный метод SubmitChanges().

  • DatabaseValue. Это свойство представляет текущее значение поля в базе данных контента. Если это значение отличается от OriginalValue, то процесс какого-то другого пользователя изменил поле, и MemberChangeConflict представляет действительный конфликт параллельности.

  • CurrentValue. Это свойство представляет самое последнее значение поля в процессе разрабатываемого кода. (Оно также называется "клиентским значением", хотя слово "клиент" здесь указывает на интерфейсный веб-сервер.) Если код изменяет значение поля, CurrentValue отличается от OriginalValue.

  • Resolve(). Этот метод разрешает конфликт посредством выбора значения, которое должно применяться к полю во время следующего вызова SubmitChanges().

Объекты MemberChangeConflict сохраняются в свойстве MemberConflicts объекта ObjectChangeConflict.

Важное примечаниеВажно!

Если в каком-либо поле элемента списка обнаруживается конфликт параллелизма (то есть DatabaseValue отличается от OriginalValue), то создается экземпляр MemberChangeConflict не только для этого поля, но также для всех полей, в которых DatabaseValue отличается от CurrentValue. Это происходит из-за того, что часто изменения полей в объекте списка должны выполняться на основе "все или ничего". Например, если существует конфликт параллельности для поля почтового индекса, а разрешение заключается в том, чтобы сохранить изменения другого пользователя, то другие поля в адресе, такие как город, тоже не должны меняться. Поэтому все несоответствия между значениями в клиенте и в базе данных должны быть представлены для разрешения.

Класс ObjectChangeConflict

Класс ObjectChangeConflict представляет элемент списка, для которого существует конфликт параллелизма в минимум одном из его полей. Два наиболее важных члена класса следующие:

  • MemberConflicts. Это свойство представляет коллекцию объектов MemberChangeConflict. Минимум один из них представляет конфликт параллельности. Если другие поля показывают несоответствие между значением в клиенте и значением в базе данных, существуют также объекты MemberChangeConflict для представления этих полей.

  • Resolve(). Этот метод представляет средства разрешения всех несоответствий без явного вызова метода MemberChangeConflict.Resolve() каждого члена свойства MemberConflicts.

Класс ChangeConflictCollection

Объект ChangeConflictCollection является коллекцией всех объектов ObjectChangeConflict, созданных вызовом метода SubmitChanges(), обнаружившего минимум один конфликт параллелизма. Наиболее важным членом этого объекта является метод ResolveAll(), который позволяет вызывающему коду разрешить все дочерние конфликты с помощью одного вызова метода.

Объекты ChangeConflictCollection сохраняются в свойстве DataContext.ChangeConflicts свойство.

См. также

Другие ресурсы

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