При реализации механизмов загрузки данных из внешних источников (например, из файлов Excel) программисты часто сталкиваются с задачей обновления уже существующих строк в табличной части документа или справочника. Типичная ситуация: пользователь загружает список номенклатуры, и если деталь с определенным кодом уже есть в таблице, нужно просто обновить её количество, а не добавлять новую строку. В этой статье мы подробно разберем, как правильно использовать метод НайтиСтроки(), почему возникают нежелательные дубли и на какие нюансы платформы стоит обратить внимание.
Рассмотрим ситуацию, когда у нас есть структура данных, полученная из файла загрузки. Она содержит "Код детали", "Наименование" и "Количество". Если мы передадим всю эту структуру в метод НайтиСтроки(), платформа будет искать строку, в которой все три параметра совпадают со значениями в таблице. Если количество в файле изменилось (например, было 3, а стало 5), метод НайтиСтроки() вернет пустой массив, так как строки с количеством "5" еще не существует. В результате код добавит новую строку, и мы получим дубль.
Для решения этой задачи нам необходимо разделить данные на две части: поля идентификации (по которым мы ищем строку) и поля обновления (которые мы записываем в найденную или новую строку). Проанализируем правильный подход к формированию структуры отбора.
// Неправильный подход:
// В структуре есть "Количество", которое мешает найти существующую строку при изменении значения
МассивСтрок = ТЗ.НайтиСтроки(СтруктураЗагрузки);
// Правильный подход:
СтруктураОтбора = Новый Структура;
СтруктураОтбора.Вставить("КодДетали", СтруктураЗагрузки.КодДетали);
СтруктураОтбора.Вставить("НаименованиеДетали", СтруктураЗагрузки.НаименованиеДетали);
// Ищем только по ключевым полям
МассивСтрок = ТЗ.НайтиСтроки(СтруктураОтбора);
Давайте пошагово разберем корректный алгоритм загрузки данных, который исключает дублирование и правильно обновляет показатели.
Структура, в который включаем только те поля, которые однозначно определяют строку (например, артикул или код).НайтиСтроки().ЗаполнитьЗначенияСвойств() для переноса всех данных из загруженной структуры в строку таблицы.Рассмотрим реализацию этого алгоритма в коде:
// Предположим, ТЗ — это выгруженная табличная часть объекта
// СтруктураДанных — данные, полученные из Excel
Отбор = Новый Структура("КодДетали, НаименованиеДетали",
СтруктураДанных.КодДетали,
СтруктураДанных.НаименованиеДетали);
МассивНаходок = ТЗ.НайтиСтроки(Отбор);
Если МассивНаходок.Количество() > 0 Тогда
// Строка найдена, будем обновлять её
СтрокаДляЗаписи = МассивНаходок[0];
Иначе
// Строка не найдена, создаем новую
СтрокаДляЗаписи = ТЗ.Добавить();
КонецЕсли;
// Обновляем все реквизиты, включая количество
ЗаполнитьЗначенияСвойств(СтрокаДляЗаписи, СтруктураДанных);
Иногда даже при правильном разделении структуры на "поиск" и "обновление" дубли продолжают появляться. Выясним причину этой распространенной ошибки. Проанализируем ситуацию: в коде всё верно, типы совпадают, но НайтиСтроки() упорно не находит существующую запись.
Проблема кроется в ограничении длины строковых полей в конфигураторе. Например, в файле Excel "Код детали" имеет длину 12 символов ("ДЕ-000012345"), а в метаданных 1С для этого реквизита установлено ограничение в 10 символов. При записи в таблицу значение обрезается до "ДЕ-0000123". Однако в структуре поиска (которую мы получили из Excel) всё еще находится полная строка длиной 12 символов. С точки зрения платформы "ДЕ-000012345" и "ДЕ-0000123" — это разные значения. Поиск не срабатывает, и создается дубль.
Рекомендация: Всегда проверяйте соответствие максимальной длины строковых реквизитов в вашей базе данных и в загружаемых файлах. Перед поиском полезно принудительно обрезать искомую строку до длины, указанной в метаданных, или использовать функцию Лев().
Часто в примерах можно увидеть использование промежуточной Таблицы Значений (метод Выгрузить(), поиск в ТЗ, затем Загрузить()). Однако, как отмечают опытные разработчики, это не всегда оправдано. Разберем, почему работа напрямую с табличной частью объекта эффективнее:
Объект.ИмяТЧ.НайтиСтроки() вы манипулируете непосредственно строками документа.Выгрузить() и Загрузить().Проанализируем пример работы напрямую с объектом:
Отбор = Новый Структура("Артикул", АртикулИзФайла);
НайденныеСтроки = Объект.Товары.НайтиСтроки(Отбор);
Если НайденныеСтроки.Количество() > 0 Тогда
ТекущаяСтрока = НайденныеСтроки[0];
Иначе
ТекущаяСтрока = Объект.Товары.Добавить();
КонецЕсли;
ТекущаяСтрока.Количество = КоличествоИзФайла;
// Другие реквизиты...
Для стабильной работы механизма загрузки данных рассмотрим еще несколько технических аспектов, которые могут повлиять на результат поиска:
1. Чувствительность к типам данных. Если в колонке таблицы хранится Число, а в структуре поиска вы передаете Строку (что часто случается при чтении из Excel), поиск всегда будет возвращать пустой массив. Обязательно используйте функции приведения типов: Число(), Дата().
2. Невидимые символы. При загрузке строковых данных (Наименования, Артикулы) из внешних источников в тексте могут присутствовать неразрывные пробелы (символ с кодом 160). Обычная функция СокрЛП() их не удаляет. Рекомендуется использовать очистку строки перед поиском:
ЧистаяСтрока = СтрЗаменить(ИсходнаяСтрока, Символы.НПП, "");
ЧистаяСтрока = СокрЛП(ЧистаяСтрока);
3. Использование индексов. Метод НайтиСтроки() выполняет линейный перебор строк. Если в вашей таблице тысячи позиций, загрузка может замедлиться. В этом случае работа через промежуточную Таблицу Значений с добавлением индексов (ТЗ.Индексы.Добавить("Код")) будет работать в десятки раз быстрее.
4. Список исключаемых свойств. Если вы используете одну структуру и для поиска, и для обновления через ЗаполнитьЗначенияСвойств(), помните о третьем параметре этого метода. Он позволяет перечислить поля, которые не нужно перезаписывать. Это удобно, если вы хотите сохранить, например, внутренние идентификаторы строки (УИД), созданные при первой загрузке.
Мы выяснили, что для корректного обновления данных необходимо использовать отдельную структуру для поиска, содержащую только ключевые поля. Мы также проанализировали важность соответствия типов данных и длины строк в метаданных конфигурации. Соблюдение этих правил позволит вам создавать надежные механизмы импорта данных, которые корректно обрабатывают изменения и не засоряют базу данных дублями.