При разработке механизмов загрузки данных из внешних источников (текстовых файлов, Excel, XML или сторонних API) программисты 1С часто сталкиваются с проблемой: передаваемое значение оказывается длиннее или точнее, чем это предусмотрено в метаданных конфигурации. Если просто присвоить значение реквизиту, платформа может автоматически обрезать строку или округлить число без какого-либо уведомления, что приведет к потере данных. В этой статье мы подробно разберем, как программно проконтролировать, «влезает» ли значение в реквизит, и как правильно выдать предупреждение пользователю.
Самый прямой путь — обратиться к метаданным конфигурации и сравнить характеристики входящего значения с установленными ограничениями реквизита. Разберем, как получить доступ к свойствам реквизита табличной части. Рассмотрим ситуацию на примере документа РеализацияТоваровУслуг и его табличной части Товары.
Для начала проанализируем, как программно добраться до описания типа реквизита:
// Получаем метаданные конкретного реквизита табличной части
МетаданныеРеквизита = Метаданные.Документы.РеализацияТоваровУслуг.ТабличныеЧасти.Товары.Реквизиты.Номенклатура;
// Тип реквизита (объект ОписаниеТипов)
ОписаниеТипа = МетаданныеРеквизита.Тип;
// Если это строка, проверим длину
Если ОписаниеТипа.СодержитТип(Тип("Строка")) Тогда
МаксДлина = ОписаниеТипа.КвалификаторыСтроки.Длина;
// Здесь можно сравнить со СтрДлина(ВходящееЗначение)
КонецЕсли;
Однако ручная проверка каждого квалификатора (длины, точности, допустимого знака) для разных типов данных — задача трудоемкая и чреватая ошибками. Поэтому перейдем к более универсальному способу.
Этот способ является наиболее «чистым» и рекомендуемым с точки зрения платформы 1С. У объекта ОписаниеТипов есть замечательный метод ПривестиЗначение(). Он берет входное значение и пытается максимально корректно «втиснуть» его в рамки заданного типа, обрезая строки и округляя числа согласно правилам метаданных.
Рассмотрим алгоритм проверки:
ОписаниеТипов из метаданных нужного реквизита.ПривестиЗначение() для входящих данных.Проанализируем пример функции для такой проверки:
Функция ДанныеВлезаютВРеквизит(ВходящееЗначение, ИмяДокумента, ИмяТЧ, ИмяРеквизита) Экспорт
// Получаем описание типа из метаданных
ОписаниеТипа = Метаданные.Документы[ИмяДокумента].ТабличныеЧасти[ИмяТЧ].Реквизиты[ИмяРеквизита].Тип;
// Приводим значение к типу реквизита
ПриведенноеЗначение = ОписаниеТипа.ПривестиЗначение(ВходящееЗначение);
// Сравниваем. Внимание: для адекватного сравнения строк и чисел
// может потребоваться дополнительная логика
Если Строка(ВходящееЗначение) <> Строка(ПриведенноеЗначение) Тогда
Возврат Ложь; // Значение изменилось, значит оно не влезло или исказилось
КонецЕсли;
Возврат Истина;
КонецФункции
Важный нюанс: при сравнении через Строка() стоит быть внимательным к пробелам и форматам чисел. Метод ПривестиЗначение для строк может добавлять или убирать пробелы в зависимости от того, фиксированная длина у строки или переменная.
Проверка чисел часто вызывает затруднения. Например, если в метаданных число имеет длину 15 и точность 3, это значит, что на целую часть отведено 12 знаков (15 минус 3). Если вы попытаетесь записать число с 13 знаками в целой части, платформа его обрежет.
Выясним причину, по которой обычное сравнение строк может не подойти для чисел. Число 100 и строка "100.000" содержательно равны, но строковое сравнение выдаст Ложь. Поэтому для чисел лучше использовать математический подход.
Разберем, как рассчитать максимально возможное число на основе метаданных:
Квалификаторы = ОписаниеТипа.КвалификаторыЧисла;
Длина = Квалификаторы.Длина;
Точность = Квалификаторы.Точность;
// Максимальное целое число, которое влезет
МаксЦелое = Pow(10, Длина - Точность) - 1;
Если Абс(ВходящееЧисло) > МаксЦелое Тогда
Сообщить("Целая часть числа слишком велика!");
КонецЕсли;
Также не забывайте проверять свойство ДопустимыйЗнак. Если в метаданных указано ДопустимыйЗнак.Неотрицательное, а из файла пришло отрицательное число, метод ПривестиЗначение() превратит его в ноль, что тоже является потерей данных.
Существует «ленивый», но действенный способ, который предложили участники обсуждения: попытаться записать значение в реквизит объекта (или строки таблицы значений с типизированными колонками), а затем сравнить то, что получилось, с исходником.
Рассмотрим этот процесс по шагам:
НоваяСтрока.Количество = ЗначениеИзФайла;.Если НоваяСтрока.Количество <> ЗначениеИзФайла Тогда....Этот метод хорош тем, что платформа сама берет на себя всю работу по преобразованию типов. Однако он может быть менее производительным при больших объемах данных из-за создания лишних объектов в памяти.
При работе со строками, загружаемыми из текстовых файлов (особенно формата DBF или TXT с фиксированной шириной), крайне важно использовать функцию СокрЛП() (TrimAll). Часто значение не «влезает» только из-за того, что в конце строки притаились невидимые пробелы.
Посмотрим на пример правильной обработки строки:
ЗначениеОчищенное = СокрЛП(ЗначениеИзФайла);
Если СтрДлина(ЗначениеОчищенное) > МаксДлинаИзМетаданных Тогда
ТекстОшибки = СтрШаблон("Строка '%1' слишком длинная (макс. %2 симв.)", ЗначениеОчищенное, МаксДлинаИзМетаданных);
// Вывод сообщения или запись в лог
КонецЕсли;
Если ваша конфигурация построена на БСП, мы можем воспользоваться готовыми инструментами. Например, модули СтроковыеФункцииКлиентСервер или ОбщегоНазначения содержат функции для валидации данных. Также полезно заглянуть в механизмы обмена данными, где проверка соответствия типов является стандартной процедурой.
Проанализируем ситуацию: если вы реализуете регулярную загрузку, лучшим решением будет создание «буферной» таблицы, где все колонки имеют тип Строка неограниченной длины. Вы загружаете данные «как есть», а затем отдельной процедурой проверяете их на соответствие метаданным целевого документа. Это позволит не прерывать загрузку всей посылки из-за одной некорректной строки и выдать пользователю подробный отчет об ошибках в конце операции.
Мы рассмотрели несколько способов проверки данных на соответствие метаданным. Выбор конкретного метода зависит от ваших задач:
Метаданные.ОписаниеТипов.ПривестиЗначение().Помните, что своевременная проверка данных на этапе загрузки — это залог чистоты информационной базы и отсутствия трудноуловимых ошибок в расчетах и отчетах в будущем.