В процессе разработки на платформе 1С часто возникает задача оптимизации записи данных. Представьте ситуацию: у вас есть форма с большой таблицей товаров (например, приходная накладная или спецификация поставки), и пользователь изменил количество только в одной строке из ста. Записывать все сто строк в регистр сведений — неэффективно, особенно если регистр хранит историю изменений или используется для аудита. Рассмотрим подробно, как реализовать механизм записи только тех строк, которые действительно подверглись правке.
Это самый простой и распространенный способ. Мы добавим в таблицу на форме «невидимый» для пользователя признак, который будет сигнализировать системе, что строка была изменена. Разберем по шагам, как это реализовать:
ТаблицаЗначений или ДанныеФормыКоллекция), создадим колонку Изменена с типом Булево.Видимость = Ложь.ПриИзменении.Проанализируем пример кода для этого события:
&НаКлиенте
Процедура ТоварыКоличествоПриИзменении(Элемент)
ТекущаяСтрока = Элементы.Товары.ТекущиеДанные;
Если ТекущаяСтрока <> Неопределено Тогда
ТекущаяСтрока.Изменена = Истина;
КонецЕсли;
КонецПроцедуры
Теперь при нажатии кнопки сохранения нам достаточно перебрать строки и выбрать только те, где Изменена = Истина. Рассмотрим, как программно сформировать записи в регистре:
&НаСервере
Процедура ЗаписатьИзмененныеСтрокиВРегистр()
Для Каждого СтрокаТовар Из Объект.Товары Цикл
Если СтрокаТовар.Изменена Тогда
// Создаем менеджер записи или набор записей
МенеджерЗаписи = РегистрыСведений.УчетПоставок.СоздатьМенеджерЗаписи();
// Заполняем измерения из шапки формы и строки
МенеджерЗаписи.Период = Объект.Дата;
МенеджерЗаписи.Номенклатура = СтрокаТовар.Номенклатура;
МенеджерЗаписи.Склад = Объект.Склад;
// Заполняем ресурсы
МенеджерЗаписи.Количество = СтрокаТовар.Количество;
МенеджерЗаписи.Сумма = СтрокаТовар.Сумма;
МенеджерЗаписи.Записать();
// Сбрасываем флаг после успешной записи
СтрокаТовар.Изменена = Ложь;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Иногда использование события ПриИзменении может быть избыточным или давать ложноположительные результаты (например, пользователь зашел в поле, ничего не менял, но событие сработало). В таких случаях эффективнее использовать метод сравнения коллекций. Выясним, как это работает.
При открытии формы (в событии ПриСозданииНаСервере) мы сохраняем текущее состояние таблицы в скрытый реквизит формы типа ТаблицаЗначений. Рассмотрим алгоритм:
КопияДанных (тип ТаблицаЗначений), полностью повторяющий структуру основной таблицы.КопияДанных.Загрузить(Объект.Товары.Выгрузить());.Посмотрим на пример функции сравнения:
&НаСервере
Процедура СохранитьОтличия()
ТаблицаТекущая = Объект.Товары.Выгрузить();
ТаблицаСтарая = РеквизитФормыВЗначение("КопияДанных");
Для Индекс = 0 По ТаблицаТекущая.Количество() - 1 Цикл
СтрокаТекущая = ТаблицаТекущая[Индекс];
СтрокаСтарая = ТаблицаСтарая[Индекс];
// Сравниваем только значимые поля, например, Количество
Если СтрокаТекущая.Количество <> СтрокаСтарая.Количество Тогда
ЗаписатьВРегистр(СтрокаТекущая);
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Важный момент: Данный метод надежен только в том случае, если порядок строк в таблице не меняется и строки не удаляются. Если возможна сортировка, сравнение необходимо делать через поиск по ключевым полям (например, по Номенклатуре).
Проанализируем ситуацию, упомянутую в обсуждении: если ваш регистр сведений имеет режим записи «Подчинение регистратору», вы не можете просто «дописать» одну строку. При записи набора записей с отбором по регистратору 1С по умолчанию замещает все старые записи новыми.
Чтобы изменить только одну строку в подчиненном регистре, нужно придерживаться следующей логики:
РегистрСведенийНаборЗаписей.Пример работы с набором:
Набор = РегистрыСведений.ВашРегистр.СоздатьНаборЗаписей();
Набор.Отбор.Регистратор.Установить(СсылкаНаДокумент);
Набор.Прочитать();
Для Каждого Запись Из Набор Цикл
Если Запись.Номенклатура = ИзмененныйТовар Тогда
Запись.Количество = НовоеКоличество;
КонецЕсли;
КонецЦикла;
Набор.Записать();
Если ваша основная задача — знать, кто и когда изменил данные, и вы используете современную платформу (8.3.11 и выше), рекомендуем рассмотреть системный механизм История данных. Рассмотрим его преимущества:
Для включения этого механизма достаточно в свойствах объекта метаданных (например, документа или регистра) установить свойство История данных = Использовать.
Проанализируем ситуацию из Сообщения 14 («Веду учет поставки»). Если вы фиксируете движение товаров, возможно, использование Регистра накопления будет более правильным решением. Регистры сведений лучше подходят для хранения характеристик, цен или статусов. Если же вам критически важно записывать «дельту» (разницу между тем, что было, и тем, что стало), лучше создавать отдельный документ-корректировку, который будет делать движения в регистр, фиксируя только измененные позиции. Это позволит сохранить прозрачность учета и избежать проблем с блокировками при одновременной работе нескольких пользователей.
Резюмируем: Для быстрой реализации используйте скрытую колонку-флаг. Для обеспечения максимальной точности при сложных манипуляциях с таблицей — сравнение с копией данных. А если нужно отслеживать действия пользователей для аудита — выбирайте системную Историю данных.