Hare.ru @ Коллективный разум / Hare.ru @ Дикое место

Архив hare.ru 
Мысли, конвертированные в текст

Собственные руки TM


Все статьи раздела

Перепроведение изменённых документов. Часть II.

Фёдор Езеев (апрель 2003)

Первая статья принесла один отклик, однако он оказался настолько концептуальным, что пришлось сесть за написание второй части.

У новой технологии нет ни одного из недостатков, упомянутых в первой статье. Кроме того, описанную идею можно использовать и в других целях. Например, для организации детального журналирования изменений БД, совершенных пользователем.

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

Первое решение, пришедшее в голову было таким: нужно отлавливать момент изменения реквизита, и в зависимости от того, какой реквизит – изменять (или не изменять) некую переменную формы документа. В процедуре ПриЗаписи() анализировать эту переменную, и, в зависимости от ее состояния, разрешать или запрещать сохранение без перепроведения.

Однако, уважаемый Mx@mail.ru и здесь проявил могучий разум, он предложил еще одну здравую мысль (просто результат он знал заранее ;-). Мысль такая: в момент записи у нас есть один документ в двух состояниях, которые можно довольно просто сравнить. Первое состояние – Контекст документа. Это то, что получилось после внесения изменений. Второе состояние –- записанный документ в базе данных.

Теория кончилась – берем в руки клавиатуру и пишем код. Начнем с анализа реквизитов шапки.

//Берем документ из БД
Д=СоздатьОбъект("Документ");
Д.НайтиДокумент(ТекущийДокумент());

МетаД=Метаданные.Документ(Вид());

//Определим, изменился реквизит, или нет
Для С=1 По МетаД.РеквизитШапки() Цикл
   РеквИД=МетаД.РеквизитШапки(С).Идентификатор;
   СтароеЗначение=Д.ПолучитьАтрибут(РеквИД);
   НовоеЗначение=ПолучитьАтрибут(РеквИД);
   Если СтароеЗначение<>НовоеЗначение Тогда
      Сообщить("Изменился реквизит шапки "+РеквИД);
      Сообщить("Старое значение: "+СтароеЗначение);
      Сообщить("Новое значение: "+НовоеЗначение);
      Сообщить("===============================");
   КонецЕсли;
КонецЦикла;

Теперь я хочу понять, насколько критичны сделанные изменения. И сообщить только о критичных.

// В список значений занесем идентификаторы тех реквизитов,
// изменение которых нас не волнует


Косметика=СоздатьОбъект("СписокЗначений");
Косметика.ДобавитьЗначение("Комментарий");
Косметика.ДобавитьЗначение("Автор");

Д=СоздатьОбъект("Документ");
Д.НайтиДокумент(ТекущийДокумент());

МетаД=Метаданные.Документ(Вид());

Для С=1 По МетаД.РеквизитШапки() Цикл
   РеквИД=МетаД.РеквизитШапки(С).Идентификатор;
   Если Косметика.НайтиЗначение(РеквИД)>0 Тогда
      Продолжить;
   КонецЕсли;

   СтароеЗначение=Д.ПолучитьАтрибут(РеквИД);
   НовоеЗначение=ПолучитьАтрибут(РеквИД);
   Если СтароеЗначение<>НовоеЗначение Тогда
      Сообщить("Изменился реквизит шапки "+РеквИД);
      Сообщить("Старое значение: "+СтароеЗначение);
      Сообщить("Новое значение: "+НовоеЗначение);
      Сообщить("===============================");
   КонецЕсли;
КонецЦикла;

Ну и в заключение на основании сделанного анализа примем нужное нам решение.

Процедура ПриЗаписи()

Если Выбран()=0 Тогда
Возврат;
КонецЕсли;

Косметика=СоздатьОбъект("СписокЗначений");
Косметика.ДобавитьЗначение("Комментарий");
Косметика.ДобавитьЗначение("Автор");
ИзменениеКритично=0;

Д=СоздатьОбъект("Документ");
Д.НайтиДокумент(ТекущийДокумент());
МетаД=Метаданные.Документ(Вид());

Для С=1 По МетаД.РеквизитШапки() Цикл
   РеквИД=МетаД.РеквизитШапки(С).Идентификатор;
   Если Косметика.НайтиЗначение(РеквИД)>0 Тогда
      Продолжить;
   КонецЕсли;
   СтароеЗначение=Д.ПолучитьАтрибут(РеквИД);
   НовоеЗначение=ПолучитьАтрибут(РеквИД);
   Если СтароеЗначение<>НовоеЗначение Тогда
      ИзменениеКритично=1;
      //Одного критичного изменения вполне достаточно
      Возврат;

   КонецЕсли;
КонецЦикла;

Если ИзменениеКритично=0 Тогда
   ПриЗаписиПерепроводить(0);
   Записать();
   ПриЗаписиПерепроводить(1);
   СтатусВозврата(0);Возврат;
КонецЕсли;


КонецПроцедуры

Общая картина ясна. Осталось только дописать анализ общих реквизитов и табличной части документа. Проблема может возникнуть разве что со сравнением табличной части. Тут главное – не забыть о том, что кроме изменения строк бывает еще и удаление и добавление.

Кусочек, сравнивающий строки, будет выглядеть примерно так (предполагаем, что любое изменение табличной части требует перепроведения):

Если КоличествоСтрок()<>Д.КоличествоСтрок() Тогда
   ИзменениеКритично=1;
   Возврат;
Иначе
   ВыбратьСтроки();
   Пока ПолучитьСтроку()=1 Цикл
      Д.ПолучитьСтрокуПоНомеру(НомерСтроки);
      Для С=1 По МетаД.РеквизитТабличнойЧасти() Цикл
         РеквИД=МетаД.РеквизитТабличнойЧасти(С).Идентификатор;
         СтароеЗначение=Д.ПолучитьАтрибут(РеквИД);
         НовоеЗначение=ПолучитьАтрибут(РеквИД);
         Если СтароеЗначение<>НовоеЗначение Тогда
            ИзменениеКритично=1;
            Возврат;
         КонецЕсли;
      КонецЦикла;
   КонецЦикла;
КонецЕсли;

Преимуществами этого метода можно признать:

  1. Прозрачность для пользователя.
  2. Размещение кода, ответственного за одну задачу в одном месте.
  3. Отсутствие "каскада записей" при изменении сразу нескольких "неважных" реквизитов.
Ну и еще раз хочется упомянуть, что данную методику можно с успехом применять для детального журналирования действий пользователя.

Партнеры:


Также может быть интересно:

Канал Россия 1 на http://spbtvonline.ru/
   
 Сайт поддерживается за счет партнеров:
:::... Сайт содержит архив двух версий hare.ru Карта сайта