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