Как обновить количество в строке табличной части при загрузке данных, используя метод НайтиСтроки?

Программист 1С v8.3 (Управляемые формы)
← На главную

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

Проблема: лишние ключи в структуре поиска

Рассмотрим ситуацию, когда у нас есть структура данных, полученная из файла загрузки. Она содержит "Код детали", "Наименование" и "Количество". Если мы передадим всю эту структуру в метод НайтиСтроки(), платформа будет искать строку, в которой все три параметра совпадают со значениями в таблице. Если количество в файле изменилось (например, было 3, а стало 5), метод НайтиСтроки() вернет пустой массив, так как строки с количеством "5" еще не существует. В результате код добавит новую строку, и мы получим дубль.

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


// Неправильный подход:
// В структуре есть "Количество", которое мешает найти существующую строку при изменении значения
МассивСтрок = ТЗ.НайтиСтроки(СтруктураЗагрузки); 

// Правильный подход:
СтруктураОтбора = Новый Структура;
СтруктураОтбора.Вставить("КодДетали", СтруктураЗагрузки.КодДетали);
СтруктураОтбора.Вставить("НаименованиеДетали", СтруктураЗагрузки.НаименованиеДетали);

// Ищем только по ключевым полям
МассивСтрок = ТЗ.НайтиСтроки(СтруктураОтбора);

Разбор по шагам: алгоритм поиска и обновления

Давайте пошагово разберем корректный алгоритм загрузки данных, который исключает дублирование и правильно обновляет показатели.

  1. Подготовка данных: Сначала мы считываем данные из источника (Excel) и приводим их к нужным типам.
  2. Создание фильтра: Формируем объект Структура, в который включаем только те поля, которые однозначно определяют строку (например, артикул или код).
  3. Поиск: Вызываем метод НайтиСтроки().
  4. Обработка результата: Если массив пуст — добавляем новую строку. Если массив содержит элементы — берем первый (индекс 0).
  5. Заполнение данных: Используем метод ЗаполнитьЗначенияСвойств() для переноса всех данных из загруженной структуры в строку таблицы.

Рассмотрим реализацию этого алгоритма в коде:


// Предположим, ТЗ — это выгруженная табличная часть объекта
// СтруктураДанных — данные, полученные из Excel

Отбор = Новый Структура("КодДетали, НаименованиеДетали", 
                         СтруктураДанных.КодДетали, 
                         СтруктураДанных.НаименованиеДетали);

МассивНаходок = ТЗ.НайтиСтроки(Отбор);

Если МассивНаходок.Количество() > 0 Тогда
    // Строка найдена, будем обновлять её
    СтрокаДляЗаписи = МассивНаходок[0];
Иначе
    // Строка не найдена, создаем новую
    СтрокаДляЗаписи = ТЗ.Добавить();
КонецЕсли;

// Обновляем все реквизиты, включая количество
ЗаполнитьЗначенияСвойств(СтрокаДляЗаписи, СтруктураДанных);

Скрытая причина дублей: длина реквизита в метаданных

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

Проблема кроется в ограничении длины строковых полей в конфигураторе. Например, в файле Excel "Код детали" имеет длину 12 символов ("ДЕ-000012345"), а в метаданных 1С для этого реквизита установлено ограничение в 10 символов. При записи в таблицу значение обрезается до "ДЕ-0000123". Однако в структуре поиска (которую мы получили из Excel) всё еще находится полная строка длиной 12 символов. С точки зрения платформы "ДЕ-000012345" и "ДЕ-0000123" — это разные значения. Поиск не срабатывает, и создается дубль.

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

Оптимизация: работа напрямую с Табличной Частью

Часто в примерах можно увидеть использование промежуточной Таблицы Значений (метод Выгрузить(), поиск в ТЗ, затем Загрузить()). Однако, как отмечают опытные разработчики, это не всегда оправдано. Разберем, почему работа напрямую с табличной частью объекта эффективнее:

Проанализируем пример работы напрямую с объектом:


Отбор = Новый Структура("Артикул", АртикулИзФайла);
НайденныеСтроки = Объект.Товары.НайтиСтроки(Отбор);

Если НайденныеСтроки.Количество() > 0 Тогда
    ТекущаяСтрока = НайденныеСтроки[0];
Иначе
    ТекущаяСтрока = Объект.Товары.Добавить();
КонецЕсли;

ТекущаяСтрока.Количество = КоличествоИзФайла;
// Другие реквизиты...

Важные нюансы метода НайтиСтроки()

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

1. Чувствительность к типам данных. Если в колонке таблицы хранится Число, а в структуре поиска вы передаете Строку (что часто случается при чтении из Excel), поиск всегда будет возвращать пустой массив. Обязательно используйте функции приведения типов: Число(), Дата().

2. Невидимые символы. При загрузке строковых данных (Наименования, Артикулы) из внешних источников в тексте могут присутствовать неразрывные пробелы (символ с кодом 160). Обычная функция СокрЛП() их не удаляет. Рекомендуется использовать очистку строки перед поиском:


ЧистаяСтрока = СтрЗаменить(ИсходнаяСтрока, Символы.НПП, "");
ЧистаяСтрока = СокрЛП(ЧистаяСтрока);

3. Использование индексов. Метод НайтиСтроки() выполняет линейный перебор строк. Если в вашей таблице тысячи позиций, загрузка может замедлиться. В этом случае работа через промежуточную Таблицу Значений с добавлением индексов (ТЗ.Индексы.Добавить("Код")) будет работать в десятки раз быстрее.

4. Список исключаемых свойств. Если вы используете одну структуру и для поиска, и для обновления через ЗаполнитьЗначенияСвойств(), помните о третьем параметре этого метода. Он позволяет перечислить поля, которые не нужно перезаписывать. Это удобно, если вы хотите сохранить, например, внутренние идентификаторы строки (УИД), созданные при первой загрузке.

Резюме

Мы выяснили, что для корректного обновления данных необходимо использовать отдельную структуру для поиска, содержащую только ключевые поля. Мы также проанализировали важность соответствия типов данных и длины строк в метаданных конфигурации. Соблюдение этих правил позволит вам создавать надежные механизмы импорта данных, которые корректно обрабатывают изменения и не засоряют базу данных дублями.

← На главную