При разработке в среде 1С:Предприятие 8.3 на управляемых формах программисты часто сталкиваются с ситуацией, когда необходимо добавить в таблицу значений (ТЗ) на форме дополнительную колонку, которой нет в метаданных объекта. Проблема заключается в том, что при любом серверном вызове, обновлении данных или закрытии формы значения в этой колонке бесследно исчезают. Давайте разберем, почему это происходит и какими способами можно обеспечить сохранность этих данных.
Прежде всего, проанализируем поведение платформы. В свойствах управляемой формы есть флаги СохранениеДанныхВНастройках и АвтоматическоеСохранениеДанныхВНастройках. Многие полагают, что включение этих опций магическим образом сохранит содержимое всех таблиц. Однако это не так.
Стандартный механизм сохранения настроек предназначен для простых реквизитов формы (числа, строки, даты, булево). Когда речь идет о таблицах, платформа не знает, как сопоставить строки при следующем открытии. Если вы добавили колонку в реквизит формы типа ТаблицаЗначений программно или в редакторе формы (без привязки к метаданным), она считается временной. Более того, если в коде используется типовой метод ЗначениеВРеквизитФормы для обновления данных из объекта, все колонки формы, отсутствующие в метаданных объекта конфигурации, будут просто очищены.
Если данные в колонке должны сохраняться индивидуально для пользователя, наиболее подходящим инструментом является ХранилищеОбщихНастроек. Рассмотрим, как реализовать сохранение и загрузку данных всей таблицы.
Для начала разберем процедуру сохранения данных. Мы будем вызывать её в событии формы ПриЗакрытии или при изменении критически важных данных (например, даты).
&НаСервере
Процедура СохранитьЗначенияКолонкиНаСервере()
// Подготовим структуру для сохранения.
// Поскольку ТЗ нельзя напрямую сериализовать в настройки без потери типов,
// выгрузим ее в массив структур.
ДанныеДляСохранения = Новый Массив;
Для Каждого СтрокаТЗ Из Объект.Товары Цикл
НоваяЗапись = Новый Структура;
НоваяЗапись.Вставить("ИдентификаторСтроки", СтрокаТЗ.НомерСтроки); // Или другой уникальный ключ
НоваяЗапись.Вставить("НашеЧисловоеЗначение", СтрокаТЗ.МояДопКолонка);
ДанныеДляСохранения.Добавить(НоваяЗапись);
КонецЦикла;
ХранилищеОбщихНастроек.Сохранить("МояОбработка_НастройкиКолонки", "ДанныеКолонки", ДанныеДляСохранения);
КонецПроцедуры
Теперь рассмотрим, как восстановить эти данные при открытии формы в событии ПриСозданииНаСервере:
&НаСервере
Процедура ЗагрузитьЗначенияКолонкиНаСервере()
ДанныеДляЗагрузки = ХранилищеОбщихНастроек.Загрузить("МояОбработка_НастройкиКолонки", "ДанныеКолонки");
Если ДанныеДляЗагрузки <> Неопределено Тогда
Для Каждого Запись Из ДанныеДляЗагрузки Цикл
// Ищем строку в нашей таблице по ключу
ПараметрыОтбора = Новый Структура("НомерСтроки", Запись.ИдентификаторСтроки);
НайденныеСтроки = Объект.Товары.НайтиСтроки(ПараметрыОтбора);
Для Каждого СтрокаТЗ Из НайденныеСтроки Цикл
СтрокаТЗ.МояДопКолонка = Запись.НашеЧисловоеЗначение;
КонецЦикла;
КонецЦикла;
КонецЕсли;
КонецПроцедуры
Важный нюанс: Если вы хотите, чтобы данные были общими для всех пользователей, в методе Записать хранилища настроек в параметре "Пользователь" нужно передать пустое значение или системную строку, доступную всем.
Если задача стоит так, чтобы данные в колонке видел любой пользователь сразу после их внесения, хранилища настроек будет недостаточно. В этом случае лучшим решением будет создание непериодического регистра сведений.
Проанализируем преимущества этого метода: данные хранятся в базе данных, они доступны для отчетов и не зависят от сеанса пользователя. В качестве измерений регистра выберите ключевые поля, которые однозначно идентифицируют строку (например, документ-основание и номенклатура), а в ресурсе храните ваше числовое значение.
Алгоритм работы будет следующим:
ПриИзменении ячейки таблицы вызывайте серверную процедуру для записи значения в регистр.ПриЧтенииНаСервере (или ПриСозданииНаСервере) делайте запрос к регистру и заполняйте колонку в таблице формы.
&НаСервере
Процедура ЗаписатьЗначениеВРегистр(КлючСтроки, Значение)
МенеджерЗаписи = РегистрыСведений.МойВспомогательныйРегистр.СоздатьМенеджерЗаписи();
МенеджерЗаписи.ОбъектСвязи = КлючСтроки;
МенеджерЗаписи.ДополнительныйПараметр = Значение;
МенеджерЗаписи.Записать();
КонецПроцедуры
Часто данные пропадают не при закрытии формы, а при штатных действиях, таких как смена даты или склада. В типовых конфигурациях (УТ 11, ERP) такие действия вызывают полную перезагрузку объекта. Чтобы этого избежать, мы применим технику кэширования.
Разберем по шагам:
ЗначениеВРеквизитФормы) проходим циклом по таблице и восстанавливаем значения из соответствия.Посмотрим на пример кода:
&НаСервере
Процедура ОбновитьДанныеССохранениемКолонки()
// 1. Кэшируем значения
КэшЗначений = Новый Соответствие;
Для Каждого Строка Из Объект.Товары Цикл
КэшЗначений.Вставить(Строка.НомерСтроки, Строка.МояДопКолонка);
КонецЦикла;
// 2. Выполняем типовое обновление (которое обычно очищает колонку)
// Например: ПересчитатьЦеныНаСервере();
// 3. Восстанавливаем данные
Для Каждого Строка Из Объект.Товары Цикл
НайденноеЗначение = КэшЗначений.Получить(Строка.НомерСтроки);
Если НайденноеЗначение <> Неопределено Тогда
Строка.МояДопКолонка = НайденноеЗначение;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Если вы добавляете колонку через ИзменитьРеквизиты, помните, что такие реквизиты существуют только пока открыта форма. Чтобы платформа подхватила их в механизм настроек, рассмотрите возможность использования специальных обработчиков:
ПередСохранениемДанныхВНастройкахНаСервере — здесь мы можем программно упаковать данные нашей ТЗ в структуру настроек.ПриЗагрузкеДанныхИзНастроекНаСервере — здесь мы распаковываем данные обратно в таблицу формы.Подведем итог: Для временного сохранения в рамках одного пользователя используйте ХранилищеОбщихНастроек. Для обеспечения доступности данных всем пользователям и надежного хранения — используйте Регистр сведений. Всегда контролируйте моменты перезаполнения таблицы из объекта конфигурации, чтобы вовремя восстанавливать данные в динамических колонках.