RDT1C/DataProcessors/ирУдалениеОбъектовСКонтролемСсылок/Ext/ObjectModule.bsl
Администратор 8319aac19b .
2021-09-04 16:05:11 +03:00

1190 lines
90 KiB
Plaintext
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//ирПортативный Перем ирПортативный Экспорт;
//ирПортативный Перем ирОбщий Экспорт;
//ирПортативный Перем ирСервер Экспорт;
//ирПортативный Перем ирКэш Экспорт;
//ирПортативный Перем ирПривилегированный Экспорт;
Перем мСервисныйПроцессор Экспорт; // Для программного вызова из Интеграции
Перем ТаблицаСсылок Экспорт;
Функция РеквизитыДляСервера(Параметры) Экспорт
Результат = Новый Структура;
Для Каждого МетаРеквизит Из Метаданные().Реквизиты Цикл
Если МетаРеквизит.Имя = "КомпоновщикДопПолей" Тогда
Продолжить;
КонецЕсли;
Результат.Вставить(МетаРеквизит.Имя, ЭтотОбъект[МетаРеквизит.Имя]);
КонецЦикла;
Результат.Вставить("УдаляемыеОбъекты", УдаляемыеОбъекты.Выгрузить());
Результат.Вставить("НеблокирующиеТипы", НеблокирующиеТипы.Выгрузить());
Возврат Результат;
КонецФункции
Процедура лСостояние(Текст)
//#Если Клиент Тогда
//Состояние(Текст);
//#КонецЕсли
КонецПроцедуры
Процедура лСостояниеПоиск(Текст)
//#Если Клиент Тогда
//Состояние("Поиск в "+Текст);
//#КонецЕсли
КонецПроцедуры
Процедура УстановитьЧтоСсылкуНельзяУдалить(Знач Ссылка, Связи, Типы)
// убираем эту ссылку из таблицы связей, где она является Ссылкой, т.к. проверять ссылание на неё уже не надо
Строки = Связи.НайтиСтроки(Новый Структура("Ссылка",Ссылка));
Если Строки.Количество() = 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 Тогда
МассивУдаляемых = ТаблицаУдаляемых;
КонецЕсли;
СтруктураОтбора.Очистить();
Для Каждого СтрокаУдаляемогоОбъекта из МассивУдаляемых Цикл
Если мСервисныйПроцессор <> Неопределено Тогда
мСервисныйПроцессор.ОбновитьИндикатор(Индикатор);
Иначе
ирОбщий.ОбработатьИндикаторЛкс(Индикатор);
КонецЕсли;
Ссылка = СтрокаУдаляемогоОбъекта.Ссылка;
ОбъектМД = Ссылка.Метаданные();
//Представление = "" + СтрокаУдаляемогоОбъекта.Ссылка;
//Объект = Ссылка.ПолучитьОбъект();
Если ПаузаМеждуУдалениями > 0 Тогда
ирОбщий.ПаузаЛкс(ПаузаМеждуУдалениями);
КонецЕсли;
СтруктураОбъекта = ирОбщий.ОбъектБДПоКлючуЛкс(ОбъектМД.ПолноеИмя(), Ссылка);
Попытка
УдалитьСтрокиНеблокирующихРегистров(НеблокирующиеРегистры, Ссылка);
Если Истина
И СтруктураОбъекта.Методы <> Неопределено
И Не СтруктураОбъекта.Методы.ЭтоНовый()
Тогда
ирОбщий.УдалитьОбъектЛкс(СтруктураОбъекта.Методы,, Ложь);
ИначеЕсли ирОбщий.ЛиКорневойТипДокументаЛкс(ирОбщий.ПервыйФрагментЛкс(СтрокаУдаляемогоОбъекта.Метаданные)) Тогда
ирОбщий.ОчиститьДвиженияДокументаЛкс(Ссылка, Истина, Истина);
КонецЕсли;
Если ВыводитьСообщения Тогда
ирОбщий.СообщитьЛкс("Удален объект: " + СокрЛП(СтрокаУдаляемогоОбъекта.Метаданные) + ": " + СтрокаУдаляемогоОбъекта.Представление, СтатусСообщения.Информация);
КонецЕсли;
УдаляемыеОбъекты.Удалить(УдаляемыеОбъекты.Найти(Ссылка, "Ссылка"));
Если ТаблицаСсылок <> Неопределено Тогда
СтруктураОтбора.Вставить("Ссылка", Ссылка);
СтрокиТаблицыСсылок = ТаблицаСсылок.НайтиСтроки(СтруктураОтбора);
Для Каждого СтрокаСсылки из СтрокиТаблицыСсылок Цикл
ТаблицаСсылок.Удалить(СтрокаСсылки);
КонецЦикла;
КонецЕсли;
Удалено = Удалено + 1;
Исключение
Обработанные[Ссылка] = 1;
ирОбщий.СообщитьЛкс("Не удален объект: " + СокрЛП(СтрокаУдаляемогоОбъекта.Метаданные) + ": " + СтрокаУдаляемогоОбъекта.Представление, СтатусСообщения.Важное);
ирОбщий.СообщитьЛкс(" " + ОписаниеОшибки(), СтатусСообщения.Важное);
НеУдалено = НеУдалено + 1;
КонецПопытки;
КонецЦикла;
Если МассивУдаляемых = ТаблицаУдаляемых Тогда
Прервать;
КонецЕсли;
Проход = Проход + 1;
КонецЦикла;
Если мСервисныйПроцессор <> Неопределено Тогда
мСервисныйПроцессор.ОсвободитьИндикаторПроцесса(Индикатор, Истина);
Иначе
ирОбщий.ОсвободитьИндикаторПроцессаЛкс(Индикатор, Истина);
КонецЕсли;
ирОбщий.СообщитьЛкс("Удаление объектов закончено. Удалено объектов: " + Удалено + ?(НеУдалено <> 0, " Не удалено объектов : " + НеУдалено, ""),);
Результат = Новый Структура;
Результат.Вставить("УдаляемыеОбъекты", УдаляемыеОбъекты.Выгрузить());
Возврат Результат
КонецФункции
Процедура УдалитьСтрокиНеблокирующихРегистров(Знач НеблокирующиеРегистры, Знач Ссылка)
Если НеблокирующиеРегистры.Количество() > 0 Тогда
УстановитьПривилегированныйРежим(Истина);
МассивСсылок = Новый Массив;
МассивСсылок.Добавить(Ссылка);
СсылкиВНеблокирующихРегистрах = Вычислить("НайтиПоСсылкам(МассивСсылок,, НеблокирующиеРегистры)");
Для Каждого СтрокаРегистра Из СсылкиВНеблокирующихРегистрах Цикл
СтруктураНаборЗаписей = ирОбщий.ОбъектБДПоКлючуЛкс(СтрокаРегистра.Метаданные.ПолноеИмя(), СтрокаРегистра.Данные,, Ложь);
ирОбщий.ЗаписатьОбъектЛкс(СтруктураНаборЗаписей.Методы);
КонецЦикла;
КонецЕсли;
КонецПроцедуры
Функция ОбщиеПараметрыОбработки(ТолькоВыделенныеСтрокиТЗ = Ложь)
Результат = Новый Структура;
Для Каждого МетаРеквизит Из Метаданные().Реквизиты Цикл
Если Ложь
Или МетаРеквизит.Имя = "КомпоновщикДопПолей"
Тогда
Продолжить;
КонецЕсли;
Результат.Вставить(МетаРеквизит.Имя, ЭтотОбъект[МетаРеквизит.Имя]);
КонецЦикла;
Результат.Вставить("УдаляемыеОбъекты", УдаляемыеОбъекты);
Результат.Вставить("НеблокирующиеТипы", НеблокирующиеТипы);
Возврат Результат;
КонецФункции
//ирПортативный лФайл = Новый Файл(ИспользуемоеИмяФайла);
//ирПортативный ПолноеИмяФайлаБазовогоМодуля = Лев(лФайл.Путь, СтрДлина(лФайл.Путь) - СтрДлина("Модули\")) + "ирПортативный.epf";
//ирПортативный #Если Клиент Тогда
//ирПортативный Контейнер = Новый Структура();
//ирПортативный Оповестить("ирПолучитьБазовуюФорму", Контейнер);
//ирПортативный Если Не Контейнер.Свойство("ирПортативный", ирПортативный) Тогда
//ирПортативный ирПортативный = ВнешниеОбработки.ПолучитьФорму(ПолноеИмяФайлаБазовогоМодуля);
//ирПортативный ирПортативный.Открыть();
//ирПортативный КонецЕсли;
//ирПортативный #Иначе
//ирПортативный ирПортативный = ВнешниеОбработки.Создать(ПолноеИмяФайлаБазовогоМодуля, Ложь); // Это будет второй экземпляр объекта
//ирПортативный #КонецЕсли
//ирПортативный ирОбщий = ирПортативный.ПолучитьОбщийМодульЛкс("ирОбщий");
//ирПортативный ирКэш = ирПортативный.ПолучитьОбщийМодульЛкс("ирКэш");
//ирПортативный ирСервер = ирПортативный.ПолучитьОбщийМодульЛкс("ирСервер");
//ирПортативный ирПривилегированный = ирПортативный.ПолучитьОбщийМодульЛкс("ирПривилегированный");
ЭтотОбъект.ВыполнятьНаСервере = ирОбщий.ПолучитьРежимОбъектыНаСервереПоУмолчаниюЛкс(Ложь);