RDT1C/DataProcessors/ирПоискДублейИЗаменаСсылок/Ext/ObjectModule.bsl
Администратор 6da878dd7f Редактор пользователей
*Обращение к свойству ЗащитаОтОпасныхДействий теперь делается через попытку, а не через проверку версии платформы
    Поиск дублей и замена ссылок
        *Исправлена свежая ошибка обработки неправильных элементов
2018-03-19 06:55:23 +03:00

1077 lines
83 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

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.

//ирПортативный Перем ирПортативный Экспорт;
//ирПортативный Перем ирОбщий Экспорт;
//ирПортативный Перем ирСервер Экспорт;
//ирПортативный Перем ирКэш Экспорт;
//ирПортативный Перем ирПривилегированный Экспорт;
Перем мПлатформа Экспорт;
Перем мСервисныйПроцессор Экспорт; // Для программного вызова из Интеграции
Перем ТаблицаБукв;
Перем мИскомыйОбъектПоискаДублей Экспорт;
Перем мСтруктураПоиска Экспорт;
Функция ЭтоБуква (Символ)
Код = КодСимвола(Символ);
Если (Код<=47) ИЛИ (Код>=58 И Код<=64) ИЛИ (Код>=91 И Код<=96) ИЛИ (Код>=123 И Код<=126) Тогда
Возврат Ложь;
Иначе
Возврат Истина;
КонецЕсли;
КонецФункции
Функция АнализРазличийВСловах(Список1, Список2, ПолныйСписок, ОдинаковыхСлов, ДопустимоеРазличиеСлов) Экспорт
Если Ложь
Или Список1.Количество() = ПолныйСписок.Количество()
Или Список2.Количество() = ПолныйСписок.Количество()
Тогда
Возврат Истина;
КонецЕсли;
Если ПолныйСписок.Количество() = 0 Тогда
Возврат Истина;
КонецЕсли;
Если Список1.Количество() = Список2.Количество() Тогда
ЕстьОтличия = ПроверитьСловаНаОтличие(Список1, Список2, ДопустимоеРазличиеСлов);
ЕСли НЕ ЕстьОтличия Тогда
Возврат Ложь;
КонецЕсли;
КонецЕсли;
ЦелоеСлово = "";
Для Каждого Слово ИЗ ПолныйСписок Цикл
ЦелоеСлово = ЦелоеСлово + Слово.Значение;
КонецЦикла;
Слово1 = "";
Для Каждого Слово ИЗ Список1 Цикл
Слово1 = Слово1 + Слово.Значение;
КонецЦикла;
Слово2 = "";
Для Каждого Слово ИЗ Список2 Цикл
Слово2 = Слово2 + Слово.Значение;
КонецЦикла;
Если Истина
И Окр(СтрДлина(Слово1)/СтрДлина(ЦелоеСлово)*100) < ДопустимоеРазличиеСлов
И Окр(СтрДлина(Слово2)/СтрДлина(ЦелоеСлово)*100) < ДопустимоеРазличиеСлов
Тогда
Возврат Ложь;
КонецЕсли;
Возврат Истина;
КонецФункции
Функция СравнитьСлова(Слово1, Слово2, ДопустимоеРазличиеСлов)
ТаблицаБукв.Очистить();
ТаблицаБуквПустая = Истина;
ЕСли СтрДлина(Слово1)<=СтрДлина(Слово2) Тогда
Слово = ВРЕГ(Слово1);
ИскомоеСлово = ВРЕГ(Слово2);
Иначе
Слово = ВРЕГ(Слово2);
ИскомоеСлово = ВРЕГ(Слово1);
КонецЕсли;
Для индекс = 1 по СтрДлина(Слово) Цикл
Символ = Сред(Слово, индекс, 1);
ЕСли ТаблицаБуквПустая Тогда
поз = Найти(ИскомоеСлово, Символ);
поправка = 0;
Пока поз>0 Цикл
ТаблицаБуквПустая = Ложь;
НовСтр = ТаблицаБукв.Добавить();
НовСтр.Позиция = поз + поправка;
НовСтр.ДлинаСлова = 1;
НовСтр.КолвоПропущенных = 0;
поправка = поправка + поз;
поз = Найти(Сред(ИскомоеСлово, поправка+1), Символ);
КонецЦикла;
Иначе
Для Каждого Вхождение ИЗ ТаблицаБукв Цикл
Если Сред(ИскомоеСлово, Вхождение.Позиция + Вхождение.ДлинаСлова, 1) = Символ Тогда
Вхождение.ДлинаСлова = Вхождение.ДлинаСлова + 1;
ИначеЕсли Сред(Слово, Вхождение.Позиция + Вхождение.ДлинаСлова - Вхождение.КолвоПропущенных, 1) = Вхождение.ПропущеноНа Тогда
Вхождение.ПропущеноНа = "";
Вхождение.ДлинаСлова = Вхождение.ДлинаСлова + 1;
Если Сред(ИскомоеСлово, Вхождение.Позиция + Вхождение.ДлинаСлова, 1) = Символ Тогда
Вхождение.ДлинаСлова = Вхождение.ДлинаСлова + 1;
Иначе
Вхождение.КолвоПропущенных = Вхождение.КолвоПропущенных + 1;
КонецЕсли;
Иначе
ЕСли Окр((Вхождение.КолвоПропущенных + 1) / СтрДлина(ИскомоеСлово) * 100)<=ДопустимоеРазличиеСлов Тогда
Вхождение.КолвоПропущенных = Вхождение.КолвоПропущенных + 1;
Вхождение.ДлинаСлова = Вхождение.ДлинаСлова + 1;
Вхождение.ПропущеноНа = Символ;
Иначе
Вхождение.КолвоПропущенных = Вхождение.КолвоПропущенных + 1;
КонецЕсли;
КонецЕсли;
КонецЦикла;
КонецЕсли;
КонецЦикла;
ЕСли ТаблицаБуквПустая Тогда
Возврат Ложь;
КонецЕсли;
ТаблицаБукв.Сортировать("ДлинаСлова УБЫВ, КолвоПропущенных ВОЗР");
СовпалоСимволов = ТаблицаБукв[0].ДлинаСлова - ТаблицаБукв[0].КолвоПропущенных;
Возврат (Окр(СовпалоСимволов / СтрДлина(ИскомоеСлово) * 100) >= (100 - ДопустимоеРазличиеСлов));
КонецФункции
Функция ПроверитьСловаНаОтличие(СписокСлов1, СписокСлов2, ДопустимоеРазличиеСлов) Экспорт
СписокРазличающихсяСлов = Новый СписокЗначений;
Для Каждого Слово1 ИЗ СписокСлов1 Цикл
ЕстьПара = Ложь;
Для Каждого Слово2 Из СписокСлов2 Цикл
Если СравнитьСлова(Слово1.Значение, Слово2.Значение, ДопустимоеРазличиеСлов) Тогда
ЕстьПара = Истина;
СписокСлов2.Удалить(Слово2);
Прервать;
КонецЕсли;
КонецЦикла;
ЕСли НЕ ЕстьПара Тогда
СписокРазличающихсяСлов.Добавить(Слово1.Значение);
КонецЕсли;
КонецЦикла;
СписокСлов1 = СписокРазличающихсяСлов;
Возврат Не (СписокСлов1.Количество() = 0 И СписокСлов2.Количество() = 0)
КонецФункции
Функция ПолучитьСписокСлов(ЗначениеРеквизита) Экспорт
СписокСлов = Новый СписокЗначений;
Слово = "";
Для индекс = 1 по СтрДлина(ЗначениеРеквизита) Цикл
Символ = Сред(ЗначениеРеквизита, индекс, 1);
Если ЭтоБуква(Символ) Тогда
Слово = Слово + Символ;
Иначе
Если Слово<>"" Тогда
СписокСлов.Добавить(ВРЕГ(Слово));
Слово = "";
КонецЕсли;
КонецЕсли;
КонецЦикла;
Если Слово<>"" Тогда
СписокСлов.Добавить(ВРЕГ(Слово));
КонецЕсли;
СписокСлов.СортироватьПоЗначению();
Возврат СписокСлов;
КонецФункции // ()
// Заменяемые - Соответствие, Массив строк таблицы
// ТаблицаСсылающихсяОбъектов - ТаблицаЗначений, *Неопределено - таблица ссылающихся объектов возвращаемая методом НайтиПоСсылкам или ее часть
// ЗамещениеВсегда - Число - замещение к ключах независимых регистров сведений, 1 - замещать, 0 - спрашивать (на клиенте) или пропускать
//
Функция ВыполнитьЗаменуЭлементов(Заменяемые, ТаблицаСсылающихсяОбъектов = Неопределено, Знач ЗаголовокИндикации = "", ЗамещениеВсегда = 0) Экспорт
//Если ТранзакцияАктивна() Тогда
// ВызватьИсключение "Замена ссылок не допускается в общей транзакции";
//КонецЕсли;
БылиИсключения = Ложь;
Параметры = Новый Структура;
Параметры.Вставить("Объект", Неопределено);
СтруктураКоллизий = Новый Структура;
ИзмененныеПроведенныеДокументы.Очистить();
Если ТаблицаСсылающихсяОбъектов = Неопределено Тогда
СписокСсылок = Новый Массив;
Для Каждого КлючИЗначение Из Заменяемые Цикл
СписокСсылок.Добавить(КлючИЗначение.Ключ);
КонецЦикла;
ТаблицаСсылающихсяОбъектов = НайтиПоСсылкам(СписокСсылок);
КонецЕсли;
РодителиПравильных = Новый Соответствие;
Для Каждого КлючИЗначение Из Заменяемые Цикл
ОбъектМД = Метаданные.НайтиПоТипу(ТипЗнч(КлючИЗначение.Ключ));
Если ОбъектМД = Неопределено Тогда
ВызватьИсключение "Не найден объект метаданных по типу";
КонецЕсли;
Если ирОбщий.ЛиМетаданныеИерархическогоОбъектаЛкс(ОбъектМД) Тогда
МассивРодителей = Новый Массив;
Родитель = КлючИЗначение.Значение;
Если ТипЗнч(Родитель) = Тип("Структура") Тогда
Родитель = Родитель.Значение;
КонецЕсли;
Пока ЗначениеЗаполнено(Родитель) Цикл
МассивРодителей.Добавить(Родитель);
Родитель = Родитель.Родитель;
КонецЦикла;
РодителиПравильных[КлючИЗначение.Значение] = МассивРодителей;
КонецЕсли;
КонецЦикла;
Если ТаблицаСсылающихсяОбъектов.Количество() > 0 Тогда
Если Не ЗначениеЗаполнено(ЗаголовокИндикации) Тогда
ЗаголовокИндикации = "Замена ссылок";
КонецЕсли;
СтрокаГруппировок = "Метаданные,Данные";
Если ТипЗнч(ТаблицаСсылающихсяОбъектов) = Тип("ТаблицаЗначений") Тогда
СсылающиесяОбъекты = ТаблицаСсылающихсяОбъектов.Скопировать(, СтрокаГруппировок);
Иначе
СсылающиесяОбъекты = ТаблицаСсылающихсяОбъектов.Выгрузить(, СтрокаГруппировок);
КонецЕсли;
СсылающиесяОбъекты.Индексы.Добавить(СтрокаГруппировок);
СсылающиесяОбъекты.Свернуть(СтрокаГруппировок);
СсылающиесяОбъекты.Сортировать(СтрокаГруппировок);
КлючПоиска = Новый Структура("Данные");
Если мСервисныйПроцессор <> Неопределено Тогда
Индикатор = мСервисныйПроцессор.ПолучитьИндикаторПроцесса(СсылающиесяОбъекты.Количество(), ЗаголовокИндикации);
Иначе
Индикатор = ирОбщий.ПолучитьИндикаторПроцессаЛкс(СсылающиесяОбъекты.Количество(), ЗаголовокИндикации);
КонецЕсли;
ТранзакцииРазрешены = Истина;
Если Истина
И ЗаписьНаСервере
И ирКэш.ЛиПортативныйРежимЛкс()
И Не ирПортативный.ЛиСерверныйМодульДоступенЛкс(Ложь)
И ирПортативный.ЭмуляцияЗаписиНаСервере
Тогда
Сообщить("В режиме эмуляции записи на сервере транзакции не поддерживаются");
ТранзакцииРазрешены = Ложь;
ОбщаяТранзакция = Ложь;
КонецЕсли;
Если ОбщаяТранзакция Тогда
НачатьТранзакцию();
КонецЕсли;
Попытка
Для Каждого ОписаниеОбъекта Из СсылающиесяОбъекты Цикл
Если мСервисныйПроцессор <> Неопределено Тогда
мСервисныйПроцессор.ОбновитьИндикатор(Индикатор);
Иначе
ирОбщий.ОбработатьИндикаторЛкс(Индикатор);
КонецЕсли;
ОбъектИзменен = Ложь;
Если ТипЗнч(ОписаниеОбъекта.Данные) = Тип("Строка") Тогда
ОбъектСодержащийСсылку = ЗначениеИзСтрокиВнутр(ОписаниеОбъекта.Данные);
Иначе
ОбъектСодержащийСсылку = ОписаниеОбъекта.Данные;
КонецЕсли;
Если ТипЗнч(ОписаниеОбъекта.Метаданные) = Тип("Строка") Тогда
//ОбъектМД = Метаданные.НайтиПоПолномуИмени(ОписаниеОбъекта.Метаданные);
ОбъектМД = мПлатформа.ПолучитьОбъектМДПоПолномуИмени(ОписаниеОбъекта.Метаданные);
Иначе
ОбъектМД = ОписаниеОбъекта.Метаданные;
КонецЕсли;
Если КомментироватьЗаменуСсылок Тогда
Сообщить("Обрабатывается " + ОбъектСодержащийСсылку);
КонецЕсли;
ПолноеИмяМД = ОбъектМД.ПолноеИмя();
ТипТаблицы = ирОбщий.ПолучитьТипТаблицыБДЛкс(ПолноеИмяМД);
ЗаполнитьЗначенияСвойств(КлючПоиска, ОписаниеОбъекта);
СсылкиВОбъектеНаНеправильныеЭлементы = ТаблицаСсылающихсяОбъектов.НайтиСтроки(КлючПоиска);
НеправильныеСсылкиВОбъекте = Новый Массив;
Для Каждого СтрокаНеправильнойСсылки Из СсылкиВОбъектеНаНеправильныеЭлементы Цикл
НеправильныеСсылкиВОбъекте.Добавить(СтрокаНеправильнойСсылки.Ссылка);
КонецЦикла;
Если ирОбщий.ЛиКорневойТипСсылочногоОбъектаБДЛкс(ТипТаблицы) Тогда
Если ТранзакцииРазрешены Тогда
НачатьТранзакцию();
КонецЕсли;
Попытка
ирОбщий.ЗаблокироватьСсылкуВТранзакцииЛкс(ОбъектСодержащийСсылку, Истина);
СтруктураОбъектаБД = ирОбщий.ОбъектБДПоКлючуЛкс(ПолноеИмяМД, ОбъектСодержащийСсылку,,, ЗаписьНаСервере);
Если СтруктураОбъектаБД.Методы <> Неопределено Тогда
Для Каждого НеправильнаяСсылка Из НеправильныеСсылкиВОбъекте Цикл
ОбъектИзменен = ЗаменитьЗначениеВОбъектеБДЛкс(СтруктураОбъектаБД, НеправильнаяСсылка, Заменяемые[НеправильнаяСсылка], РодителиПравильных[Заменяемые[НеправильнаяСсылка]]) Или ОбъектИзменен;
КонецЦикла;
КонецЕсли;
ЗаписатьОбъектЕслиИзменен(СтруктураОбъектаБД, БылиИсключения, ОбъектИзменен, ОбъектМД);
Если ТранзакцииРазрешены Тогда
ЗафиксироватьТранзакцию();
КонецЕсли;
Исключение
Если ТранзакцииРазрешены Тогда
ОтменитьТранзакцию();
КонецЕсли;
БылиИсключения = Истина;
Если ОбщаяТранзакция Тогда
ВызватьИсключение;
КонецЕсли;
Сообщить("Ошибка обработки ссылающегося объекта " + ирОбщий.ПолучитьXMLКлючОбъектаБДЛкс(ОбъектСодержащийСсылку) + ": " + ОписаниеОшибки(), СтатусСообщения.Внимание);
КонецПопытки;
Если Не БылиИсключения Тогда
Если Метаданные.Документы.Содержит(ОбъектМД) Тогда
Для Каждого Движение ИЗ ОбъектМД.Движения Цикл
//НаборЗаписей = Новый (СтрЗаменить(Движение.ПолноеИмя(), ".", "НаборЗаписей."));
ИмяТаблицыРегистра = ирОбщий.ПолучитьИмяТаблицыИзМетаданныхЛкс(Движение);
СтруктураНаборЗаписей = ирОбщий.ОбъектБДПоКлючуЛкс(ИмяТаблицыРегистра, Новый Структура("Регистратор", ОбъектСодержащийСсылку),, Ложь, ЗаписьНаСервере);
БылиИсключения = Не ВыполнитьЗаменуВНабореЗаписей(СтруктураНаборЗаписей, Заменяемые, НеправильныеСсылкиВОбъекте, ТранзакцииРазрешены);
КонецЦикла;
Для Каждого Последовательность ИЗ Метаданные.Последовательности Цикл
Если Последовательность.Документы.Содержит(ОбъектМД) Тогда
//НаборЗаписей = Новый (СтрЗаменить(Последовательность.ПолноеИмя(), ".", "НаборЗаписей."));
ИмяТаблицыРегистра = ирОбщий.ПолучитьИмяТаблицыИзМетаданныхЛкс(Последовательность);
СтруктураНаборЗаписей = ирОбщий.ОбъектБДПоКлючуЛкс(ИмяТаблицыРегистра, Новый Структура("Регистратор", ОбъектСодержащийСсылку),, Ложь, ЗаписьНаСервере);
БылиИсключения = Не ВыполнитьЗаменуВНабореЗаписей(СтруктураНаборЗаписей, Заменяемые, НеправильныеСсылкиВОбъекте, ТранзакцииРазрешены);
КонецЕсли;
КонецЦикла;
КонецЕсли;
КонецЕсли;
ИначеЕсли ирОбщий.ЛиКорневойТипКонстантыЛкс(ТипТаблицы) Тогда
Если ТранзакцииРазрешены Тогда
НачатьТранзакцию();
КонецЕсли;
Попытка
СтруктураОбъектаБД = ирОбщий.ОбъектБДПоКлючуЛкс(ПолноеИмяМД,,, Ложь, ЗаписьНаСервере);
ирОбщий.ЗаблокироватьКонстантуЛкс(СтруктураОбъектаБД, Истина);
СтруктураОбъектаБД.Методы.Прочитать(ЗаписьНаСервере);
НовоеЗначение = Заменяемые[СтруктураОбъектаБД.Данные.Значение];
Если НовоеЗначение <> Неопределено Тогда
СтруктураОбъектаБД.Данные.Значение = НовоеЗначение;
ОбъектИзменен = Истина;
ЗаписатьОбъектЕслиИзменен(СтруктураОбъектаБД, БылиИсключения, ОбъектИзменен, ОбъектМД);
КонецЕсли;
Если ТранзакцииРазрешены Тогда
ЗафиксироватьТранзакцию();
КонецЕсли;
Исключение
Если ТранзакцииРазрешены Тогда
ОтменитьТранзакцию();
КонецЕсли;
БылиИсключения = Истина;
Если ОбщаяТранзакция Тогда
ВызватьИсключение;
КонецЕсли;
Сообщить("Ошибка обработки ссылающегося объекта " + ирОбщий.ПолучитьXMLКлючОбъектаБДЛкс(СтруктураОбъектаБД) + ": " + ОписаниеОшибки(), СтатусСообщения.Внимание);
КонецПопытки;
ИначеЕсли ирОбщий.ЛиКорневойТипРегистраСведенийЛкс(ТипТаблицы) Тогда
МассивИзмененныхИзмерений = Новый Массив;
МенеджерЗаписи = РегистрыСведений[ОбъектМД.Имя].СоздатьМенеджерЗаписи();
КоллизийныйМенеджерЗаписи = РегистрыСведений[ОбъектМД.Имя].СоздатьМенеджерЗаписи();
Если ТранзакцииРазрешены Тогда
НачатьТранзакцию();
КонецЕсли;
ИмяТаблицыРегистра = ирОбщий.ПолучитьИмяТаблицыИзМетаданныхЛкс(ОбъектМД);
СтруктураКлючаЗаписи = ирОбщий.ПолучитьСтруктуруКлючаТаблицыБДЛкс(ИмяТаблицыРегистра);
Попытка
БылаКоллизия = Ложь;
ЗаполнитьЗначенияСвойств(МенеджерЗаписи, ОбъектСодержащийСсылку);
ЗаполнитьЗначенияСвойств(КоллизийныйМенеджерЗаписи, ОбъектСодержащийСсылку);
ЗаполнитьЗначенияСвойств(СтруктураКлючаЗаписи, ОбъектСодержащийСсылку);
ирОбщий.ЗаблокироватьРегистрПоМенеджеруЗаписиЛкс(МенеджерЗаписи, Истина);
КоллизийныйМенеджерЗаписи.Прочитать();
Если КоллизийныйМенеджерЗаписи.Выбран() Тогда
ПоляТаблицыБД = ирОбщий.ПолучитьПоляТаблицыМДЛкс(ПолноеИмяМД,,,, Ложь);
ОбъектИзменен = ВыполнитьЗаменуВСтрокеНабораЗаписей(КоллизийныйМенеджерЗаписи, Заменяемые, ПоляТаблицыБД);
Если Не БылиИсключения И ОбъектИзменен Тогда
Для каждого МетаИзмерение Из ОбъектМД.Измерения Цикл
Если КоллизийныйМенеджерЗаписи[МетаИзмерение.Имя] <> ОбъектСодержащийСсылку[МетаИзмерение.Имя] Тогда
МассивИзмененныхИзмерений.Добавить(МетаИзмерение.Имя);
КонецЕсли;
КонецЦикла;
Если МассивИзмененныхИзмерений.Количество() > 0 Тогда
ЗаполнитьЗначенияСвойств(СтруктураКлючаЗаписи, КоллизийныйМенеджерЗаписи);
ирОбщий.ЗаблокироватьРегистрПоМенеджеруЗаписиЛкс(КоллизийныйМенеджерЗаписи, Истина);
КоллизийныйМенеджерЗаписи.Прочитать();
Если КоллизийныйМенеджерЗаписи.Выбран() Тогда
МенеджерЗаписи.Прочитать();
МассивКоллекцийРеквизитов = Новый Массив;
МассивКоллекцийРеквизитов.Добавить(ОбъектМД.Ресурсы);
МассивКоллекцийРеквизитов.Добавить(ОбъектМД.Реквизиты);
Если Не СтруктураКоллизий.Свойство(ОбъектМД.Имя) Тогда
ТаблицаЗаписей = РегистрыСведений[ОбъектМД.Имя].СоздатьНаборЗаписей().Выгрузить();
ТаблицаЗаписей.Колонки.Добавить("МенеджерЗамены");
ТаблицаЗаписей.Колонки.Добавить("МенеджерОригинала");
Для Каждого КоллекцияРеквизитов Из МассивКоллекцийРеквизитов Цикл
Для Каждого МетаРеквизит Из КоллекцияРеквизитов Цикл
ИмяКолонки = МетаРеквизит.Имя;
ПредставлениеКолонки = МетаРеквизит.Представление();
КолонкаОригинала = ТаблицаЗаписей.Колонки[ИмяКолонки];
КолонкаОригинала.Имя = "Оригинал" + ИмяКолонки;
КолонкаОригинала.Заголовок = "Оригинал: " + ПредставлениеКолонки;
КолонкаЗамены = ТаблицаЗаписей.Колонки.Вставить(ТаблицаЗаписей.Колонки.Индекс(КолонкаОригинала),
"Замена" + ИмяКолонки, , "Замена: " + ПредставлениеКолонки);
ЗаполнитьЗначенияСвойств(КолонкаЗамены, КолонкаОригинала, , "Имя, Заголовок");
КонецЦикла;
КонецЦикла;
ТаблицаЗаписей.Колонки.Вставить(0, "Заменить", Новый ОписаниеТипов("Булево"), "Заменить");
СтруктураКоллизий.Вставить(ОбъектМД.Имя, ТаблицаЗаписей);
КонецЕсли;
НоваяКоллизийнаяЗапись = СтруктураКоллизий[ОбъектМД.Имя].Добавить();
Для Каждого КоллекцияРеквизитов Из МассивКоллекцийРеквизитов Цикл
Для Каждого МетаРеквизит Из КоллекцияРеквизитов Цикл
ИмяКолонки = МетаРеквизит.Имя;
ЗначениеРеквизита = МенеджерЗаписи[ИмяКолонки];
НоваяКоллизийнаяЗапись["Оригинал" + ИмяКолонки] = КоллизийныйМенеджерЗаписи[ИмяКолонки];
ЗаменаЗначения = Заменяемые[ЗначениеРеквизита];
Если ЗаменаЗначения <> Неопределено Тогда
НоваяКоллизийнаяЗапись["Замена" + ИмяКолонки] = ЗаменаЗначения;
Иначе
НоваяКоллизийнаяЗапись["Замена" + ИмяКолонки] = ЗначениеРеквизита;
КонецЕсли;
КоллизийныйМенеджерЗаписи[ИмяКолонки] = НоваяКоллизийнаяЗапись["Замена" + ИмяКолонки];
Если НоваяКоллизийнаяЗапись["Оригинал" + ИмяКолонки] <> НоваяКоллизийнаяЗапись["Замена" + ИмяКолонки] Тогда
БылаКоллизия = Истина;
КонецЕсли;
КонецЦикла;
КонецЦикла;
Если БылаКоллизия И ЗамещениеВсегда <> 1 Тогда
ЗаполнитьЗначенияСвойств(НоваяКоллизийнаяЗапись, КоллизийныйМенеджерЗаписи);
Для Каждого ИмяКолонки Из МассивИзмененныхИзмерений Цикл
НоваяКоллизийнаяЗапись[ИмяКолонки] = МенеджерЗаписи[ИмяКолонки];
КонецЦикла;
НоваяКоллизийнаяЗапись.МенеджерЗамены = КоллизийныйМенеджерЗаписи;
НоваяКоллизийнаяЗапись.МенеджерОригинала = МенеджерЗаписи;
Иначе
СтруктураКоллизий[ОбъектМД.Имя].Удалить(НоваяКоллизийнаяЗапись);
МенеджерЗаписи.Удалить();
БылаКоллизия = Истина;
КонецЕсли;
КонецЕсли;
КонецЕсли;
КонецЕсли;
КонецЕсли;
Если БылаКоллизия Тогда
БылиИсключения = Ложь;
Иначе
БылиИсключения = Не ВыполнитьЗаменуВНабореЗаписей(МенеджерЗаписи, Заменяемые, НеправильныеСсылкиВОбъекте);
КонецЕсли;
Если ТранзакцииРазрешены Тогда
ЗафиксироватьТранзакцию();
КонецЕсли;
Исключение
Если ТранзакцииРазрешены Тогда
ОтменитьТранзакцию();
КонецЕсли;
БылиИсключения = Истина;
Если ОбщаяТранзакция Тогда
ВызватьИсключение;
КонецЕсли;
НаборЗаписей = ирОбщий.ОбъектБДПоКлючуЛкс(ИмяТаблицыРегистра, СтруктураКлючаЗаписи,, Ложь, ЗаписьНаСервере);
Сообщить("Ошибка обработки ссылающегося объекта " + ирОбщий.ПолучитьXMLКлючОбъектаБДЛкс(НаборЗаписей) + ": " + ОписаниеОшибки(), СтатусСообщения.Внимание);
КонецПопытки;
Иначе
БылиИсключения = Истина;
Сообщить("Замена ссылок в объектах типа " + ОбъектМД.ПолноеИмя() + " не поддерживается");
КонецЕсли;
КонецЦикла;
Если ОбщаяТранзакция Тогда
ЗафиксироватьТранзакцию();
КонецЕсли;
Исключение
Если ОбщаяТранзакция Тогда
ОтменитьТранзакцию();
КонецЕсли;
ВызватьИсключение;
КонецПопытки;
Если мСервисныйПроцессор <> Неопределено Тогда
мСервисныйПроцессор.ОсвободитьИндикаторПроцесса(Индикатор, Истина);
Иначе
ирОбщий.ОсвободитьИндикаторПроцессаЛкс(Индикатор, Истина);
КонецЕсли;
КонецЕсли;
МассивЭлементовКУдалению = Новый Массив;
Для Каждого ЭлементТаблицыРегистра Из СтруктураКоллизий Цикл
Если ЭлементТаблицыРегистра.Значение.Количество() = 0 Тогда
МассивЭлементовКУдалению.Добавить(ЭлементТаблицыРегистра.Ключ);
КонецЕсли;
КонецЦикла;
Для Каждого ЭлементКУдалению Из МассивЭлементовКУдалению Цикл
СтруктураКоллизий.Удалить(ЭлементКУдалению);
КонецЦикла;
Если СтруктураКоллизий.Количество() > 0 Тогда
Если ЗамещениеВсегда = 1 Тогда
ЗамещатьВЭтотРаз = Истина;
Иначе
#Если Клиент Тогда
ФормаЗамещенияВНезависимыхРегистрахСведений = ПолучитьФорму("ФормаЗамещенияВНезависимыхРегистрахСведений");
ФормаЗамещенияВНезависимыхРегистрахСведений.КодВсегда = ЗамещениеВсегда;
ФормаЗамещенияВНезависимыхРегистрахСведений.СтруктураКоллизий = СтруктураКоллизий;
ФормаЗамещенияВНезависимыхРегистрахСведений.ОткрытьМодально();
ЗамещениеВсегда = ФормаЗамещенияВНезависимыхРегистрахСведений.КодВсегда;
ЗамещатьВЭтотРаз = ФормаЗамещенияВНезависимыхРегистрахСведений.РезультатФормы;
#Иначе
ЗамещатьВЭтотРаз = Ложь;
#КонецЕсли
КонецЕсли;
Если ЗамещатьВЭтотРаз Тогда
Для Каждого ЭлементРегистра Из СтруктураКоллизий Цикл
Для Каждого СтрокаЗаписи Из ЭлементРегистра.Значение Цикл
Если СтрокаЗаписи.Заменить Тогда
СтрокаЗаписи.МенеджерЗамены.Записать();
КонецЕсли;
СтрокаЗаписи.МенеджерОригинала.Удалить();
КонецЦикла;
КонецЦикла;
КонецЕсли;
КонецЕсли;
Возврат Не БылиИсключения;
КонецФункции
Процедура ЗаписатьОбъектЕслиИзменен(СтруктураОбъектБД, БылиИсключения, ОбъектИзменен, ОбъектМД)
Если ирОбщий.ЛиТипОбъектаБДЛкс(ирОбщий.ТипОбъектаБДЛкс(СтруктураОбъектБД)) Тогда
//Если Объект.Модифицированность() Тогда
Если ОбъектИзменен Тогда
Попытка
ирОбщий.ЗаписатьОбъектЛкс(СтруктураОбъектБД.Методы, ЗаписьНаСервере,,, ОтключатьКонтрольЗаписи, БезАвторегистрацииИзменений);
//Если ОтключатьКонтрольЗаписи Тогда
// ЗаписьЖурналаРегистрации("Запись с флагом Загрузка", УровеньЖурналаРегистрации.Информация, ОбъектМД,
// ОбъектСодержащийСсылку, "");
//КонецЕсли;
Исключение
Сообщить(ОписаниеОшибки(), СтатусСообщения.Важное);
БылиИсключения = Истина;
ОбъектИзменен = Ложь;
КонецПопытки;
Если Истина
И ОбъектИзменен
И Метаданные.Документы.Содержит(ОбъектМД)
И ОбъектМД.Проведение = Метаданные.СвойстваОбъектов.Проведение.Разрешить
И СтруктураОбъектБД.Данные.Проведен
Тогда
СтрокаДляДокумента = ИзмененныеПроведенныеДокументы.Добавить();
СтрокаДляДокумента.ДатаДокумента = СтруктураОбъектБД.Данные.Дата;
СтрокаДляДокумента.ТипДокумента = ОбъектМД.Имя;
СтрокаДляДокумента.Документ = СтруктураОбъектБД.Данные.Ссылка;
КонецЕсли;
КонецЕсли;
КонецЕсли;
КонецПроцедуры // ВыполнитьЗаменуЭлементов()
// Ищет все экземпляры значения ЧтоЗаменять в объекте и заменяет их на НаЧтоЗаменять
Функция ЗаменитьЗначениеВОбъектеБДЛкс(СтруктураОбъектаБД, ЧтоЗаменять, НаЧтоЗаменять, РодителиПравильного = Неопределено)
ОбъектМД = Метаданные.НайтиПоТипу(ирОбщий.ТипОбъектаБДЛкс(СтруктураОбъектаБД));
ПолноеИмяМД = ОбъектМД.ПолноеИмя();
ПоляТаблицыБД = ирОбщий.ПолучитьПоляТаблицыМДЛкс(ПолноеИмяМД,,,, Ложь);
#Если Сервер И Не Сервер Тогда
ПоляТаблицыБД = ПолучитьСтруктуруХраненияБазыДанных().Колонки;
#КонецЕсли
ОбъектИзменен = Ложь;
Для Каждого ПолеТаблицыБД Из ПоляТаблицыБД Цикл
Если ПолеТаблицыБД.ТипЗначения.СодержитТип(Тип("ТаблицаЗначений")) Тогда
ТабличнаяЧасть = СтруктураОбъектаБД.Данные[ПолеТаблицыБД.Имя];
ПоляТаблицыТЧ = ирОбщий.ПолучитьПоляТаблицыБДЛкс(ПолноеИмяМД + "." + ПолеТаблицыБД.Имя);
Если ТипЗнч(ТабличнаяЧасть) = Тип("ТаблицаЗначений") Тогда
КолонкиТЧ = ТабличнаяЧасть.СкопироватьКолонки();
Иначе
КолонкиТЧ = ТабличнаяЧасть.ВыгрузитьКолонки();
КонецЕсли;
Для Каждого КолонкаТЧ Из КолонкиТЧ.Колонки Цикл
ИмяРеквизита = КолонкаТЧ.Имя;
Если КолонкаТЧ.ТипЗначения.СодержитТип(ТипЗнч(ЧтоЗаменять)) Тогда
СтрокиТабЧасти = ТабличнаяЧасть.НайтиСтроки(Новый Структура(ИмяРеквизита, ЧтоЗаменять));
Для Каждого СтрокаТабЧасти Из СтрокиТабЧасти Цикл
ОбъектИзменен = ЗаменитьЗначениеРеквизитаСПроверкойВозможности(СтрокаТабЧасти, ИмяРеквизита, НаЧтоЗаменять, ПоляТаблицыТЧ) Или ОбъектИзменен;
КонецЦикла;
КонецЕсли;
КонецЦикла;
Иначе
ИмяРеквизита = "" + ПолеТаблицыБД.Имя;
Если ирОбщий.СтрокиРавныЛкс(ИмяРеквизита, "Ссылка") Тогда
Продолжить;
КонецЕсли;
Если ПолеТаблицыБД.ТипЗначения.СодержитТип(ТипЗнч(ЧтоЗаменять)) И СтруктураОбъектаБД.Данные[ИмяРеквизита] = ЧтоЗаменять Тогда
Если Истина
И РодителиПравильного <> Неопределено
И ирОбщий.СтрокиРавныЛкс(ПолеТаблицыБД.Имя, "Родитель")
И РодителиПравильного.Найти(СтруктураОбъектаБД.Данные.Ссылка) <> Неопределено
Тогда
// Вместо зацикливания уровней иерархии поднимаем до ближайшего корректного родителя
лНаЧтоЗаменять = ЧтоЗаменять.Родитель;
Пока РодителиПравильного.Найти(лНаЧтоЗаменять) <> Неопределено Цикл
лНаЧтоЗаменять = лНаЧтоЗаменять.Родитель;
КонецЦикла;
Сообщить("Родитель объекта """ + СтруктураОбъектаБД.Данные.Ссылка + """ был заменен на """ + лНаЧтоЗаменять + """ для избежания зацикливания уровней");
Иначе
лНаЧтоЗаменять = НаЧтоЗаменять;
КонецЕсли;
ОбъектИзменен = ЗаменитьЗначениеРеквизитаСПроверкойВозможности(СтруктураОбъектаБД.Данные, ИмяРеквизита, лНаЧтоЗаменять, ПоляТаблицыБД) Или ОбъектИзменен;
КонецЕсли;
КонецЕсли;
КонецЦикла;
Возврат ОбъектИзменен;
КонецФункции
// Результат - Булево - была ли выполнена замена
Функция ЗаменитьЗначениеРеквизитаСПроверкойВозможности(СтрокаТаблицы, ИмяРеквизита, НаЧтоЗаменять, ПоляТаблицыБД)
ОбъектНеИзменен = Истина;
ПолнаяЗаменаВозможна = ЗаменитьЗначениеРеквизитаСВлияющимиИЗависимыми(СтрокаТаблицы, ИмяРеквизита, НаЧтоЗаменять, ПоляТаблицыБД, , Истина);
Если ПолнаяЗаменаВозможна Тогда
ОбъектНеИзменен = ЗаменитьЗначениеРеквизитаСВлияющимиИЗависимыми(СтрокаТаблицы, ИмяРеквизита, НаЧтоЗаменять, ПоляТаблицыБД, , Ложь);
КонецЕсли;
Возврат Не ОбъектНеИзменен;
КонецФункции
// Результат - Булево
// Если ТолькоПроверитьВозможность = Истина, то содержит успешность полной замены
// Если ТолькоПроверитьВозможность = Ложь, то содержит факт отсутствия изменения объекта
Функция ЗаменитьЗначениеРеквизитаСВлияющимиИЗависимыми(СтрокаТаблицыБД, ИмяРеквизита, Знач НаЧтоЗаменять, ПоляТаблицыБД, ПравилаЗаменыЗависимых = Неопределено,
ТолькоПроверитьВозможность = Истина, ИмяРеквизитаОтбора = "Ссылка", ИсключитьЗависимое = "", ИсключитьВлияющее = "")
Результат = Истина;
Если ТипЗнч(НаЧтоЗаменять) = Тип("Структура") Тогда
ПравилаЗаменыЗависимых = НаЧтоЗаменять.ПравилаЗависимых;
НаЧтоЗаменять = НаЧтоЗаменять.Значение;
КонецЕсли;
ЧтоЗаменять = СтрокаТаблицыБД[ИмяРеквизита];
Если ТипЗнч(ЧтоЗаменять) = Тип("ЭлементОтбора") Тогда
ЧтоЗаменять = ЧтоЗаменять.Значение;
КонецЕсли;
Если ЧтоЗаменять = НаЧтоЗаменять Тогда
Возврат Результат;
КонецЕсли;
Если ПравилаЗаменыЗависимых <> Неопределено Тогда
ПолеТаблицы = ПоляТаблицыБД.Найти(ИмяРеквизита, "Имя");
ДанныеДляПоискаСвязейПоВладельцу = Неопределено;
Если ОпределятьСвязьПоВладельцуПоДанным Тогда
ДанныеДляПоискаСвязейПоВладельцу = СтрокаТаблицыБД;
КонецЕсли;
Если ПолеТаблицы.Метаданные <> Неопределено Тогда
СвязиПараметровВыбора = Новый Массив(ПолеТаблицы.Метаданные.СвязиПараметровВыбора);
Если ОпределятьСвязьПоВладельцуПоДанным Тогда
Попытка
ЗначениеВладельца = ЧтоЗаменять.Владелец;
Исключение
ЗначениеВладельца = Неопределено;
КонецПопытки;
Если ЗначениеЗаполнено(ЗначениеВладельца) Тогда
Для Каждого ПолеТаблицыБДВладельца Из ПоляТаблицыБД Цикл
Попытка
ЗначениеПоляВладельца = ДанныеДляПоискаСвязейПоВладельцу[ПолеТаблицыБДВладельца.Имя];
Исключение
// Ссылка у строки ТЧ
Продолжить;
КонецПопытки;
Если ТипЗнч(ЗначениеПоляВладельца) = Тип("ЭлементОтбора") Тогда
ЗначениеПоляВладельца = ЗначениеПоляВладельца.Значение;
КонецЕсли;
Если ЗначениеПоляВладельца = ЗначениеВладельца Тогда
СвязиПараметровВыбора.Добавить(Новый Структура("Имя, ПутьКДанным", "Отбор.Владелец", ПолеТаблицыБДВладельца.Имя));
КонецЕсли;
КонецЦикла;
КонецЕсли;
КонецЕсли;
УжеОбработанныеРеквизиты = Новый Структура;
Для Каждого СвязьПараметровВыбора Из СвязиПараметровВыбора Цикл
ИмяРеквизитаСодежащегоВлияющее = СвязьПараметровВыбора.ПутьКДанным;
ИмяРеквизитаСодежащегоВлияющее = ирОбщий.ПолучитьПоследнийФрагментЛкс(ИмяРеквизитаСодежащегоВлияющее);
Если ИсключитьВлияющее = ИмяРеквизитаСодежащегоВлияющее Тогда
Продолжить;
КонецЕсли;
ИмяРеквизитаОтбора = СтрЗаменить(СвязьПараметровВыбора.Имя, "Отбор.", "");
Если УжеОбработанныеРеквизиты.Свойство(ИмяРеквизитаОтбора) Тогда
Продолжить;
КонецЕсли;
УжеОбработанныеРеквизиты.Вставить(ИмяРеквизитаОтбора);
ВлияющееЗначениеЧтоЗаменять = ЧтоЗаменять[ИмяРеквизитаОтбора];
ВлияющееЗначениеНаЧтоЗаменять = НаЧтоЗаменять[ИмяРеквизитаОтбора];
Если ВлияющееЗначениеЧтоЗаменять <> ВлияющееЗначениеНаЧтоЗаменять Тогда
Результат = ЗаменитьЗначениеРеквизитаСВлияющимиИЗависимыми(СтрокаТаблицыБД, ИмяРеквизитаСодежащегоВлияющее, ВлияющееЗначениеНаЧтоЗаменять, ПоляТаблицыБД,
ПравилаЗаменыЗависимых, ТолькоПроверитьВозможность, ИмяРеквизитаОтбора, ИмяРеквизита) И Результат;
КонецЕсли;
КонецЦикла;
КонецЕсли;
ЗависимыеРеквизиты = ПолучитьЗависимыеРеквизитыМД(ПоляТаблицыБД, ИмяРеквизита, ДанныеДляПоискаСвязейПоВладельцу);
Для Каждого КлючИЗначение Из ЗависимыеРеквизиты Цикл
Если ИсключитьЗависимое = КлючИЗначение.Ключ Тогда
Продолжить;
КонецЕсли;
ЗависимоеЗначение = СтрокаТаблицыБД[КлючИЗначение.Ключ];
Если ТипЗнч(ЗависимоеЗначение) = Тип("ЭлементОтбора") Тогда
ЗависимоеЗначение = ЗависимоеЗначение.Значение;
КонецЕсли;
Если Не ЗначениеЗаполнено(ЗависимоеЗначение) Тогда
Продолжить;
КонецЕсли;
КлючПоискаПравила = Новый Структура("ПутьКДаннымВлияющего, ТипЗначения, ЧтоЗаменять, ЗависимоеВлияющее, ВлияющееЧтоЗаменять",
ИмяРеквизитаОтбора, Новый (ТипЗнч(ЗависимоеЗначение)), ЗависимоеЗначение, КлючИЗначение.Значение, ЧтоЗаменять);
ПравилаЗаменыЗависимого = ПравилаЗаменыЗависимых.НайтиСтроки(КлючПоискаПравила);
Если ПравилаЗаменыЗависимого.Количество() > 0 Тогда
ПравилоЗаменыЗависимого = ПравилаЗаменыЗависимого[0];
Если ПравилоЗаменыЗависимого.Пометка Тогда
Результат = ЗаменитьЗначениеРеквизитаСВлияющимиИЗависимыми(СтрокаТаблицыБД, КлючИЗначение.Ключ, ПравилоЗаменыЗависимого.НаЧтоЗаменять, ПоляТаблицыБД,
ПравилаЗаменыЗависимых, ТолькоПроверитьВозможность, ПравилоЗаменыЗависимого.ЗависимоеВлияющее,, ИмяРеквизита) И Результат;
Иначе
Результат = Ложь;
КонецЕсли;
Иначе
ПравилоЗаменыЗависимого = ПравилаЗаменыЗависимых.Добавить();
ЗаполнитьЗначенияСвойств(ПравилоЗаменыЗависимого, КлючПоискаПравила);
Результат = Ложь;
КонецЕсли;
ПравилоЗаменыЗависимого.НайденоСтрок = ПравилоЗаменыЗависимого.НайденоСтрок + 1;
ПравилоЗаменыЗависимого.Требуется = Истина;
КонецЦикла;
КонецЕсли;
Если Не ТолькоПроверитьВозможность Тогда
Если ТипЗнч(СтрокаТаблицыБД[ИмяРеквизита]) = Тип("ЭлементОтбора") Тогда
Результат = Не ирОбщий.БезопасноПрисвоитьПроизвольнуюСсылкуЛкс(СтрокаТаблицыБД[ИмяРеквизита].Значение, НаЧтоЗаменять) И Результат;
Иначе
Результат = Не ирОбщий.БезопасноПрисвоитьПроизвольнуюСсылкуЛкс(СтрокаТаблицыБД[ИмяРеквизита], НаЧтоЗаменять) И Результат;
КонецЕсли;
КонецЕсли;
Возврат Результат;
КонецФункции
Функция ВыполнитьЗаменуВНабореЗаписей(НаборЗаписейИлиМенеджерЗаписи, Заменяемые, НеправильныеСсылкиВОбъекте, Блокировать = Истина)
ОбъектМД = Метаданные.НайтиПоТипу(ирОбщий.ТипОбъектаБДЛкс(НаборЗаписейИлиМенеджерЗаписи));
ИмяТаблицыРегистра = ирОбщий.ПолучитьИмяТаблицыИзМетаданныхЛкс(ОбъектМД);
Если ирОбщий.ЛиМенеджерЗаписиРегистраЛкс(НаборЗаписейИлиМенеджерЗаписи) Тогда
НаборЗаписей = ирОбщий.ПолучитьНаборЗаписейПоКлючуЛкс(ИмяТаблицыРегистра, НаборЗаписейИлиМенеджерЗаписи);
СтруктураКлючаЗаписи = ирОбщий.ПолучитьСтруктуруКлючаТаблицыБДЛкс(ИмяТаблицыРегистра);
ЗаполнитьЗначенияСвойств(СтруктураКлючаЗаписи, НаборЗаписейИлиМенеджерЗаписи);
СтруктураНабораЗаписей = ирОбщий.ОбъектБДПоКлючуЛкс(ИмяТаблицыРегистра, СтруктураКлючаЗаписи,, Ложь, ЗаписьНаСервере);
Иначе
СтруктураНабораЗаписей = НаборЗаписейИлиМенеджерЗаписи;
КонецЕсли;
Если Блокировать Тогда
НачатьТранзакцию();
КонецЕсли;
Попытка
Если Блокировать Тогда
ирОбщий.ЗаблокироватьНаборЗаписейПоОтборуЛкс(СтруктураНабораЗаписей.Методы, Истина);
КонецЕсли;
ТипТаблицы = ирОбщий.ПолучитьТипТаблицыБДЛкс(ИмяТаблицыРегистра);
СтруктураНабораЗаписей.Методы.Прочитать();
Если СтруктураНабораЗаписей.Данные.Количество() = 0 Тогда
Если Блокировать Тогда
ЗафиксироватьТранзакцию();
КонецЕсли;
Возврат Истина;
КонецЕсли;
ПоляТаблицыБД = ирОбщий.ПолучитьПоляТаблицыМДЛкс(ОбъектМД,,,, Ложь);
#Если Сервер И Не Сервер Тогда
ПоляТаблицыБД = ПолучитьСтруктуруХраненияБазыДанных().Колонки;
#КонецЕсли
// Старый пустой набор нужен для очистки строк по старому отбору в случае изменения отбора набора
//СтарыйНабор = ирОбщий.СоздатьНаборЗаписейПоИмениТаблицыБДЛкс(ИмяТаблицыРегистра);
СтруктураСтарогоНабора = ирОбщий.ОбъектБДПоКлючуЛкс(ИмяТаблицыРегистра, СтруктураКлючаЗаписи,, Ложь, ЗаписьНаСервере);
ирОбщий.СкопироватьОтборПостроителяЛкс(СтруктураСтарогоНабора.Методы.Отбор, СтруктураНабораЗаписей.Методы.Отбор, Ложь);
ОтборИзменен = Ложь;
Для Каждого ЭлементОтбора Из СтруктураНабораЗаписей.Методы.Отбор Цикл
ЗначениеПоля = ЭлементОтбора.Значение;
НаЧтоЗаменять = Заменяемые[ЗначениеПоля];
Если НаЧтоЗаменять = Неопределено Тогда
Продолжить;
КонецЕсли;
ОтборИзменен = ЗаменитьЗначениеРеквизитаСПроверкойВозможности(СтруктураНабораЗаписей.Методы.Отбор, ЭлементОтбора.Имя, НаЧтоЗаменять, ПоляТаблицыБД) Или ОтборИзменен;
КонецЦикла;
ОбъектИзменен = ОтборИзменен; // Антибаг платформы 8.2. При изменении реквизитов строк набора записей для регистра бухгалтерии не взводится модифицированность
ЭтоРегистрБухгалтерии = ирОбщий.ПолучитьПервыйФрагментЛкс(ИмяТаблицыРегистра) = "РегистрБухгалтерии";
Если ЭтоРегистрБухгалтерии Тогда
ТаблицаНабора = СтруктураНабораЗаписей.Методы.Выгрузить();
Иначе
ТаблицаНабора = СтруктураНабораЗаписей.Данные;
КонецЕсли;
Для Каждого СтрокаНабора Из ТаблицаНабора Цикл
ОбъектИзменен = ВыполнитьЗаменуВСтрокеНабораЗаписей(СтрокаНабора, Заменяемые, ПоляТаблицыБД) Или ОбъектИзменен;
#Если Клиент Тогда
ОбработкаПрерыванияПользователя();
#КонецЕсли
КонецЦикла;
Если ЭтоРегистрБухгалтерии Тогда
СтруктураНабораЗаписей.Методы.Загрузить(ТаблицаНабора);
ирОбщий.НаборЗаписейПослеЗагрузкиИзТаблицыЗначенийЛкс(СтруктураНабораЗаписей.Методы);
ИначеЕсли ТипТаблицы = "РегистрСведений" И ОбъектМД.РежимЗаписи = Метаданные.СвойстваОбъектов.РежимЗаписиРегистра.ПодчинениеРегистратору Тогда
// Избавимся от неуникальных строк набора
Если СтруктураНабораЗаписей.Данные.Количество() > 1 Тогда
СтруктураКлюча = ирОбщий.ПолучитьСтруктуруКлючаТаблицыБДЛкс(ИмяТаблицыРегистра,,, Ложь);
СтрокаПолейКлюча = "";
Для Каждого КлючИЗначение Из СтруктураКлюча Цикл
СтрокаПолейКлюча = СтрокаПолейКлюча + "," + КлючИЗначение.Ключ;
КонецЦикла;
СтрокаПолейКлюча = Сред(СтрокаПолейКлюча, 2);
НеуникальныеКлючи = ирОбщий.ПолучитьНеуникальныеКлючиТаблицыЛкс(СтруктураНабораЗаписей.Данные, СтрокаПолейКлюча);
Если НеуникальныеКлючи.Количество() > 0 Тогда
ТаблицаНабора = СтруктураНабораЗаписей.Методы.Выгрузить();
Для Каждого НеуникальныйКлюч Из НеуникальныеКлючи Цикл
СтрокиНеуникальногоКлюча = ТаблицаНабора.НайтиСтроки(НеуникальныйКлюч);
Для ИндексУдаляемойСтроки = 0 По СтрокиНеуникальногоКлюча.Количество() - 2 Цикл
ТаблицаНабора.Удалить(СтрокиНеуникальногоКлюча[ИндексУдаляемойСтроки]);
КонецЦикла;
ПредставлениеСтруктуры = ирОбщий.ПолучитьПредставлениеСтруктурыЛкс(НеуникальныйКлюч);
Сообщить("Замещены неуникальные строки регистра сведений " + ОбъектМД.Имя + " по ключу " + ПредставлениеСтруктуры);
КонецЦикла;
СтруктураНабораЗаписей.Методы.Загрузить(ТаблицаНабора);
КонецЕсли;
КонецЕсли;
КонецЕсли;
Если ОбъектИзменен Тогда
Если ОтборИзменен Тогда
ирОбщий.ЗаписатьОбъектЛкс(СтруктураСтарогоНабора.Методы, ЗаписьНаСервере,,, ОтключатьКонтрольЗаписи, БезАвторегистрацииИзменений);
КонецЕсли;
ирОбщий.ЗаписатьОбъектЛкс(СтруктураНабораЗаписей.Методы, ЗаписьНаСервере,,, ОтключатьКонтрольЗаписи, БезАвторегистрацииИзменений);
КонецЕсли;
Если ТипТаблицы = "РегистрРасчета" Тогда
Для Каждого Перерасчет Из ОбъектМД.Перерасчеты Цикл
ИмяТаблицыПерерасчета = ирОбщий.ПолучитьИмяТаблицыИзМетаданныхЛкс(Перерасчет);
СтруктураНабораЗаписейПерерасчета = ирОбщий.ОбъектБДПоКлючуЛкс(ИмяТаблицыПерерасчета,,, Ложь, ЗаписьНаСервере);
СтруктураНабораЗаписейПерерасчета.Методы.Отбор.ОбъектПерерасчета.Установить(СтруктураНабораЗаписей.Методы.Отбор.Регистратор.Значение);
БылиИсключения = Не ВыполнитьЗаменуВНабореЗаписей(СтруктураНабораЗаписейПерерасчета, Заменяемые, НеправильныеСсылкиВОбъекте, Ложь);
Если БылиИсключения Тогда
Возврат Ложь;
КонецЕсли;
КонецЦикла;
КонецЕсли;
Если Блокировать Тогда
ЗафиксироватьТранзакцию();
КонецЕсли;
Исключение
Если Блокировать Тогда
ОтменитьТранзакцию();
КонецЕсли;
Если ОбщаяТранзакция Тогда
ВызватьИсключение;
КонецЕсли;
Сообщить("Ошибка обработки ссылающегося объекта " + ирОбщий.ПолучитьXMLКлючОбъектаБДЛкс(СтруктураНабораЗаписей.Методы) + ": " + ОписаниеОшибки(), СтатусСообщения.Внимание);
Возврат Ложь;
КонецПопытки;
Возврат Истина;
КонецФункции
Функция ВыполнитьЗаменуВСтрокеНабораЗаписей(СтрокаНабора, Заменяемые, ПоляТаблицыБД)
ОбъектИзменен = Ложь;
Для Каждого ПолеТаблицыБД Из ПоляТаблицыБД Цикл
Если ПолеТаблицыБД.ТипЗначения.СодержитТип(Тип("ТаблицаЗначений")) Тогда
Продолжить;
КонецЕсли;
//Если Не Поле.Поле Тогда // было для полей построителя запроса
// // Антибаг платформы. Зачем то добавляются лишние поля в доступные поля, не свойственные по признаку наличия корресподнеции
// // у бухгалтерских таблиц.
// Продолжить;
//КонецЕсли;
//ИмяПоля = Поле.Имя;
ИмяПоля = ПолеТаблицыБД.Имя;
ЗначениеПоля = СтрокаНабора[ИмяПоля];
НаЧтоЗаменять = Заменяемые[ЗначениеПоля];
Если НаЧтоЗаменять = Неопределено Тогда
Продолжить;
КонецЕсли;
ОбъектИзменен = ЗаменитьЗначениеРеквизитаСПроверкойВозможности(СтрокаНабора, ИмяПоля, НаЧтоЗаменять, ПоляТаблицыБД) Или ОбъектИзменен;
КонецЦикла;
Возврат ОбъектИзменен;
КонецФункции
Функция ПолучитьЗависимыеРеквизитыМД(ПоляТаблицы, ИмяРеквизита, ДанныеДляПоискаСвязейПоВладельцу = Неопределено) Экспорт
Результат = Новый Структура;
Для Каждого ПолеТаблицы Из ПоляТаблицы Цикл
Если ПолеТаблицы.Метаданные = Неопределено Тогда
Продолжить;
КонецЕсли;
Для Каждого СвязьПараметровВыбора Из ПолеТаблицы.Метаданные.СвязиПараметровВыбора Цикл
ИмяРеквизитаСодежащегоВлияющее = СвязьПараметровВыбора.ПутьКДанным;
//Если Найти(ИмяРеквизитаСодежащегоВлияющее, ОбъектМД.Имя + ".") = 1 Тогда
// // Это строка ТЧ
ИмяРеквизитаСодежащегоВлияющее = ирОбщий.ПолучитьПоследнийФрагментЛкс(ИмяРеквизитаСодежащегоВлияющее);
//КонецЕсли;
Если ИмяРеквизитаСодежащегоВлияющее = ИмяРеквизита Тогда
ИмяРеквизитаОтбора = СтрЗаменить(СвязьПараметровВыбора.Имя, "Отбор.", "");
Результат.Вставить(ПолеТаблицы.Имя, ИмяРеквизитаОтбора);
КонецЕсли;
КонецЦикла;
Если ДанныеДляПоискаСвязейПоВладельцу <> Неопределено Тогда
Попытка
ЗначениеВладельца = ДанныеДляПоискаСвязейПоВладельцу[ПолеТаблицы.Имя].Владелец;
Исключение
ЗначениеВладельца = Неопределено;
КонецПопытки;
Если ЗначениеВладельца <> Неопределено Тогда
Если ЗначениеВладельца = ДанныеДляПоискаСвязейПоВладельцу[ИмяРеквизита] Тогда
Результат.Вставить(ПолеТаблицы.Имя, "Владелец");
КонецЕсли;
КонецЕсли;
КонецЕсли;
КонецЦикла;
Возврат Результат;
КонецФункции
Функция ОбработатьНеправильныйОбъектПослеЗамены(УдаляемаяСсылка, НепосредственноеУдаление = Ложь, СсылкаДляЗаменыДанных = Неопределено) Экспорт
#Если Сервер И Не Сервер Тогда
УдаляемаяСсылка = Справочники.УчастникиИис.ПустаяСсылка();
#КонецЕсли
СтруктураОбъекта = ирОбщий.ОбъектБДПоКлючуЛкс(ПолноеИмяОбъекта, УдаляемаяСсылка,,, ЗаписьНаСервере);
ОбъектУдалили = СтруктураОбъекта.Методы.ЭтоНовый();
Если Не ОбъектУдалили Тогда
КорневойТип = ирОбщий.ПолучитьКорневойТипКонфигурацииЛкс(УдаляемаяСсылка);
НачатьТранзакцию();
Попытка
ПредставлениеОбъекта = "" + СтруктураОбъекта.Данные.Ссылка;
Если СсылкаДляЗаменыДанных <> Неопределено Тогда
ПравильныйЭлементСНеправильнымиДанными = СсылкаДляЗаменыДанных.ПолучитьОбъект();
СтандартнаяОбработка = Истина;
Если ЗначениеЗаполнено(ОбработкаЗаменыДанных) Тогда
ТекстАлгоритма = "ПравильныйОбъект = _П0; НеправильныйОбъект = _П1; СтандартнаяОбработка = _П2; " + ОбработкаЗаменыДанных + "; _П2 = СтандартнаяОбработка;";
ирОбщий.ВыполнитьАлгоритм(ТекстАлгоритма,,, ПравильныйЭлементСНеправильнымиДанными, СтруктураОбъекта.Данные, СтандартнаяОбработка);
КонецЕсли;
Если СтандартнаяОбработка Тогда
НеправильныйОбъектXDTO = СериализаторXDTO.ЗаписатьXDTO(ПравильныйЭлементСНеправильнымиДанными);
НеправильныйОбъектXDTO.Ref = УдаляемаяСсылка;
ПравильныйОбъектXDTO = СериализаторXDTO.ЗаписатьXDTO(СтруктураОбъекта.Данные);
ПравильныйОбъектXDTO.Ref = СсылкаДляЗаменыДанных;
ПравильныйОбъект = СериализаторXDTO.ПрочитатьXDTO(ПравильныйОбъектXDTO);
Если Истина
И Не ирОбщий.РежимСовместимостиМеньше8_3_4Лкс()
И ирОбщий.ЛиКорневойТипОбъектаСПредопределеннымЛкс(КорневойТип)
И (Ложь
Или Не НепосредственноеУдаление
Или (Истина
И НепосредственноеУдаление
И Не ЗначениеЗаполнено(ПравильныйОбъект.ИмяПредопределенныхДанных)))
Тогда
ПравильныйОбъект.ИмяПредопределенныхДанных = ПравильныйЭлементСНеправильнымиДанными.ИмяПредопределенныхДанных;
КонецЕсли;
Иначе
ПравильныйОбъект = ПравильныйЭлементСНеправильнымиДанными;
КонецЕсли;
ирОбщий.ЗаписатьОбъектЛкс(ПравильныйОбъект, ЗаписьНаСервере, , , Истина);
Если СтандартнаяОбработка Тогда
Объект = СериализаторXDTO.ПрочитатьXDTO(НеправильныйОбъектXDTO);
Объект.Прочитать();
ПредставлениеОбъекта = "" + Объект;
КонецЕсли;
КонецЕсли;
Если НепосредственноеУдаление Тогда
ирОбщий.УдалитьОбъектЛкс(СтруктураОбъекта.Методы, ЗаписьНаСервере, ОтключатьКонтрольЗаписи, БезАвторегистрацииИзменений);
ОбъектУдалили = Истина;
Сообщить("Удалили """ + ПредставлениеОбъекта + """");
Иначе
ирОбщий.УстановитьПометкуУдаленияОбъектаЛкс(СтруктураОбъекта.Методы, ЗаписьНаСервере, Истина);
Сообщить("Установили пометку удаления """ + ПредставлениеОбъекта + """");
КонецЕсли;
ЗафиксироватьТранзакцию();
Исключение
Сообщить("Обработка неправильного """ + ПредставлениеОбъекта + """: " + ОписаниеОшибки());
ОтменитьТранзакцию();
КонецПопытки;
КонецЕсли;
Возврат ОбъектУдалили;
КонецФункции
Процедура ОбработатьПравильныйОбъектПослеЗамены(ПравильнаяСсылка, СнятьПометкуУдаления = Ложь, Перезаписать = Ложь) Экспорт
Если Истина
И Не СнятьПометкуУдаления
И Не Перезаписать
Тогда
Возврат;
КонецЕсли;
ПолноеИмяМД = ПравильнаяСсылка.Метаданные().ПолноеИмя();
СтруктураОбъекта = ирОбщий.ОбъектБДПоКлючуЛкс(ПолноеИмяМД, ПравильнаяСсылка,,, ЗаписьНаСервере);
Попытка
Если СнятьПометкуУдаления Тогда
СтруктураОбъекта.Данные.ПометкаУдаления = Ложь;
Сообщить("Сняли пометку удаления """ + ПравильнаяСсылка + """");
КонецЕсли;
ирОбщий.ЗаписатьОбъектЛкс(СтруктураОбъекта.Методы, ЗаписьНаСервере, , , ОтключатьКонтрольЗаписи, БезАвторегистрацииИзменений);
Исключение
Сообщить("Обработка правильного """ + ПравильнаяСсылка + """: " + ОписаниеОшибки(), СтатусСообщения.Внимание);
КонецПопытки;
КонецПроцедуры
Функция ПолучитьСсылочныеИзмеренияРегистраЛкс(НаборЗаписей, МетаРегистр) Экспорт
ПоляТаблицы = НаборЗаписей.ВыгрузитьКолонки();
Результат = Новый Структура;
Для Каждого МетаИзмерение Из МетаРегистр.Измерения Цикл
ПолеТаблицы = ПоляТаблицы.Найти(МетаИзмерение.Имя);
Если ПолеТаблицы = Неопределено Тогда
// Например, небалансовое измерение регистра бухгалтерии
Продолжить;
КонецЕсли;
Для Каждого Тип Из МетаИзмерение.Тип.Типы() Цикл
Если Найти(XMLТип(Тип).ИмяТипа, "Ref.") > 0 Тогда
Результат.Вставить(МетаИзмерение.Имя, МетаИзмерение.Тип);
Прервать;
КонецЕсли;
КонецЦикла;
КонецЦикла;
Возврат Результат;
КонецФункции
Процедура ЗаблокироватьРегистрПоОтборуИИзмерениямПередЗаменой(НаборЗаписей, НайденныеВОбъектеНеправильныеСсылки) Экспорт
Блокировка = Новый БлокировкаДанных;
ОбъектМД = НаборЗаписей.Метаданные();
ПолноеИмяМД = ОбъектМД.ПолноеИмя();
ИмяТаблицыРегистра = ирОбщий.ПолучитьИмяТаблицыИзМетаданныхЛкс(ОбъектМД);
ТипТаблицы = ирОбщий.ПолучитьТипТаблицыБДЛкс(ИмяТаблицыРегистра);
// По регистратору
Если Ложь
Или Не ирОбщий.ЛиКорневойТипРегистраСведенийЛкс(ТипТаблицы)
Или ОбъектМД.РежимЗаписи = Метаданные.СвойстваОбъектов.РежимЗаписиРегистра.ПодчинениеРегистратору
Тогда
ПространствоБлокировок = ПолноеИмяМД + ".НаборЗаписей";
ЭлементБлокировки = Блокировка.Добавить(ПространствоБлокировок);
ЭлементБлокировки.УстановитьЗначение("Регистратор", НаборЗаписей.Отбор.Регистратор.Значение);
КонецЕсли;
// По измерениям блокируем все возможные диапазоны. В большинстве случаев при замене ссылок такие блокировки будут неоправданными
ПространствоБлокировок = ПолноеИмяМД;
ЭлементБлокировки = Блокировка.Добавить(ПространствоБлокировок);
СсылочныеИзмерения = ПолучитьСсылочныеИзмеренияРегистраЛкс(НаборЗаписей, ОбъектМД);
Для Каждого КлючЗначение Из СсылочныеИзмерения Цикл
ИмяИзмерения = КлючЗначение.Ключ;
ТипИзмерения = КлючЗначение.Значение;
Для Каждого НеправильнаяСсылка Из НайденныеВОбъектеНеправильныеСсылки Цикл
Если ТипИзмерения.СодержитТип(ТипЗнч(НеправильнаяСсылка)) Тогда
Блокировка.Добавить(ПространствоБлокировок).УстановитьЗначение(ИмяИзмерения, НеправильнаяСсылка);
КонецЕсли;
КонецЦикла;
КонецЦикла;
Блокировка.Заблокировать();
КонецПроцедуры // ВыполнитьЗаменуВНабореЗаписей()
//ирПортативный лФайл = Новый Файл(ИспользуемоеИмяФайла);
//ирПортативный ПолноеИмяФайлаБазовогоМодуля = Лев(лФайл.Путь, СтрДлина(лФайл.Путь) - СтрДлина("Модули\")) + "ирПортативный.epf";
//ирПортативный #Если Клиент Тогда
//ирПортативный Контейнер = Новый Структура();
//ирПортативный Оповестить("ирПолучитьБазовуюФорму", Контейнер);
//ирПортативный Если Не Контейнер.Свойство("ирПортативный", ирПортативный) Тогда
//ирПортативный ирПортативный = ВнешниеОбработки.ПолучитьФорму(ПолноеИмяФайлаБазовогоМодуля);
//ирПортативный ирПортативный.Открыть();
//ирПортативный КонецЕсли;
//ирПортативный #Иначе
//ирПортативный ирПортативный = ВнешниеОбработки.Создать(ПолноеИмяФайлаБазовогоМодуля, Ложь); // Это будет второй экземпляр объекта
//ирПортативный #КонецЕсли
//ирПортативный ирОбщий = ирПортативный.ПолучитьОбщийМодульЛкс("ирОбщий");
//ирПортативный ирКэш = ирПортативный.ПолучитьОбщийМодульЛкс("ирКэш");
//ирПортативный ирСервер = ирПортативный.ПолучитьОбщийМодульЛкс("ирСервер");
//ирПортативный ирПривилегированный = ирПортативный.ПолучитьОбщийМодульЛкс("ирПривилегированный");
мПлатформа = ирКэш.Получить();
ТаблицаБукв = Новый ТаблицаЗначений;
ТаблицаБукв.Колонки.Добавить("Позиция");
ТаблицаБукв.Колонки.Добавить("КолвоПропущенных");
ТаблицаБукв.Колонки.Добавить("ДлинаСлова");
ТаблицаБукв.Колонки.Добавить("ПропущеноНа");
ЗаписьНаСервере = ирОбщий.ПолучитьРежимЗаписиНаСервереПоУмолчаниюЛкс();
ЭтотОбъект.ОтключатьКонтрольЗаписи = Истина;