Описание способов дочитки данных

Иногда требуется дочитать ранее не загруженные свойства объекта данных.

Пусть объект прочитан по представлению “НечтоE”. Возможна ситуация, когда для реализации бизнес-логики, например, для выполнения проверок при сохранении объекта, требуется дополнительное подмножество свойств объекта, т.е. объект должен быть загружен по представлению “НечтоПлюсНовыеСвойстваE”. Соответственно требуется Дочитать объект.

Существует несколько способов дочитки данных. Идеального способа, подходящего во всех случаях не существует. Для правильной дочитки данных следует прочитать руководство полностью и выберать наиболее походящий способ догрузки данных.

Особенности дочитки данных

  • В зависимости от потребностей задачи должен быть выбран способ работы с копией объекта данных. Если после дочитки будет выполняться сохранение объекта в БД, значения свойств в копии должны быть установлены таким образом, чтобы обеспечить сохранение для всех требуемых свойств.
  • Если в объекте данных перед дочиткой были свойства с измененными значениями, для дочитки надо выбрать представление таким образом, чтобы не потерять эти новые значения.

Подходы к дочитке данных

Существует два подхода к реализации дочитки:

  • Логика дочитки полностью реализуется прикладным программистом с помощью использования перегрузки метода LoadObject. В этом случае всю последовательность действий по определению догружаемых свойств и способ работы с копией данных выбирает сам программист. Это позволяет наиболее тонко учесть особенности дальнейшего использования объекта в прикладной ситуации.
  • Догрузка выполняется с помощью метода SecondLoadObject класса SQLDataService.В данный метод уже зашита стандартная, наиболее часто требуемая, логика работы с копией данных, Flexberry Platform избавляет программиста от необходимости собственной реализации.

Реализация дочитки данных в коде

Когда требуется догрузить данные, а не вычитать объект заново по указанному представлению, следует использовать [перегрузку] метода LoadObject(fo_data-service.html) с четырьмя параметрами. Третий из них - ClearDataObject - надо устанавливать в False.

/// <summary>
/// Загрузка одного объекта данных
/// </summary>
/// <param name="dataObjectView">представление</param>
/// <param name="dobject">бъект данных, который требуется загрузить</param>
/// <param name="ClearDataObject">очищать ли объект</param>
/// <param name="CheckExistingObject">проверять ли существование объекта в хранилище</param>
virtual public void LoadObject(
            ICSSoft.STORMNET.View dataObjectView,
            ICSSoft.STORMNET.DataObject dobj, bool ClearDataObject, bool CheckExistingObject, DataObjectCache DataObjectCache)

Если указать CheckExistingObject = true, при отсутствии объекта в базе будет выдано исключение типа CantFindDataObjectException.

При этом надо временно отключать переинициализацию копии данных:

dobj.DisableInitDataCopy(); // запрещаем инициализацию копии данных
ICSSoft.STORMNET.Business.DataServiceProvider.DataService.LoadObject(view, dobj, false, false); // дочитка объекта данных
dobj.EnableInitDataCopy();// возвращаем инициализацию копии данных  
dobj.GetStatus();//Для того чтобы статус объекта был вычислен по изменённым свойствам относительно копии данных.

Важно понимать что после дочитки статус объекта данных будет установлен в UnAltered, поэтому, если планируется дальнейшее обновление объекта в БД, то не забудьте вызвать dobj.GetStatus(), что приведёт к перевычислению статуса по изменённым свойствам относительно копии данных.

Данный вариант применим только к случаю, когда догружаемый объект используется только для чтения и не будет в дальнейшем сохраняться в базу. Приведённый код приведёт к тому, что в объекте поля, указанные в представлении дочитки, заполнятся, а в копии объекта данных останутся без изменений. Это, в свою очередь, приведёт к тому, что догруженные поля будут считаться изменёнными (так как расходятся с копией данных), и будут обновляться в базе данных. Поэтому если дочитываемый объект данных будет в дальнейшем сохраняться в базу, то необходимо привести в соответствие копию данных:

dobj.DisableInitDataCopy(); // запрещаем инициализацию копии данных
ICSSoft.STORMNET.Business.DataServiceProvider.DataService.LoadObject(view, dobj, false, false); // дочитка объекта данных

// вручную обновляем внутреннюю копию данных
ТипОбъекта внутренКопия = dobj.GetDataCopy();
внутренКопия.Поле1 = dobj.Поле1;
внутренКопия.Поле2 = dobj.Поле2;
//...
	
внутренКопия.ПолеN = dobj.ПолеN;

dobj.EnableInitDataCopy();// возвращаем инициализацию копии данных

Альтернативным вариантом догрузки данных является создания отдельного экземпляра того же типа с таким же первичным ключом и вычитка по необходимому представлению. При этом представление может быть полное или содержать только те атрибуты, которые будут использоваться в дальнейшем:

	// Вручную обновляем внутреннюю копию данных
	ТипОбъекта dobj_forLoading = new ТипОбъекта();
	dobj_forLoading.SetExistingPrimaryKey(dobj.__PrimaryKey);
	// view - требуемое представление. Его состав зависит от задачи.
	ICSSoft.STORMNET.Business.DataServiceProvider.DataService.LoadObject(view, dobj_forLoading);

Чтобы дочитать объект таким образом, необходимо использовать перегрузку метода LoadObject без параметра типа View. К примеру, подойдет самая простая перегрузка:

ICSSoft.STORMNET.Business.DataServiceProvider.DataService.LoadObject(dobj_forLoading);

В этом случае объект dobj_forLoading также не предназначен для сохранения в базу данных. При этом необходимо понимать, что если объект dobj имеет изменённые свойства (статус Altered), то в dobj_forLoading они не попадут, так как ещё не сохранены в базу данных. На практике логика не должна зависеть от этого фактора, так как перед дочиткой динамически определяется состав свойств, которые требуется догрузить, при этом изменённые свойства (при правильной проверке) не должны учитываться:

View viewДочитки = new View();
viewДочитки.DefineClassType = this.GetType();
if (!dobj.CheckLoadedProperty("Эпизод"))
    viewДочитки.AddProperty("Эпизод");
if (!dobj.CheckLoadedProperty("Эпизод.УД"))
    viewДочитки.AddProperty("Эпизод.УД");
if (!dobj.CheckLoadedProperty("Эпизод.УД.РУОВД"))
    viewДочитки.AddProperty("Эпизод.УД.РУОВД");
if (!dobj.CheckLoadedProperty("Эпизод.УД.РУОВД.Наименование"))
    viewДочитки.AddProperty("Эпизод.УД.РУОВД.Наименование");
if (!dobj.CheckLoadedProperty("Эпизод.УД.ГодДокумента"))
    viewДочитки.AddProperty("Эпизод.УД.ГодДокумента");
if (!dobj.CheckLoadedProperty("Эпизод.УД.НомерУД"))
    viewДочитки.AddProperty("Эпизод.УД.НомерУД");
if (!dobj.CheckLoadedProperty("Эпизод.НомерЭпизода"))
    viewДочитки.AddProperty("Эпизод.НомерЭпизода");
if (!dobj.CheckLoadedProperty("ДатаПоступленияВИЦ"))
    viewДочитки.AddProperty("ДатаПоступленияВИЦ");
if (viewДочитки.Properties.Length > 0)
{
    // дочитка объекта
}

Реализация дочитки средствами Flexberry ORM

Перед использованием данного метода догрузки следует ознакомится с тем, как обновляются значения свойств в обновляемом объекте и его копии, и учитывать это при подготовке объекта к дочитке и его дальнейшем использовании. Метод имеет следующие параметры:

 /// <summary>
/// Метод для дочитки объекта данных. Загруженные ранее свойства не затираются, изменённые свойства не затираются. Подменяются поштучно свойства копии данных. 
/// </summary>
/// <param name="dataObjectView">представление</param>
/// <param name="dataObject">бъект данных, который требуется загрузить</param>
/// <param name="checkExistingObject">проверять ли существование объекта в хранилище</param>
/// <param name="dataObjectCache"></param>
protected virtual void SecondLoadObject(
View dataObjectView,
DataObject dataObject, bool checkExistingObject, DataObjectCache dataObjectCache)

Дочитка собственных свойств

  • Все собственные свойства обновляются только если не были загружены ранее.

Копия данных

  • Если свойство не было загружено, но было изменено, то обновится значение этого свойства в копии данных (т.е. значение в копии синхронизируется с БД).
  • Если свойство было вычитано ранее, то значение в его копии данных не меняется.
  • Если копия данных не была инициализирована ранее, то она инициализируется в этот раз относительно базы данных по новому представлению. Это означает что loaded-свойства, которые достались от предыдущей зачитки останутся с неправильными значениями в копии данных, логика по определению изменённых свойств работать не будет, поэтому все свойства, обозначенные в представлении будут обновлены, кроме тех что есть в массиве loaded
  • Если в объекте отключена инициализация копии данных методом DisableInitDataCopy(), то копия данных после дочитки не будет инициализирована. По сути это означает что невозможно понять какие свойства были изменены, а какие нет. Массив LoadedProperties будет содержать массив загруженных свойств.

Дочитка мастеров

  • Если мастер не был вычитан ранее, то он будет зачитан со всеми его мастерами
  • Если мастер уже был вычитан, то будут обновлены его свойства по общему принципу
  • Если мастер был зачитан ранее, но был заменён на другой, то будет зачитан новый объект
  • При дочитке мастер проставляется в LoadedProperties даже если явно не был указан в представлении предка и в БД его нет (изменена стандартная логика). Мастер не будет указан в LoadedProperties только если LoadingState объекта: LoadingState.NotLoaded
Копия данных
  • По стандартной логике копия данных мастерового объекта инициализируется только первичным ключом.

Дочитка детейлов

  • Если детейл не участвовал в loadedProperties, то он зачитывается отдельным массивом и присваивается
  • Если детейл был загружен, то производится поэлементное слияние. Объекты, которые не были найдены в коллекции, но были загружены из БД будут добавлены