//ирПортативный Перем ирПортативный Экспорт; //ирПортативный Перем ирОбщий Экспорт; //ирПортативный Перем ирСервер Экспорт; //ирПортативный Перем ирКэш Экспорт; //ирПортативный Перем ирПривилегированный Экспорт; Перем мСервисныйПроцессор Экспорт; // Для программного вызова из Интеграции Перем ТаблицаСсылок Экспорт; Функция РеквизитыДляСервера(Параметры) Экспорт Результат = Новый Структура; Для Каждого МетаРеквизит Из Метаданные().Реквизиты Цикл Если МетаРеквизит.Имя = "КомпоновщикДопПолей" Тогда Продолжить; КонецЕсли; Результат.Вставить(МетаРеквизит.Имя, ЭтотОбъект[МетаРеквизит.Имя]); КонецЦикла; Результат.Вставить("УдаляемыеОбъекты", УдаляемыеОбъекты.Выгрузить()); Результат.Вставить("НеблокирующиеТипы", НеблокирующиеТипы.Выгрузить()); Возврат Результат; КонецФункции Процедура лСостояние(Текст) //#Если Клиент Тогда //Состояние(Текст); //#КонецЕсли КонецПроцедуры Процедура лСостояниеПоиск(Текст) //#Если Клиент Тогда //Состояние("Поиск в "+Текст); //#КонецЕсли КонецПроцедуры Процедура УстановитьЧтоСсылкуНельзяУдалить(Знач Ссылка, Связи, Типы) // убираем эту ссылку из таблицы связей, где она является Ссылкой, т.к. проверять ссылание на неё уже не надо Строки = Связи.НайтиСтроки(Новый Структура("Ссылка",Ссылка)); Если Строки.Количество() = 0 Тогда // ссылка уже исключена из кандидатов на удаление Возврат; КонецЕсли; Для каждого С из Строки Цикл Связи.Удалить(С); КонецЦикла; // убираем эту ссылку из дальнейших проверок в полях базы МассивСсылок = Типы[ТипЗнч(Ссылка)]; МассивСсылок.Удалить(МассивСсылок.Найти(Ссылка)); Если МассивСсылок.Количество() = 0 Тогда Типы.Удалить(ТипЗнч(Ссылка)); КонецЕсли; // надо также убрать из кандидатов все ссылки, для которых данная была связью Строки = Связи.НайтиСтроки(Новый Структура("Данные",Ссылка)); Для каждого С из Строки Цикл УстановитьЧтоСсылкуНельзяУдалить(С.Ссылка,Связи,Типы); КонецЦикла; КонецПроцедуры Процедура ПросмотретьСсылкиИзЗапроса(Запрос, КолвоСсылок, ДляУдаления, Связи, Типы, ЭтоТаблицаОбъектов, ОбъектСвязи, ИмяРегистра = Неопределено, КлючиЗаписей = Неопределено, ОтборКлюча = Неопределено, // для работы с независимыми регистрами сведений Мета = Неопределено // для записи в данные, если данные=Неопределено ) Отбор = Новый Структура("Ссылка,Данные"); Выборка = Запрос.Выполнить().Выбрать(); Индикатор = ирОбщий.ПолучитьИндикаторПроцессаЛкс(Выборка.Количество(), ОбъектСвязи); Пока Выборка.Следующий() Цикл ирОбщий.ОбработатьИндикаторЛкс(Индикатор); К = КолвоСсылок; Пока К > 0 Цикл К = К - 1; Ссылка = Выборка[К]; Если Истина И ЗначениеЗаполнено(Ссылка) И Не (Истина И ДляУдаления И ЭтоТаблицаОбъектов И Ссылка = Выборка.Ссылка) Тогда // проверяем только заполненные ссылки и не учитываем связи с собой же СтрокаСвязи = Связи.Найти(Ссылка, "Ссылка"); Если СтрокаСвязи <> Неопределено Тогда // ссылка - кандидат на удаление Если ДляУдаления Тогда // если ключ записи в качестве ссылки - всегда считаем, что нельзя удалять и надо убрать из кандидатов Если Истина И ЭтоТаблицаОбъектов И Связи.Найти(Выборка.Ссылка, "Ссылка") <> Неопределено Тогда // связанная ссылка находится в таблице кандидатов на удаление, поэтому нельзя пока сказать точно можно удалить текущую или нет Если СтрокаСвязи.Данные = Неопределено Тогда // если ранее еще не было связей с кандидатами на удаление СтрокаСвязи.Данные = Выборка.Ссылка; // поменяли, что есть связь с кандидатом на удаление СтрокаСвязи.ОбъектСвязи = ОбъектСвязи; ИначеЕсли СтрокаСвязи.Данные <> Выборка.Ссылка Тогда // если текущая найденная связь не с этим кандидатом, поищем нет ли с этим Отбор.Ссылка = Ссылка; Отбор.Данные = Выборка.Ссылка; Если Связи.НайтиСтроки(Отбор).Количество() = 0 Тогда // нет связей с таким кандидатом - надо добавить СтрокаСвязи = Связи.Добавить(); ЗаполнитьЗначенияСвойств(СтрокаСвязи, Отбор); СтрокаСвязи.ОбъектСвязи = ОбъектСвязи; КонецЕсли; КонецЕсли; Иначе // связанная ссылка не находится в таблице кандидатов на удаление, поэтому текущую ссылку точно удалять нельзя УстановитьЧтоСсылкуНельзяУдалить(Ссылка,Связи,Типы); КонецЕсли; Иначе // если просто ищем все ссылки на помеченные // если есть ссылка - в качестве ключа берём её, иначе надо где-то хранить ключи и в качестве Данные давать строку из этой таблицы Если КлючиЗаписей = Неопределено Тогда Отбор.Данные = Выборка.Ссылка; Если Отбор.Данные = Неопределено Тогда Если ТипЗнч(Мета) = Тип("Строка") Тогда Мета = ирКэш.ОбъектМДПоПолномуИмениЛкс(Мета); КонецЕсли; Отбор.Данные = Мета; КонецЕсли; Иначе Для каждого Элемент из ОтборКлюча Цикл ОтборКлюча[Элемент.Ключ] = Выборка[Элемент.Ключ]; КонецЦикла; Строки = КлючиЗаписей.НайтиСтроки(ОтборКлюча); Если Строки.Количество() = 0 Тогда СК = КлючиЗаписей.Добавить(); Для каждого Элемент из ОтборКлюча Цикл СК[Элемент.Ключ] = Элемент.Значение; КонецЦикла; НомерСтроки = КлючиЗаписей.Количество()-1; Иначе СК = Строки[0]; НомерСтроки = КлючиЗаписей.Индекс(СК); КонецЕсли; Отбор.Данные = ИмяРегистра + "." + Формат(НомерСтроки, "ЧГ=0"); //КлючЗаписи = РегистрыСведений[ИмяРегистра].СоздатьКлючЗаписи(ОтборКлюча); //Отбор.Данные = ЗначениеВСтрокуВнутр(КлючЗаписи); КонецЕсли; Если СтрокаСвязи.Данные = Неопределено Тогда СтрокаСвязи.Данные = Отбор.Данные; СтрокаСвязи.ОбъектСвязи = ОбъектСвязи; //Если СтрокаСвязи.Данные = Неопределено Тогда // Если ТипЗнч(Мета) = Тип("Строка") Тогда // Мета = ирКэш.ОбъектМДПоПолномуИмениЛкс(Мета); // КонецЕсли; // СтрокаСвязи.Данные = Мета; //КонецЕсли; //ирОбщий.СообщитьЛкс(Строка(Ссылка)+ " <- " + Отбор.Данные); ИначеЕсли СтрокаСвязи.Данные <> Отбор.Данные Тогда Отбор.Ссылка = Ссылка; Если Связи.НайтиСтроки(Отбор).Количество() = 0 Тогда СтрокаСвязи = Связи.Добавить(); ЗаполнитьЗначенияСвойств(СтрокаСвязи, Отбор); //ирОбщий.СообщитьЛкс(Строка(Ссылка)+ " <- " + Отбор.Данные); СтрокаСвязи.ОбъектСвязи = ОбъектСвязи; //Если СтрокаСвязи.Данные = Неопределено Тогда // Если ТипЗнч(Мета) = Тип("Строка") Тогда // Мета = ирКэш.ОбъектМДПоПолномуИмениЛкс(Мета); // КонецЕсли; // СтрокаСвязи.Данные = Мета; //КонецЕсли; КонецЕсли; КонецЕсли; КонецЕсли; КонецЕсли; КонецЕсли; // ЗначениеЗаполнено(Ссылка) КонецЦикла; КонецЦикла; ирОбщий.ОсвободитьИндикаторПроцессаЛкс(); КонецПроцедуры Процедура НайтиСсылкиВТаблице(ДляУдаления,Связи,Типы,ИмяТаблицы,Реквизиты,ИмяСсылка,КлючиЗаписей=Неопределено, Знач Мета=Неопределено // метаданные, чтобы записать в данные если неопределено ) Если Реквизиты.Количество() = 0 Тогда Возврат; КонецЕсли; // надо искать в реквизитах и табличных частях документов Запрос = Новый Запрос; ТекстУсловия = ""; ТекстВыбора = ""; Для каждого Реквизит из Реквизиты Цикл // строим массив ссылок для этого реквизита СсылкиРеквизита = Неопределено; // Пассивный оригинал расположенного ниже однострочного кода. Выполняйте изменения синхронно в обоих вариантах. #Если Сервер И Не Сервер Тогда Для каждого ТекущийТип из Типы Цикл Если Реквизит.Тип.СодержитТип(ТекущийТип.Ключ) Тогда // надо проверить по этому реквизиту ссылки этого типа Если СсылкиРеквизита = Неопределено Тогда СсылкиРеквизита = Новый Массив; КонецЕсли; Для каждого Ссылка из ТекущийТип.Значение Цикл СсылкиРеквизита.Добавить(Ссылка); КонецЦикла; КонецЕсли; КонецЦикла; #КонецЕсли // Однострочный код использован для ускорения. Выше расположен оригинал. Выполняйте изменения синхронно в обоих вариантах. Преобразовано консолью кода из подсистемы "Инструменты разработчика" (http://devtool1c.ucoz.ru) Для каждого ТекущийТип из Типы Цикл   Если Реквизит.Тип.СодержитТип(ТекущийТип.Ключ) Тогда   Если СсылкиРеквизита = Неопределено Тогда   СсылкиРеквизита = Новый Массив;   КонецЕсли;   Для каждого Ссылка из ТекущийТип.Значение Цикл   СсылкиРеквизита.Добавить(Ссылка);   КонецЦикла;   КонецЕсли;   КонецЦикла;   Если СсылкиРеквизита <> Неопределено Тогда ИмяПоля = Реквизит.Имя; ТекстВыбора = ТекстВыбора + "Т." + ИмяПоля + ","; ТекстУсловия = ТекстУсловия + " ИЛИ Т." + ИмяПоля + " В (&" + ИмяПоля + ")"; Запрос.УстановитьПараметр(ИмяПоля, СсылкиРеквизита); КонецЕсли; КонецЦикла; Если ТекстВыбора <> "" Тогда // есть хотя бы один искомый реквизит в документе Отбор = Новый Структура("Ссылка,Данные"); ОтборКлюча = Неопределено; // здесь будет структура для отбора по ключу независимого регистра сведений, если нужно Если КлючиЗаписей = Неопределено Тогда ПолеСсылки = ИмяСсылка + " КАК Ссылка"; ИначеЕсли КлючиЗаписей = ИСТИНА Тогда ПолеСсылки = ""; Иначе // ключ получаем, а не ссылку ПолеСсылки = ""; Для каждого Поле из КлючиЗаписей.Колонки Цикл ПолеСсылки = ПолеСсылки + ", Т." + Поле.Имя; КонецЦикла; ПолеСсылки = Сред(ПолеСсылки, 2); ОтборКлюча = Новый Структура; Для каждого Колонка из КлючиЗаписей.Колонки Цикл ОтборКлюча.Вставить(Колонка.Имя, Неопределено); КонецЦикла; КонецЕсли; Если ПолеСсылки = "" Тогда ПолеСсылки = "Неопределено КАК Ссылка"; КонецЕсли; Запрос.Текст = "ВЫБРАТЬ " + ТекстВыбора + ПолеСсылки + " ИЗ " + ИмяТаблицы + " КАК Т ГДЕ " + Сред(ТекстУсловия, 6); ЭтоТаблицаОбъектов = (ВРЕГ(ИмяСсылка) = "ССЫЛКА"); ПросмотретьСсылкиИзЗапроса(Запрос, Запрос.Параметры.Количество(), ДляУдаления, Связи, Типы, ЭтоТаблицаОбъектов, ИмяТаблицы, ИмяСсылка, КлючиЗаписей, ОтборКлюча, Мета); КонецЕсли; КонецПроцедуры Процедура НайтиСсылкиВТаблицеСубконто(ДляУдаления,Мета,Связи,Типы) // ищет ссылки в таблице субконто регистров бухгалтерии // будем пытаться использовать индекс по Вид(Субконто) + Значение // в процессе работы могут наши типы удаляться из соответствия Типы, надо учитывать эту ситуацию - сбросим их во временный массив МассивТипов = Новый Массив; Для каждого ТекущийТип из Типы Цикл МассивТипов.Добавить(ТекущийТип.Ключ); КонецЦикла; ИмяТаблицы = Мета.ПолноеИмя() + "." + ирОбщий.ПеревестиСтроку("Субконто"); Запрос = Новый Запрос("ВЫБРАТЬ Значение,Регистратор КАК Ссылка ИЗ " + ИмяТаблицы + " ГДЕ Вид=&ВидСубконто И Значение В (&Значение)"); МетаВидыСубконто = Мета.ПланСчетов.ВидыСубконто; Если МетаВидыСубконто <> Неопределено Тогда ЗапросВидаСубконто = Новый Запрос("ВЫБРАТЬ Ссылка,ТипЗначения ИЗ "+МетаВидыСубконто.ПолноеИмя()); ВыборкаВидаСубконто = ЗапросВидаСубконто.Выполнить().Выбрать(); Пока ВыборкаВидаСубконто.Следующий() Цикл Запрос.УстановитьПараметр("ВидСубконто", ВыборкаВидаСубконто.Ссылка); // готовимся выбирать значения субконто этого вида // надо посмотреть какие наши типы подходят в этот ВидСубконто Л = МассивТипов.Количество(); Пока Л > 0 Цикл Л = Л - 1; Если Истина И ВыборкаВидаСубконто.ТипЗначения <> Null И ВыборкаВидаСубконто.ТипЗначения.СодержитТип(МассивТипов[Л]) Тогда // можно проверять наших кандидатов указанного типа с этим видом субконто МассивСсылок = Типы[МассивТипов[Л]]; Если МассивСсылок <> Неопределено Тогда // могут удалиться некоторые типы в процессе работы Запрос.УстановитьПараметр("Значение", МассивСсылок); ПросмотретьСсылкиИзЗапроса(Запрос, 1, ДляУдаления, Связи, Типы, Ложь, ИмяТаблицы); КонецЕсли; КонецЕсли; КонецЦикла; КонецЦикла; КонецЕсли; КонецПроцедуры // НайтиСсылкиВТаблицеСубконто Процедура ОбновитьСтрокуУдаляемогоОбъекта(ЭтаФорма, СтрокаУдаляемогоОбъекта = Неопределено, СоответствиеТипаКМетаданному = Неопределено, Знач ПометкаУдаления = Неопределено, Знач Представление = Неопределено, Знач Предопределенный = Неопределено, Знач ИндексКартинки = Неопределено) Экспорт Если СтрокаУдаляемогоОбъекта = Неопределено Тогда СтрокаУдаляемогоОбъекта = ЭтаФорма.ЭлементыФормы.УдаляемыеОбъекты.ТекущаяСтрока; КонецЕсли; #Если Сервер И Не Сервер Тогда СтрокаУдаляемогоОбъекта = УдаляемыеОбъекты.Добавить(); #КонецЕсли Если Представление = Неопределено Тогда Представление = "" + СтрокаУдаляемогоОбъекта.Ссылка; КонецЕсли; СтрокаУдаляемогоОбъекта.Представление = Представление; ТипУдаляемогоОбъекта = ТипЗнч(СтрокаУдаляемогоОбъекта.Ссылка); Если СоответствиеТипаКМетаданному <> Неопределено Тогда ИмяМетаданного = СоответствиеТипаКМетаданному[ТипУдаляемогоОбъекта]; КонецЕсли; Если ИмяМетаданного = Неопределено Тогда ИмяМетаданного = СтрокаУдаляемогоОбъекта.Ссылка.Метаданные().ПолноеИмя(); Если СоответствиеТипаКМетаданному <> Неопределено Тогда СоответствиеТипаКМетаданному.Вставить(ТипУдаляемогоОбъекта, ИмяМетаданного); КонецЕсли; КонецЕсли; СтрокаУдаляемогоОбъекта.Метаданные = ИмяМетаданного; СтрокаУдаляемогоОбъекта.Предопределенный = Предопределенный; СтрокаУдаляемогоОбъекта.Разрешен = Не СтрокаУдаляемогоОбъекта.Предопределенный; //СтрокаУдаляемогоОбъекта.Удаляется = Истина; Если ПометкаУдаления = Неопределено Тогда ПометкаУдаления = СтрокаУдаляемогоОбъекта.Ссылка.ПометкаУдаления; КонецЕсли; Если ИндексКартинки = Неопределено Тогда Если ПометкаУдаления Тогда СтрокаУдаляемогоОбъекта.ИндексКартинки = 1; КонецЕсли; Иначе СтрокаУдаляемогоОбъекта.ИндексКартинки = ИндексКартинки; КонецЕсли; КонецПроцедуры Функция ДобавитьМассивОбъектовВУдаляемыеОбъекты(МассивОбъектов, ЭтаФорма = Неопределено, УстанавливатьТекущуюСтроку = Ложь, ПредлагатьПомечатьНаУдаление = Ложь) Экспорт ВМассивеБылиНовыеПодходящиеОбъекты = Ложь; ТаблицаОбъектов = УдаляемыеОбъекты.ВыгрузитьКолонки(); Для Каждого Объект Из МассивОбъектов Цикл Если ирОбщий.ЛиТипСсылкиБДЛкс(ТипЗнч(Объект)) Тогда СтрокаОбъекта = ТаблицаОбъектов.Добавить(); СтрокаОбъекта.Ссылка = Объект; Если СтрокаОбъекта.Ссылка <> Объект Тогда // Это тип из расширения конфигурации http://www.hostedredmine.com/issues/886337 ТаблицаОбъектов.Удалить(СтрокаОбъекта); КонецЕсли; КонецЕсли; КонецЦикла; Если ТаблицаОбъектов.Количество() = 0 Тогда Возврат ВМассивеБылиНовыеПодходящиеОбъекты; КонецЕсли; ОбновитьДанныеКандидатов(ТаблицаОбъектов); СписокБылПустым = УдаляемыеОбъекты.Количество() = 0; СоответствиеТипаКМетаданному = Новый Соответствие; Если ПредлагатьПомечатьНаУдаление Тогда ПомечатьНаУдаление = Неопределено; Иначе ПомечатьНаУдаление = Ложь; КонецЕсли; #Если Клиент Тогда Индикатор = ирОбщий.ПолучитьИндикаторПроцессаЛкс(ТаблицаОбъектов.Количество(), "Добавление кандидатов"); #КонецЕсли Для Каждого СтрокаОбъекта Из ТаблицаОбъектов Цикл #Если Клиент Тогда ирОбщий.ОбработатьИндикаторЛкс(Индикатор); #КонецЕсли //Если СтрокаОбъекта.Предопределенный Тогда // ирОбщий.СообщитьЛкс("Предопределенный объект """ + СтрокаОбъекта.Представление + """ нельзя добавлять в кандидаты"); // Продолжить; //КонецЕсли; Если Не СписокБылПустым Тогда СтрокаКандидата = УдаляемыеОбъекты.Найти(СтрокаОбъекта.Ссылка, "Ссылка"); Иначе СтрокаКандидата = Неопределено; КонецЕсли; Если СтрокаКандидата = Неопределено Тогда #Если Клиент Тогда Если ПомечатьНаУдаление = Неопределено И Не СтрокаОбъекта.ПометкаУдаления Тогда Ответ = Вопрос("Хотите пометить на удаление добавляемые кандидаты?", РежимДиалогаВопрос.ДаНет); ПомечатьНаУдаление = Ответ = КодВозвратаДиалога.Да; КонецЕсли; #КонецЕсли Если ПомечатьНаУдаление = Истина И Не СтрокаОбъекта.ПометкаУдаления Тогда //ОбъектКандидата = СтрокаОбъекта.Ссылка.ПолучитьОбъект(); СтруктураОбъекта = ирОбщий.ОбъектБДПоКлючуЛкс(СтрокаОбъекта.Ссылка.Метаданные().ПолноеИмя(), СтрокаОбъекта.Ссылка); ирОбщий.УстановитьПометкуУдаленияОбъектаЛкс(СтруктураОбъекта.Методы,, Истина); СтрокаОбъекта.ПометкаУдаления = Истина; КонецЕсли; СтрокаКандидата = УдаляемыеОбъекты.Добавить(); СтрокаКандидата.Ссылка = СтрокаОбъекта.Ссылка; ОбновитьСтрокуУдаляемогоОбъекта(ЭтаФорма, СтрокаКандидата, СоответствиеТипаКМетаданному, СтрокаОбъекта.ПометкаУдаления, СтрокаОбъекта.Представление, СтрокаОбъекта.Предопределенный, СтрокаОбъекта.ИндексКартинки); ВМассивеБылиНовыеПодходящиеОбъекты = Истина; КонецЕсли; КонецЦикла; #Если Клиент Тогда ирОбщий.ОсвободитьИндикаторПроцессаЛкс(); #КонецЕсли Если Истина И ЭтаФорма <> Неопределено И УстанавливатьТекущуюСтроку И СтрокаКандидата <> Неопределено Тогда ЭтаФорма.ЭлементыФормы.УдаляемыеОбъекты.ТекущаяСтрока = СтрокаКандидата; КонецЕсли; Если ВМассивеБылиНовыеПодходящиеОбъекты Тогда Если ЭтаФорма <> Неопределено Тогда ЭтаФорма.НеобходимоВыполнитьКонтроль = Истина; Если ЭтаФорма.Открыта() Тогда ЭтаФорма.ПодключитьОбработчикОжидания("ПослеИзмененияСоставаКандидатов", 0.1, Истина); КонецЕсли; КонецЕсли; КонецЕсли; Возврат ВМассивеБылиНовыеПодходящиеОбъекты; КонецФункции // Неинтерактивный аналог метода формы вОбновитьПомеченныеНаУдаление Процедура ЗаполнитьКандидатыНаУдалениеПомеченнымиНаУдаление() Экспорт СсылкиНаКандидата.Очистить(); УдаляемыеОбъекты.Очистить(); МассивКУдалению = НайтиПомеченныеНаУдаление(); ДобавитьМассивОбъектовВУдаляемыеОбъекты(МассивКУдалению); КонецПроцедуры Функция ДобавитьНеблокирующийТип(Знач ПолноеИмяМД) Экспорт СтрокаНеблокурующегоТипа = НеблокирующиеТипы.Найти(ПолноеИмяМД); Если СтрокаНеблокурующегоТипа = Неопределено Тогда СтрокаНеблокурующегоТипа = НеблокирующиеТипы.Добавить(); СтрокаНеблокурующегоТипа.Метаданные = ПолноеИмяМД; Если ирОбщий.ЛиКорневойТипРегистраСведенийЛкс(ирОбщий.ПервыйФрагментЛкс(ПолноеИмяМД)) Тогда СтрокаНеблокурующегоТипа.Игнорировать = Истина; КонецЕсли; КонецЕсли; Возврат СтрокаНеблокурующегоТипа КонецФункции Процедура УстановитьНеблокирующиеТипы(МассивПолныхИменМД) Экспорт КопияТаблицы = НеблокирующиеТипы.Выгрузить(); НеблокирующиеТипы.Очистить(); Для Каждого ПолноеИмяМД Из МассивПолныхИменМД Цикл СтрокаНеблокирующегоТипа = ДобавитьНеблокирующийТип(ПолноеИмяМД); СтараяСтрока = КопияТаблицы.Найти(ПолноеИмяМД, "Метаданные"); Если СтараяСтрока <> Неопределено Тогда СтрокаНеблокирующегоТипа.Игнорировать = СтараяСтрока.Игнорировать; КонецЕсли; КонецЦикла; НеблокирующиеТипы.Сортировать("Метаданные"); КонецПроцедуры Функция НайтиПомеченныеНаУдалениеЛкс(Параметры) Экспорт ирОбщий.СостояниеЛкс("Выполняется поиск объектов, помеченных на удаление..."); Попытка //Если ирКэш.НомерИзданияПлатформыЛкс() = "83" Тогда // // Баг платформы 8.3 https://partners.v8.1c.ru/forum/t/1438019/m/1438019 // ПомеченныеОбъекты = НайтиПомеченныеНаУдаление(, ЗначениеВыбора); //Иначе ПомеченныеОбъекты = НайтиПомеченныеНаУдаление(); //КонецЕсли; Исключение ирОбщий.СообщитьЛкс(ОписаниеОшибки()); КонецПопытки; Результат = Новый Структура; Результат.Вставить("ПомеченныеОбъекты", ПомеченныеОбъекты); Результат.Вставить("МассивРазрешенныхТипов", Параметры.МассивРазрешенныхТипов); Возврат Результат; КонецФункции Функция НайтиСсылки(Ссылки, ДляУдаления) Экспорт // Ссылки - массив ссылок объектов для проверки // ДляУдаления - равен Ложь если надо получить результат в виде таблицы, аналогично встроенной функции ПоискПоСсылкам() // - равен Истина для более быстрого поиска объектов, которые можно удалить. Результат возвращается в виде массива объектов для удаления. //лСостояние("Поиск помеченных на удаление..."); // найдём помеченные на удаление //Ссылки = НайтиПомеченныеНаУдаление(); ДатаНачала = ТекущаяДата(); // готовим таблицу найденных ссылок Связи = Новый ТаблицаЗначений; Связи.Колонки.Добавить("Ссылка"); Связи.Колонки.Добавить("Данные"); Связи.Колонки.Добавить("ОбъектСвязи", Новый ОписаниеТипов("Строка",,Новый КвалификаторыСтроки(100))); // раскладываем ссылки по типам Типы = Новый Соответствие; Для каждого Ссылка из Ссылки Цикл ТекущийТип = ТипЗнч(Ссылка); СсылкиТипа = Типы[ТекущийТип]; Если СсылкиТипа = Неопределено Тогда СсылкиТипа = Новый Массив; Типы.Вставить(ТекущийТип,СсылкиТипа); КонецЕсли; СсылкиТипа.Добавить(Ссылка); С = Связи.Добавить(); // начальное заполнение кандидатов С.Ссылка = Ссылка; С.Данные = Неопределено; КонецЦикла; Связи.Индексы.Добавить("Ссылка"); Связи.Индексы.Добавить("Ссылка,Данные"); //Если ДляУдаления Тогда Связи.Индексы.Добавить("Данные"); //КонецЕсли; //Регистраторы = Новый Соответствие; // будет таблица типов регистраторов для регистров. Ключ - имя регистра ТаблицаВсехТаблиц = ирКэш.ТаблицаВсехТаблицБДЛкс(); Индикатор = ирОбщий.ПолучитьИндикаторПроцессаЛкс(ТаблицаВсехТаблиц.Количество(), "Поиск ссылок по таблицам"); Для Каждого ОписаниеТаблицы Из ТаблицаВсехТаблиц Цикл ирОбщий.ОбработатьИндикаторЛкс(Индикатор); Если Ложь Или ирОбщий.ЛиКорневойТипСсылочногоОбъектаБДЛкс(ОписаниеТаблицы.Тип) Или ирОбщий.ЛиТипВложеннойТаблицыБДЛкс(ОписаниеТаблицы.Тип) Тогда КлючевоеПоле = "Ссылка"; ИначеЕсли Ложь Или ОписаниеТаблицы.Тип = "РегистрНакопления" Или ОписаниеТаблицы.Тип = "РегистрРасчета" Или ОписаниеТаблицы.Тип = "Последовательность" //Или ОписаниеТаблицы.Тип = "Границы" Тогда КлючевоеПоле = "Регистратор"; ИначеЕсли Ложь Или ОписаниеТаблицы.Тип = "Константа" Тогда КлючевоеПоле = "НЕОПРЕДЕЛЕНО"; ИначеЕсли Ложь Или ОписаниеТаблицы.Тип = "Перерасчет" Тогда КлючевоеПоле = "ОбъектПерерасчета"; Иначе Продолжить; КонецЕсли; Если ирОбщий.ПроверитьПропуститьНедоступнуюТаблицуБДЛкс(ОписаниеТаблицы) Тогда Продолжить; КонецЕсли; Реквизиты = Новый ТаблицаЗначений; Реквизиты.Колонки.Добавить("Имя", Новый ОписаниеТипов("Строка")); Реквизиты.Колонки.Добавить("Тип"); ПоляТаблицыБД = ирКэш.ПоляТаблицыБДЛкс(ОписаниеТаблицы.ПолноеИмя); #Если Сервер И Не Сервер Тогда ПоляТаблицыБД = НайтиПоСсылкам().Колонки; #КонецЕсли // Пассивный оригинал расположенного ниже однострочного кода. Выполняйте изменения синхронно в обоих вариантах. #Если Сервер И Не Сервер Тогда Для Каждого ПолеТаблицыБД Из ПоляТаблицыБД Цикл Если Ложь Или ПолеТаблицыБД.ТипЗначения.СодержитТип(Тип("ТаблицаЗначений")) Или ирОбщий.СтрокиРавныЛкс(ПолеТаблицыБД.Имя, КлючевоеПоле) Тогда Продолжить; КонецЕсли; Реквизит = Реквизиты.Добавить(); Реквизит.Имя = ПолеТаблицыБД.Имя; Реквизит.Тип = ПолеТаблицыБД.ТипЗначения; КонецЦикла; #КонецЕсли // Однострочный код использован для ускорения. Выше расположен оригинал. Выполняйте изменения синхронно в обоих вариантах. Преобразовано консолью кода из подсистемы "Инструменты разработчика" (http://devtool1c.ucoz.ru) Для Каждого ПолеТаблицыБД Из ПоляТаблицыБД Цикл   Если Ложь   Или ПолеТаблицыБД.ТипЗначения.СодержитТип(Тип("ТаблицаЗначений"))   Или ирОбщий.СтрокиРавныЛкс(ПолеТаблицыБД.Имя, КлючевоеПоле)   Тогда   Продолжить;   КонецЕсли;   Реквизит = Реквизиты.Добавить();   Реквизит.Имя = ПолеТаблицыБД.Имя;   Реквизит.Тип = ПолеТаблицыБД.ТипЗначения;   КонецЦикла;   НайтиСсылкиВТаблице(ДляУдаления, Связи, Типы, ОписаниеТаблицы.ПолноеИмя, Реквизиты, КлючевоеПоле,, ОписаниеТаблицы.ПолноеИмя); КонецЦикла; ирОбщий.ОсвободитьИндикаторПроцессаЛкс(); ////////////////////////// Регистры бухгалтерии Индикатор = ирОбщий.ПолучитьИндикаторПроцессаЛкс(Метаданные.РегистрыБухгалтерии.Количество(), "Регистры бухгалтерии"); Для каждого Мета из Метаданные.РегистрыБухгалтерии Цикл ирОбщий.ОбработатьИндикаторЛкс(Индикатор); ИмяТаблицы = Мета.ПолноеИмя(); ОписаниеТаблицы = ирОбщий.ОписаниеТаблицыБДЛкс(ИмяТаблицы); Если ирОбщий.ПроверитьПропуститьНедоступнуюТаблицуБДЛкс(ОписаниеТаблицы) Тогда Продолжить; КонецЕсли; //лСостояниеПоиск(ИмяТаблицы); // надо проверить по регистраторам для зависимых регистров // для независимых будем ключ записи искать Реквизиты = Новый Массив; Для каждого Реквизит из Мета.Измерения Цикл Если Мета.Корреспонденция И Не Реквизит.Балансовый Тогда Реквизиты.Добавить(Новый Структура("Имя,Тип", Реквизит.Имя+"Кт", Реквизит.Тип)); Реквизиты.Добавить(Новый Структура("Имя,Тип", Реквизит.Имя+"Дт", Реквизит.Тип)); Иначе Реквизиты.Добавить(Реквизит); КонецЕсли; КонецЦикла; Для каждого Реквизит из Мета.Ресурсы Цикл Если Мета.Корреспонденция И Не Реквизит.Балансовый Тогда Реквизиты.Добавить(Новый Структура("Имя,Тип", Реквизит.Имя+"Кт", Реквизит.Тип)); Реквизиты.Добавить(Новый Структура("Имя,Тип", Реквизит.Имя+"Дт", Реквизит.Тип)); Иначе Реквизиты.Добавить(Реквизит); КонецЕсли; КонецЦикла; Для каждого Реквизит из Мета.Реквизиты Цикл Реквизиты.Добавить(Реквизит); КонецЦикла; ОписаниеТиповСсылки = Новый ОписаниеТипов(ирОбщий.ИмяТипаИзПолногоИмениМДЛкс(Мета.ПланСчетов)); Если Мета.Корреспонденция Тогда Реквизиты.Добавить(Новый Структура("Имя,Тип","СчетКт", ОписаниеТиповСсылки)); Реквизиты.Добавить(Новый Структура("Имя,Тип","СчетДт", ОписаниеТиповСсылки)); Иначе Реквизиты.Добавить(Новый Структура("Имя,Тип","Счет", ОписаниеТиповСсылки)); КонецЕсли; //Реквизиты.Добавить(Новый Структура("Имя,Тип","Регистратор",Новый ОписаниеТипов(Регистраторы[ИмяТаблицы]))); НайтиСсылкиВТаблице(ДляУдаления, Связи, Типы, ИмяТаблицы, Реквизиты, "Регистратор"); // надо поискать ещё в таблице субконто НайтиСсылкиВТаблицеСубконто(ДляУдаления, Мета, Связи, Типы); КонецЦикла; ирОбщий.ОсвободитьИндикаторПроцессаЛкс(); /////////// Регистры сведений ТаблицыКлючей = Новый Структура; Индикатор = ирОбщий.ПолучитьИндикаторПроцессаЛкс(Метаданные.РегистрыСведений.Количество(), "Регистры сведений"); Для каждого Мета из Метаданные.РегистрыСведений Цикл ирОбщий.ОбработатьИндикаторЛкс(Индикатор); ИмяТаблицы = Мета.ПолноеИмя(); ОписаниеТаблицы = ирОбщий.ОписаниеТаблицыБДЛкс(ИмяТаблицы); Если ирОбщий.ПроверитьПропуститьНедоступнуюТаблицуБДЛкс(ОписаниеТаблицы) Тогда Продолжить; КонецЕсли; //лСостояниеПоиск(ИмяТаблицы); // надо проверить по регистраторам для зависимых регистров // для независимых будем ключ записи искать Реквизиты = Новый Массив; Для каждого Реквизит из Мета.Измерения Цикл // не будем проверять измерения со признаком "Ведущее", т.к. они должны автоматически удаляться при удалении объекта Если Не (ДляУдаления И Реквизит.Ведущее) Тогда Реквизиты.Добавить(Реквизит); КонецЕсли; КонецЦикла; Для каждого Реквизит из Мета.Ресурсы Цикл Реквизиты.Добавить(Реквизит); КонецЦикла; Для каждого Реквизит из Мета.Реквизиты Цикл Реквизиты.Добавить(Реквизит); КонецЦикла; Если Мета.РежимЗаписи = Метаданные.СвойстваОбъектов.РежимЗаписиРегистра.ПодчинениеРегистратору Тогда ИмяСсылка = "Регистратор"; //Реквизиты.Добавить(Новый Структура("Имя,Тип","Регистратор",Новый ОписаниеТипов(Регистраторы[ИмяТаблицы]))); КлючиЗаписей = Неопределено; Иначе Если ДляУдаления Тогда ИмяСсылка = ""; КлючиЗаписей = Истина; Иначе ИмяСсылка = Мета.Имя; КлючиЗаписей = Новый ТаблицаЗначений; ТаблицыКлючей.Вставить(Мета.Имя,КлючиЗаписей); СтрокаИндекса = ""; // надо набор измерений основного отбора и период (если основной отбор по периоду) в качестве ключей // как искать в связях? - надо будет ещё одну дополнительную таблицу для хранения ключей независимого регистра сведений Если Мета.ПериодичностьРегистраСведений <> Метаданные.СвойстваОбъектов.ПериодичностьРегистраСведений.Непериодический Тогда //Если Мета.ОсновнойОтборПоПериоду Тогда ИмяПоля = "Период"; КлючиЗаписей.Колонки.Добавить(ИмяПоля,Новый ОписаниеТипов("Дата",,,Новый КвалификаторыДаты(ЧастиДаты.ДатаВремя))); СтрокаИндекса = СтрокаИндекса + "," + ИмяПоля; КонецЕсли; Для каждого Измерение из Мета.Измерения Цикл //Если Измерение.ОсновнойОтбор Тогда ИмяПоля = Измерение.Имя; КлючиЗаписей.Колонки.Добавить(ИмяПоля, Измерение.Тип); СтрокаИндекса = СтрокаИндекса + "," + ИмяПоля; //КонецЕсли; КонецЦикла; КлючиЗаписей.Индексы.Добавить(Сред(СтрокаИндекса, 2)); КонецЕсли; КонецЕсли; НайтиСсылкиВТаблице(ДляУдаления,Связи,Типы,ИмяТаблицы,Реквизиты,ИмяСсылка,КлючиЗаписей,Мета); КонецЦикла; ирОбщий.ОсвободитьИндикаторПроцессаЛкс(); //////////////////////////// Регистры расчёта //Индикатор = ирОбщий.ПолучитьИндикаторПроцессаЛкс(Метаданные.РегистрыРасчета.Количество(), "Регистры расчета"); //Для каждого Мета из Метаданные.РегистрыРасчета Цикл // ирОбщий.ОбработатьИндикаторЛкс(Индикатор); // ИмяТаблицы = Мета.ПолноеИмя(); // //лСостояниеПоиск(ИмяТаблицы); // // надо проверить по регистраторам для зависимых регистров // // для независимых будем ключ записи искать // Реквизиты = Новый Массив; // Для каждого Реквизит из Мета.Измерения Цикл // Реквизиты.Добавить(Реквизит); // КонецЦикла; // Для каждого Реквизит из Мета.Ресурсы Цикл // Реквизиты.Добавить(Реквизит); // КонецЦикла; // Для каждого Реквизит из Мета.Реквизиты Цикл // Реквизиты.Добавить(Реквизит); // КонецЦикла; // Реквизиты.Добавить(Новый Структура("Имя,Тип","ВидРасчета",Новый ОписаниеТипов(ТипСсылкаСтрокой(Мета.ПланВидовРасчета)))); // //ОписаниеТиповРегистраторы = Новый ОписаниеТипов(Регистраторы[ИмяТаблицы]); // //Реквизиты.Добавить(Новый Структура("Имя,Тип","Регистратор",ОписаниеТиповРегистраторы)); // НайтиСсылкиВТаблице(ДляУдаления,Связи,Типы,ИмяТаблицы,Реквизиты,"Регистратор"); // // перерасчеты тоже проверим // //Для каждого Перерасчет из Мета.Перерасчеты Цикл // // ИмяПерерасчета = ИмяТаблицы+"."+Перерасчет.Имя; // // лСостояниеПоиск(ИмяПерерасчета); // // // // Реквизиты.Очистить(); // // Для каждого Реквизит из Перерасчет.Измерения Цикл // // Реквизиты.Добавить(Мета.Измерения[Реквизит.Имя]); // // КонецЦикла; // // Реквизиты.Добавить(Новый Структура("Имя,Тип","ВидРасчета",Новый ОписаниеТипов(ТипСсылкаСтрокой(Мета.ПланВидовРасчета)))); // // Реквизиты.Добавить(Новый Структура("Имя,Тип","ОбъектПерерасчета",ОписаниеТиповРегистраторы)); // // НайтиСсылкиВТаблице(ДляУдаления,Связи,Типы,ИмяПерерасчета,Реквизиты,"Регистратор"); // // // //КонецЦикла; //КонецЦикла; //ирОбщий.ОсвободитьИндикаторПроцессаЛкс(); Если ДляУдаления Тогда Связи.Свернуть("Ссылка"); лСостояние("Поиск закончен."); Возврат Связи.ВыгрузитьКолонку("Ссылка"); Иначе Строки = Связи.НайтиСтроки(Новый Структура("Данные",Неопределено)); Для каждого С из Строки Цикл Связи.Удалить(С); КонецЦикла; // надо заменить ссылки на ключи независимых регистров сведений на сами ключи ТипСтрока = Тип("Строка"); Связи.Колонки.Добавить("Метаданные"); Для каждого С из Связи Цикл Если ТипЗнч(С.Данные) = ТипСтрока Тогда // выделяем имя таблицы и номер строки из таблицы Позиция = Найти(С.Данные,"."); ИмяРегистра = Лев(С.Данные,Позиция-1); Если Позиция = СтрДлина(С.Данные) Тогда НомерСтроки = 0; Иначе НомерСтроки = Число(Сред(С.Данные,Позиция+1)); КонецЕсли; ТЗ = ТаблицыКлючей[ИмяРегистра]; СК = ТЗ[НомерСтроки]; Отбор = Новый Структура; Для каждого Колонка из ТЗ.Колонки Цикл Отбор.Вставить(Колонка.Имя,СК[Колонка.Имя]); КонецЦикла; С.Данные = РегистрыСведений[ИмяРегистра].СоздатьКлючЗаписи(Отбор); С.Метаданные = Метаданные.РегистрыСведений[ИмяРегистра]; ИначеЕсли ТипЗнч(С.Данные)=Тип("ОбъектМетаданных") Тогда С.Метаданные = С.Данные; С.Данные = Неопределено; Иначе // бывает, что данные = Неопределено - тогда как найти метаданные? С.Метаданные = С.Данные.Метаданные(); Если С.Данные = Неопределено Тогда ВызватьИсключение "Невозможно установить поле Метаданные по значению Неопределено."; КонецЕсли; КонецЕсли; КонецЦикла; Длительность = ТекущаяДата() - ДатаНачала; Если Длительность > 60 Тогда ирОбщий.СообщитьЛкс("Поиск ссылок выполнен за " + XMLСтрока(Длительность) + "с. Найдено " + XMLСтрока(Связи.Количество()) + " ссылок."); КонецЕсли; Возврат Связи; КонецЕсли; КонецФункции Функция ОбновитьДанныеКандидатов(ТаблицаОбъектов = Неопределено, МинимизироватьТипы = Истина, ДополнительноеПоле = "") Экспорт Если ТаблицаОбъектов = Неопределено Тогда ТаблицаОбъектов = УдаляемыеОбъекты.Выгрузить(); КонецЕсли; Если МинимизироватьТипы Тогда ТаблицаОбъектов = ирОбщий.СузитьТипыКолонокТаблицыБезПотериДанныхЛкс(ТаблицаОбъектов); // Так будет меньше неявных соединений в запросе КонецЕсли; Запрос = Новый Запрос; ТекстЗапроса = " |ВЫБРАТЬ РАЗЛИЧНЫЕ * ПОМЕСТИТЬ ТЗ ИЗ &ТЗ КАК ТЗ; |ВЫБРАТЬ ТЗ.Разрешен, ТЗ.Удаляется, ТЗ.НеудаляемыхСсылок, ТЗ.Ссылок, ТЗ.Метаданные, ТЗ.Ссылка, ЕСТЬNULL(ТЗ.Ссылка.ПометкаУдаления, ИСТИНА) КАК ПометкаУдаления, |Представление(ТЗ.Ссылка) КАК Представление, ЕСТЬNULL(ТЗ.Ссылка.Предопределенный, Ложь) КАК Предопределенный, |ВЫБОР КОГДА ЕСТЬNULL(ТЗ.Ссылка.ПометкаУдаления, ИСТИНА) ТОГДА 1 КОГДА ЕСТЬNULL(ТЗ.Ссылка.Предопределенный, Ложь) ТОГДА 2 ИНАЧЕ 0 КОНЕЦ КАК ИндексКартинки "; Если ЗначениеЗаполнено(ДополнительноеПоле) Тогда ТекстЗапроса = ТекстЗапроса + " |, ТЗ.Ссылка." + ДополнительноеПоле + " КАК " + ДополнительноеПоле; КонецЕсли; ТекстЗапроса = ТекстЗапроса + " |ИЗ ТЗ КАК ТЗ"; Запрос.Текст = ТекстЗапроса; Запрос.УстановитьПараметр("ТЗ", ТаблицаОбъектов); // Проверяем наличие хотя бы одного типа с полем Предопределенный ПроверочныйЗапрос = Новый ПостроительЗапроса; ПроверочныйЗапрос.Текст = ирОбщий.ПолучитьЗапросИмитаторКоллекцииПолейЛкс(ТаблицаОбъектов.Колонки); ПроверочныйЗапрос.ЗаполнитьНастройки(); Если ПроверочныйЗапрос.ДоступныеПоля.Ссылка.Поля.Найти("Предопределенный") = Неопределено Тогда Запрос.Текст = СтрЗаменить(Запрос.Текст, "ТЗ.Ссылка.Предопределенный", "Ложь"); КонецЕсли; // Может происходить ошибка платформы 8.3.10 "Несовместимые типы" https://partners.v8.1c.ru/forum/t/1617826/m/1617826 // Если она произошла, то попробуйте обрабатывать кандидатов мелкими порциями ТаблицаОбъектов = Запрос.Выполнить().Выгрузить(); Возврат ТаблицаОбъектов; КонецФункции // Выполняет поиск ссылок на помеченные на удаление объекты, // заполняет ими таблицу значений "ТаблицаСсылок", // производит контроль на возможность удаления // // Результат - Булево - нужно ли выполнять повторный контроль Функция КонтролироватьСсылкиНаКандидаты(Параметры = Неопределено) Экспорт выхДобавленыКандидаты = Ложь; МассивКУдалению = Новый Массив; Для Каждого СтрокаУдаляемогоОбъекта из УдаляемыеОбъекты Цикл Если СтрокаУдаляемогоОбъекта.Разрешен Тогда МассивКУдалению.Добавить(СтрокаУдаляемогоОбъекта.Ссылка); СтрокаУдаляемогоОбъекта.Удаляется = Истина; Иначе СтрокаУдаляемогоОбъекта.Удаляется = Ложь; КонецЕсли; СтрокаУдаляемогоОбъекта.НеУдаляемыхСсылок = 0; СтрокаУдаляемогоОбъекта.Ссылок = 0; КонецЦикла; СсылкиНаКандидата.Очистить(); Если СтандартныйПоискСсылок Тогда ТаблицаСсылок = НайтиПоСсылкам(МассивКУдалению); ирОбщий.ПеревестиКолонкиНайтиПоСсылкамЛкс(ТаблицаСсылок); Иначе ТаблицаСсылок = НайтиСсылки(МассивКУдалению, Ложь); КонецЕсли; ТаблицаСсылок.Колонки.Добавить("КлючЗаписиРегистраСведений"); ДатаНачала = ТекущаяДата(); ТаблицаСсылок.Колонки.Добавить("СсылкаДанного"); ТаблицаСсылок.Колонки.Добавить("Удаляется"); Для Каждого МетаРеквизит Из Метаданные().ТабличныеЧасти.СсылкиНаКандидата.Реквизиты Цикл Если ТаблицаСсылок.Колонки.Найти(МетаРеквизит.Имя) = Неопределено Тогда ТаблицаСсылок.Колонки.Добавить(МетаРеквизит.Имя); КонецЕсли; КонецЦикла; МассивДобавляемыхКандидатов = Новый Массив; СоответствиеСсылокЧтенияПометкиУдаления = Новый Соответствие; СоответствиеТиповЧтенияПометкиУдаления = Новый Соответствие; // Для поиска строк ТЧ по ссыке будем использовать соотвествие СоответствиеКандидатов = Новый Соответствие; Для Каждого СтрокаКандидата Из УдаляемыеОбъекты Цикл СоответствиеКандидатов[СтрокаКандидата.Ссылка] = СтрокаКандидата; КонецЦикла; ПредставлениеПроцесса = "Анализ ссылающихся объектов"; Если мСервисныйПроцессор <> Неопределено Тогда Индикатор = мСервисныйПроцессор.ПолучитьИндикаторПроцесса(ТаблицаСсылок.Количество(), ПредставлениеПроцесса); Иначе Индикатор = ирОбщий.ПолучитьИндикаторПроцессаЛкс(ТаблицаСсылок.Количество(), ПредставлениеПроцесса); КонецЕсли; Для каждого ЭлементТаблицыСсылок из ТаблицаСсылок Цикл Если мСервисныйПроцессор <> Неопределено Тогда мСервисныйПроцессор.ОбновитьИндикатор(Индикатор); Иначе ирОбщий.ОбработатьИндикаторЛкс(Индикатор); КонецЕсли; Ссылка = ЭлементТаблицыСсылок.ссылка; Данные = ЭлементТаблицыСсылок.Данные; //СтрокаСсылки = ТаблицаКандидатов.Найти(Ссылка, "Ссылка"); СтрокаКандидатаСсылки = СоответствиеКандидатов[Ссылка]; МетаданныеДанных = ЭлементТаблицыСсылок.Метаданные; ИмяМетаданных = МетаданныеДанных.ПолноеИмя(); ЭтоРегистрСведений = ирОбщий.ЛиКорневойТипРегистраСведенийЛкс(ирОбщий.ПервыйФрагментЛкс(ИмяМетаданных)); Если ЭтоРегистрСведений Тогда ЭлементТаблицыСсылок.КлючЗаписиРегистраСведений = ЭлементТаблицыСсылок.Данные; ИзмеренияРегистраСведений = МетаданныеДанных.Измерения; УдаляетсяРегистрСведений = Ложь; Для Каждого Измерение Из ИзмеренияРегистраСведений Цикл Если Измерение.Ведущее Тогда Если Ссылка = Данные[Измерение.Имя] Тогда УдаляетсяРегистрСведений = Истина; ЭлементТаблицыСсылок.Данные = Ссылка; Данные = ссылка; Прервать; КонецЕсли; КонецЕсли; КонецЦикла; Если Не УдаляетсяРегистрСведений Тогда ЭлементТаблицыСсылок.Данные = Неопределено; Данные = Неопределено; КонецЕсли; КонецЕсли; СтрокаНеблокирующегоТипа = НеблокирующиеТипы.Найти(ИмяМетаданных, "Метаданные"); Если Данные = Неопределено Тогда ЭлементТаблицыСсылок.ИндексКартинки = 3; СтрокаКандидатаОбъектаСодержащегоСсылку = Неопределено; Иначе Если ТипЗнч(Данные) = Тип("Строка") Тогда СтрокаКандидатаОбъектаСодержащегоСсылку = Неопределено; ИначеЕсли Данные = Ссылка Тогда СтрокаКандидатаОбъектаСодержащегоСсылку = СтрокаКандидатаСсылки; Иначе //СтрокаДанного = ТаблицаКандидатов.Найти(Данные, "Ссылка"); СтрокаКандидатаОбъектаСодержащегоСсылку = СоответствиеКандидатов[Данные]; КонецЕсли; Если СтрокаНеблокирующегоТипа <> Неопределено И Не СтрокаНеблокирующегоТипа.Игнорировать Тогда МассивДобавляемыхКандидатов.Добавить(Данные); КонецЕсли; СоответствиеСсылокЧтенияПометкиУдаления[Данные] = 1; СоответствиеТиповЧтенияПометкиУдаления[ТипЗнч(Данные)] = 1; КонецЕсли; СтрокаКандидатаСсылки.Ссылок = СтрокаКандидатаСсылки.Ссылок + 1; УдаляетсяСсылка = СтрокаКандидатаСсылки.Удаляется; Если СтрокаКандидатаОбъектаСодержащегоСсылку = Неопределено Тогда Если Ложь //Или ЭтоРегистрСведений Или СтрокаНеблокирующегоТипа <> Неопределено Тогда УдаляетсяОбъектСодержащийСсылку = Истина; Иначе УдаляетсяОбъектСодержащийСсылку = Ложь; Если УдаляетсяСсылка Тогда СтрокаКандидатаСсылки.Удаляется = Ложь; КонецЕсли; КонецЕсли; Иначе Если СтрокаКандидатаОбъектаСодержащегоСсылку.Ссылка = Ссылка Тогда УдаляетсяОбъектСодержащийСсылку = СтрокаКандидатаОбъектаСодержащегоСсылку.Разрешен; Иначе УдаляетсяОбъектСодержащийСсылку = СтрокаКандидатаОбъектаСодержащегоСсылку.Удаляется; КонецЕсли; Если Не УдаляетсяОбъектСодержащийСсылку Тогда Если УдаляетсяСсылка Тогда СтрокаКандидатаСсылки.Удаляется = ложь; КонецЕсли; КонецЕсли; КонецЕсли; Если УдаляетсяОбъектСодержащийСсылку = ложь Тогда СтрокаКандидатаСсылки.НеУдаляемыхСсылок = СтрокаКандидатаСсылки.НеУдаляемыхСсылок + 1; КонецЕсли; ЭлементТаблицыСсылок.Удаляется = УдаляетсяОбъектСодержащийСсылку; Если Данные <> ЭлементТаблицыСсылок.Данные Тогда // Для ускорения ЭлементТаблицыСсылок.СсылкаДанного = Данные; КонецЕсли; ЭлементТаблицыСсылок.Метаданные = ЭлементТаблицыСсылок.Метаданные.ПолноеИмя(); КонецЦикла; Если мСервисныйПроцессор <> Неопределено Тогда мСервисныйПроцессор.ОсвободитьИндикаторПроцесса(Индикатор); Иначе ирОбщий.ОсвободитьИндикаторПроцессаЛкс(Индикатор); КонецЕсли; Если МассивДобавляемыхКандидатов.Количество() > 0 Тогда Если ДобавитьМассивОбъектовВУдаляемыеОбъекты(МассивДобавляемыхКандидатов) Тогда ирОбщий.СообщитьЛкс("Состав кандидатов на удаление был дополнен. Рекомендуется выполнить контроль заново"); выхДобавленыКандидаты = Истина; КонецЕсли; КонецЕсли; Если СоответствиеТиповЧтенияПометкиУдаления.Количество() > 0 Тогда МассивТиповКолонки = Новый Массив; Для Каждого КлючИЗначение Из СоответствиеТиповЧтенияПометкиУдаления Цикл МассивТиповКолонки.Добавить(КлючИЗначение.Ключ); КонецЦикла; ТаблицаЧтенияПометкиУдаления = УдаляемыеОбъекты.ВыгрузитьКолонки(); ТаблицаЧтенияПометкиУдаления.Колонки.Удалить("Ссылка"); ТаблицаЧтенияПометкиУдаления.Колонки.Добавить("Ссылка", Новый ОписаниеТипов(МассивТиповКолонки)); Для Каждого КлючИЗначение Из СоответствиеСсылокЧтенияПометкиУдаления Цикл СтрокаОбъекта = ТаблицаЧтенияПометкиУдаления.Добавить(); СтрокаОбъекта.Ссылка = КлючИЗначение.Ключ; КонецЦикла; СчитанныеПометки = ОбновитьДанныеКандидатов(ТаблицаЧтенияПометкиУдаления, Ложь); ПредставлениеПроцесса = "Заполнение пометок на удаление"; Если мСервисныйПроцессор <> Неопределено Тогда Индикатор = мСервисныйПроцессор.ПолучитьИндикаторПроцесса(СчитанныеПометки.Количество(), ПредставлениеПроцесса); Иначе Индикатор = ирОбщий.ПолучитьИндикаторПроцессаЛкс(СчитанныеПометки.Количество(), ПредставлениеПроцесса); КонецЕсли; Для Каждого СтрокаСчитаннойПометки Из СчитанныеПометки Цикл Если мСервисныйПроцессор <> Неопределено Тогда мСервисныйПроцессор.ОбновитьИндикатор(Индикатор); Иначе ирОбщий.ОбработатьИндикаторЛкс(Индикатор); КонецЕсли; СтрокиСсылающегося = ТаблицаСсылок.НайтиСтроки(Новый Структура("Данные", СтрокаСчитаннойПометки.Ссылка)); Для Каждого СтрокаСсылающегося Из СтрокиСсылающегося Цикл СтрокаСсылающегося.ИндексКартинки = ?(СтрокаСчитаннойПометки.ПометкаУдаления, 4, 3); // В конце будем более подробно вычислять состояние КонецЦикла; КонецЦикла; Если мСервисныйПроцессор <> Неопределено Тогда мСервисныйПроцессор.ОсвободитьИндикаторПроцесса(Индикатор); Иначе ирОбщий.ОсвободитьИндикаторПроцессаЛкс(Индикатор); КонецЕсли; КонецЕсли; НашлиДляИсключения = Истина; Пока НашлиДляИсключения Цикл НашлиДляИсключения = Ложь; Для каждого ЭлементТаблицыСсылок из ТаблицаСсылок Цикл СсылкаОбъектаСодержащегоСсылку = ЭлементТаблицыСсылок.СсылкаДанного; Если СсылкаОбъектаСодержащегоСсылку = Неопределено Тогда СсылкаОбъектаСодержащегоСсылку = ЭлементТаблицыСсылок.Данные; КонецЕсли; СтрокаКандидатаОбъектаСодержащегоСсылку = СоответствиеКандидатов[СсылкаОбъектаСодержащегоСсылку]; Если СтрокаКандидатаОбъектаСодержащегоСсылку <> Неопределено Тогда УдаляетсяОбъектСодержащийСсылку = СтрокаКандидатаОбъектаСодержащегоСсылку.Удаляется; УдаляетсяСсылающаясяСтрокаТаблицыБД = ЭлементТаблицыСсылок.Удаляется; СтрокаКандидатаСсылки = СоответствиеКандидатов[ЭлементТаблицыСсылок.Ссылка]; УдаляетсяСсылка = СтрокаКандидатаСсылки.Удаляется; Если УдаляетсяСсылающаясяСтрокаТаблицыБД И Не УдаляетсяОбъектСодержащийСсылку И СсылкаОбъектаСодержащегоСсылку <> Ссылка Тогда ЭлементТаблицыСсылок.Удаляется = Ложь; СтрокаКандидатаСсылки.НеУдаляемыхСсылок = СтрокаКандидатаСсылки.НеУдаляемыхСсылок + 1; КонецЕсли; Если УдаляетсяСсылка И Не УдаляетсяОбъектСодержащийСсылку Тогда СтрокаКандидатаСсылки.Удаляется = Ложь; НашлиДляИсключения = Истина; КонецЕсли; КонецЕсли; КонецЦикла; КонецЦикла; Длительность = ТекущаяДата() - ДатаНачала; Если Длительность > 60 Тогда ирОбщий.СообщитьЛкс("Анализ найденных ссылок выполнен за " + XMLСтрока(Длительность) + "с."); КонецЕсли; Если Параметры = Неопределено Тогда Возврат Неопределено; КонецЕсли; Результат = Новый Структура; Результат.Вставить("ЗапуститьУдалениеПослеКонтроля", Параметры.ЗапуститьУдалениеПослеКонтроля); Если Параметры.ЭтаФорма = Неопределено Тогда Результат.Вставить("ТаблицаСсылок", ТаблицаСсылок); Результат.Вставить("УдаляемыеОбъекты", УдаляемыеОбъекты.Выгрузить()); КонецЕсли; Возврат Результат; КонецФункции // Выполняет удаление помеченные объектов, которые возможно удалить // В платформе есть похожий метод УдалитьОбъекты // Функция УдалитьОбъектыЛкс(Параметры) Экспорт ирОбщий.СообщитьЛкс("---------------------- Удаление объектов -----------------------"); Удалено = 0; НеУдалено = 0; Проход = 1; Индикатор = Неопределено; НеблокирующиеРегистры = Новый Массив; Для Каждого СтрокаРегистра Из НеблокирующиеТипы Цикл Если Ложь Или Не ирОбщий.ЛиКорневойТипРегистраСведенийЛкс(ирОбщий.ПервыйФрагментЛкс(СтрокаРегистра.Метаданные)) Или СтрокаРегистра.Игнорировать Тогда Продолжить; КонецЕсли; НеблокирующиеРегистры.Добавить(СтрокаРегистра.Метаданные); КонецЦикла; Если ирКэш.НомерВерсииПлатформыЛкс() < 803005 Тогда ирОбщий.СообщитьЛкс("Удаление строк неблокирующих регистров поддерживается только на 8.3.5+. Все неблокирующие регистры будут игнорироваться с образованием битых ссылок."); НеблокирующиеРегистры.Очистить(); КонецЕсли; Обработанные = Новый Соответствие; // Нужно минимизировать длительность транзакций. Поэтому на первых проходах удаляем только элементы без потомков Пока Истина Цикл СтруктураОтбора = Новый Структура; СтруктураОтбора.Вставить("Удаляется", Истина); ТаблицаУдаляемых = УдаляемыеОбъекты.Выгрузить(СтруктураОтбора); Если Индикатор = Неопределено Тогда ПредставлениеПроцесса = "Удаление"; Если мСервисныйПроцессор <> Неопределено Тогда Индикатор = мСервисныйПроцессор.ПолучитьИндикаторПроцесса(ТаблицаУдаляемых.Количество(), ПредставлениеПроцесса); Иначе Индикатор = ирОбщий.ПолучитьИндикаторПроцессаЛкс(ТаблицаУдаляемых.Количество(), ПредставлениеПроцесса); КонецЕсли; КонецЕсли; ТаблицаСсылокСРодителями = ТаблицаУдаляемых.СкопироватьКолонки(); НачальноеКоличество = ТаблицаУдаляемых.Количество(); Для СчетчикТаблицаУдаляемых = 1 По НачальноеКоличество Цикл СтрокаУдаляемого = ТаблицаУдаляемых[НачальноеКоличество - СчетчикТаблицаУдаляемых]; Если Истина И Обработанные[СтрокаУдаляемого.Ссылка] = Неопределено И ирОбщий.ЛиМетаданныеИерархическогоОбъектаЛкс(ирКэш.ОбъектМДПоПолномуИмениЛкс(СтрокаУдаляемого.Метаданные)) Тогда ЗаполнитьЗначенияСвойств(ТаблицаСсылокСРодителями.Добавить(), СтрокаУдаляемого); КонецЕсли; КонецЦикла; Если ТаблицаСсылокСРодителями.Количество() = 0 Тогда МассивУдаляемых = Новый Массив; Иначе ТаблицаСсылокСРодителями = ОбновитьДанныеКандидатов(ТаблицаСсылокСРодителями,, "Родитель"); ТаблицаСсылокСРодителями.Колонки.Добавить("ЭтоЭлементБезПотомков"); ТаблицаСсылокСРодителями.Индексы.Добавить("Родитель"); Для Каждого СтрокаУдаляемого Из ТаблицаСсылокСРодителями Цикл СтрокаУдаляемого.ЭтоЭлементБезПотомков = ТаблицаСсылокСРодителями.Найти(СтрокаУдаляемого.Ссылка, "Родитель") = Неопределено; КонецЦикла; МассивУдаляемых = ТаблицаСсылокСРодителями.Скопировать(Новый Структура("ЭтоЭлементБезПотомков", Истина)); КонецЕсли; Если МассивУдаляемых.Количество() = 0 Тогда МассивУдаляемых = ТаблицаУдаляемых; КонецЕсли; СтруктураОтбора.Очистить(); Для Каждого СтрокаУдаляемогоОбъекта из МассивУдаляемых Цикл Если мСервисныйПроцессор <> Неопределено Тогда мСервисныйПроцессор.ОбновитьИндикатор(Индикатор); Иначе ирОбщий.ОбработатьИндикаторЛкс(Индикатор); КонецЕсли; Ссылка = СтрокаУдаляемогоОбъекта.Ссылка; ОбъектМД = Ссылка.Метаданные(); //Представление = "" + СтрокаУдаляемогоОбъекта.Ссылка; //Объект = Ссылка.ПолучитьОбъект(); СтруктураОбъекта = ирОбщий.ОбъектБДПоКлючуЛкс(ОбъектМД.ПолноеИмя(), Ссылка); Попытка УдалитьСтрокиНеблокирующихРегистров(НеблокирующиеРегистры, Ссылка); Если Истина И СтруктураОбъекта.Методы <> Неопределено И Не СтруктураОбъекта.Методы.ЭтоНовый() Тогда ирОбщий.УдалитьОбъектЛкс(СтруктураОбъекта.Методы,, Ложь); ИначеЕсли ирОбщий.ЛиКорневойТипДокументаЛкс(ирОбщий.ПервыйФрагментЛкс(СтрокаУдаляемогоОбъекта.Метаданные)) Тогда ирОбщий.ОчиститьДвиженияДокументаЛкс(Ссылка, Истина, Истина); КонецЕсли; Если ВыводитьСообщения Тогда ирОбщий.СообщитьЛкс("Удален объект: " + СокрЛП(СтрокаУдаляемогоОбъекта.Метаданные) + ": " + СтрокаУдаляемогоОбъекта.Представление, СтатусСообщения.Информация); КонецЕсли; УдаляемыеОбъекты.Удалить(УдаляемыеОбъекты.Найти(Ссылка, "Ссылка")); Если ТаблицаСсылок <> Неопределено Тогда СтруктураОтбора.Вставить("Ссылка", Ссылка); СтрокиТаблицыСсылок = ТаблицаСсылок.НайтиСтроки(СтруктураОтбора); Для Каждого СтрокаСсылки из СтрокиТаблицыСсылок Цикл ТаблицаСсылок.Удалить(СтрокаСсылки); КонецЦикла; КонецЕсли; Удалено = Удалено + 1; Исключение Обработанные[Ссылка] = 1; ирОбщий.СообщитьЛкс("Не удален объект: " + СокрЛП(СтрокаУдаляемогоОбъекта.Метаданные) + ": " + СтрокаУдаляемогоОбъекта.Представление, СтатусСообщения.Важное); ирОбщий.СообщитьЛкс(" " + ОписаниеОшибки(), СтатусСообщения.Важное); НеУдалено = НеУдалено + 1; КонецПопытки; КонецЦикла; Если МассивУдаляемых = ТаблицаУдаляемых Тогда Прервать; КонецЕсли; Проход = Проход + 1; КонецЦикла; Если мСервисныйПроцессор <> Неопределено Тогда мСервисныйПроцессор.ОсвободитьИндикаторПроцесса(Индикатор, Истина); Иначе ирОбщий.ОсвободитьИндикаторПроцессаЛкс(Индикатор, Истина); КонецЕсли; ирОбщий.СообщитьЛкс("Удаление объектов закончено. Удалено объектов: " + Удалено + ?(НеУдалено <> 0, " Не удалено объектов : " + НеУдалено, ""),); Результат = Новый Структура; Результат.Вставить("УдаляемыеОбъекты", УдаляемыеОбъекты.Выгрузить()); Возврат Результат КонецФункции Процедура УдалитьСтрокиНеблокирующихРегистров(Знач НеблокирующиеРегистры, Знач Ссылка) Если НеблокирующиеРегистры.Количество() > 0 Тогда УстановитьПривилегированныйРежим(Истина); МассивСсылок = Новый Массив; МассивСсылок.Добавить(Ссылка); СсылкиВНеблокирующихРегистрах = Вычислить("НайтиПоСсылкам(МассивСсылок,, НеблокирующиеРегистры)"); Для Каждого СтрокаРегистра Из СсылкиВНеблокирующихРегистрах Цикл СтруктураНаборЗаписей = ирОбщий.ОбъектБДПоКлючуЛкс(СтрокаРегистра.Метаданные.ПолноеИмя(), СтрокаРегистра.Данные,, Ложь); ирОбщий.ЗаписатьОбъектЛкс(СтруктураНаборЗаписей.Методы); КонецЦикла; КонецЕсли; КонецПроцедуры Функция ОбщиеПараметрыОбработки(ТолькоВыделенныеСтрокиТЗ = Ложь) Результат = Новый Структура; Для Каждого МетаРеквизит Из Метаданные().Реквизиты Цикл Если Ложь Или МетаРеквизит.Имя = "КомпоновщикДопПолей" Тогда Продолжить; КонецЕсли; Результат.Вставить(МетаРеквизит.Имя, ЭтотОбъект[МетаРеквизит.Имя]); КонецЦикла; Результат.Вставить("УдаляемыеОбъекты", УдаляемыеОбъекты); Результат.Вставить("НеблокирующиеТипы", НеблокирующиеТипы); Возврат Результат; КонецФункции //ирПортативный лФайл = Новый Файл(ИспользуемоеИмяФайла); //ирПортативный ПолноеИмяФайлаБазовогоМодуля = Лев(лФайл.Путь, СтрДлина(лФайл.Путь) - СтрДлина("Модули\")) + "ирПортативный.epf"; //ирПортативный #Если Клиент Тогда //ирПортативный Контейнер = Новый Структура(); //ирПортативный Оповестить("ирПолучитьБазовуюФорму", Контейнер); //ирПортативный Если Не Контейнер.Свойство("ирПортативный", ирПортативный) Тогда //ирПортативный ирПортативный = ВнешниеОбработки.ПолучитьФорму(ПолноеИмяФайлаБазовогоМодуля); //ирПортативный ирПортативный.Открыть(); //ирПортативный КонецЕсли; //ирПортативный #Иначе //ирПортативный ирПортативный = ВнешниеОбработки.Создать(ПолноеИмяФайлаБазовогоМодуля, Ложь); // Это будет второй экземпляр объекта //ирПортативный #КонецЕсли //ирПортативный ирОбщий = ирПортативный.ПолучитьОбщийМодульЛкс("ирОбщий"); //ирПортативный ирКэш = ирПортативный.ПолучитьОбщийМодульЛкс("ирКэш"); //ирПортативный ирСервер = ирПортативный.ПолучитьОбщийМодульЛкс("ирСервер"); //ирПортативный ирПривилегированный = ирПортативный.ПолучитьОбщийМодульЛкс("ирПривилегированный"); ЭтотОбъект.ВыполнятьНаСервере = ирОбщий.ПолучитьРежимОбъектыНаСервереПоУмолчаниюЛкс(Ложь);