При автоматизации загрузки данных из внешних источников, таких как Excel, разработчики часто сталкиваются с проблемой дублирования информации. Одной из наиболее типичных ситуаций является повторная загрузка изображений товаров в конфигурации «Управление торговлей 11» (УТ 11). Если не предусмотреть очистку старых данных, справочник присоединенных файлов быстро разрастается, занимая лишнее место в базе данных или на диске. В этой статье мы подробно разберем, как программно удалить записи по конкретной номенклатуре, проанализируем различные подходы и выберем наиболее безопасный и эффективный способ.
Прежде всего, нам необходимо понять, где именно хранятся данные. В типовых конфигурациях на платформе 1С:Предприятие 8, использующих «Библиотеку стандартных подсистем» (БСП), файлы не хранятся напрямую в карточке товара. Для каждой позиции номенклатуры существует подчиненный справочник. В случае с УТ 11 этот справочник называется НоменклатураПрисоединенныеФайлы. Сама Номенклатура выступает в роли Владельца для элементов этого справочника.
Разберем ситуацию: нам нужно перед загрузкой нового фото найти все старые файлы, принадлежащие конкретному товару, и удалить их, чтобы избежать «мусора» в системе.
Самый простой и понятный способ, который был предложен в ходе обсуждения на форуме, — это использование метода Выбрать(). Этот метод позволяет получить все записи справочника, установив фильтр по владельцу.
Проанализируем пример кода:
// Предположим, что переменная ОбъектНоменклатура содержит ссылку на нужный товар
Выборка = Справочники.НоменклатураПрисоединенныеФайлы.Выбрать(, ОбъектНоменклатура);
Пока Выборка.Следующий() Цикл
// Получаем объект для редактирования
ОбъектФайл = Выборка.ПолучитьОбъект();
// Выполняем физическое удаление из базы данных
Попытка
ОбъектФайл.Удалить();
Исключение
Сообщить("Не удалось удалить файл: " + ОписаниеОшибки());
КонецПопытки;
КонецЦикла;
Рассмотрим подробнее параметры метода Выбрать(). Второй параметр метода как раз отвечает за отбор по владельцу. Это позволяет нам не перебирать весь справочник (который может содержать миллионы записей), а сразу получить узкий список файлов конкретного товара.
Если в вашей базе данных огромное количество присоединенных файлов, использование прямой выборки может быть менее эффективным, чем использование запроса. Запрос работает быстрее на уровне СУБД и позволяет более гибко управлять данными. Например, мы можем захотеть удалить только файлы с определенным расширением (только картинки .jpg) или файлы, загруженные ранее определенной даты.
Разберем реализацию через запрос:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| НоменклатураПрисоединенныеФайлы.Ссылка КАК Ссылка
|ИЗ
| Справочник.НоменклатураПрисоединенныеФайлы КАК НоменклатураПрисоединенныеФайлы
|ГДЕ
| НоменклатураПрисоединенныеФайлы.Владелец = &Владелец";
Запрос.УстановитьПараметр("Владелец", СсылкаНаНоменклатуру);
РезультатЗапроса = Запрос.Выполнить();
ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();
Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
// Важно: для удаления объекта его необходимо сначала получить
ФайлОбъект = ВыборкаДетальныеЗаписи.Ссылка.ПолучитьОбъект();
ФайлОбъект.Удалить();
КонецЦикла;
Хотя вышеуказанные способы решают задачу удаления записей из справочника, работа в современных конфигурациях (таких как УТ 11, ERP 2.5, КА 2.5) требует более глубокого понимания механизмов БСП. Выясним причину, по которой простое удаление объекта через Удалить() может быть не совсем корректным:
Удалить() для справочника может оставить «осиротевший» файл на сервере.ВерсииФайлов.Для корректного удаления в типовых решениях рекомендуется использовать методы общего модуля ПрисоединенныеФайлы. Это гарантирует целостность данных во всех связанных таблицах.
// Пример использования механизмов БСП для удаления всех файлов владельца
МассивФайловДляУдаления = Новый Массив;
Выборка = Справочники.НоменклатураПрисоединенныеФайлы.Выбрать(, СсылкаНаНоменклатуру);
Пока Выборка.Следующий() Цикл
МассивФайловДляУдаления.Добавить(Выборка.Ссылка);
КонецЦикла;
Если МассивФайловДляУдаления.Количество() > 0 Тогда
// Используем штатный метод БСП (название метода может варьироваться от версии БСП)
ПрисоединенныеФайлы.УдалитьФайлы(МассивФайловДляУдаления);
КонецЕсли;
Проанализируем совет, данный в обсуждении (сообщения 25 и 26). Часто полное удаление — это избыточная операция. Если ваша цель — просто обновить фотографию, рассмотрите возможность проверки существования файла перед его перезаписью.
Почему это лучше?
Рассмотрим логику такого процесса: мы ищем, есть ли уже у номенклатуры присоединенный файл. Если есть — мы просто обновляем его двоичные данные. Если нет — создаем новый.
// Псевдокод логики обновления
ФайлСсылка = Справочники.НоменклатураПрисоединенныеФайлы.НайтиПоНаименованию("ОсновноеФото", Ложь, , СсылкаНаНоменклатуру);
Если ФайлСсылка.Пустая() Тогда
// Создаем новый файл средствами БСП
// ПрисоединенныеФайлы.ДобавитьФайл(...);
Иначе
// Обновляем данные существующего
// ПрисоединенныеФайлы.ОбновитьДанныеФайла(ФайлСсылка, НовыеДанные);
КонецЕсли;
В промышленной разработке 1С физическое удаление методом Удалить() используется редко и с большой осторожностью. Рекомендуется использовать метод УстановитьПометкуУдаления(Истина). Это позволит избежать ошибок объектной целостности (битых ссылок), если этот файл был выбран в каком-то документе или заказе. Окончательную чистку базы в таком случае выполнит администратор через стандартную обработку «Удаление помеченных объектов».
Подведем итог: для быстрого решения задачи в рамках простой обработки подойдет метод Выбрать() с отбором по владельцу. Однако для надежной работы в типовой конфигурации УТ 11 лучше использовать программный интерфейс модуля ПрисоединенныеФайлы, предоставляемый БСП.