#Если Сервер Или ТолстыйКлиентОбычноеПриложение Или ВнешнееСоединение Тогда
#Область СлужебныеПроцедурыИФункции
Функция МенеджерОбластиПоискаДублей(Знач ИмяОбластиПоискаДанных) Экспорт
ОбластьПоискаДанных = ОбщегоНазначения.ОбъектМетаданныхПоПолномуИмени(ИмяОбластиПоискаДанных);
Если Метаданные.Справочники.Содержит(ОбластьПоискаДанных) Тогда
Возврат Справочники[ОбластьПоискаДанных.Имя];
ИначеЕсли Метаданные.ПланыВидовХарактеристик.Содержит(ОбластьПоискаДанных) Тогда
Возврат ПланыВидовХарактеристик[ОбластьПоискаДанных.Имя];
ИначеЕсли Метаданные.ПланыСчетов.Содержит(ОбластьПоискаДанных) Тогда
Возврат ПланыСчетов[ОбластьПоискаДанных.Имя];
ИначеЕсли Метаданные.ПланыВидовРасчета.Содержит(ОбластьПоискаДанных) Тогда
Возврат ПланыВидовРасчета[ОбластьПоискаДанных.Имя];
КонецЕсли;
ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Некорректный тип объекта метаданных ""%1""'"), ИмяОбластиПоискаДанных);
КонецФункции
Функция ГруппыДублей(Знач ПараметрыПоиска, Знач ЭталонныйОбъект = Неопределено) Экспорт
ПолноеИмяОбъектаМетаданных = ПараметрыПоиска.ОбластьПоискаДублей;
ОбъектМетаданных = ОбщегоНазначения.ОбъектМетаданныхПоПолномуИмени(ПолноеИмяОбъектаМетаданных);
РазмерВозвращаемойПорции = ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(ПараметрыПоиска, "МаксимальноеЧислоДублей");
Если Не ЗначениеЗаполнено(РазмерВозвращаемойПорции) Тогда
РазмерВозвращаемойПорции = 0;
КонецЕсли;
РассчитыватьМестаИспользования = ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(ПараметрыПоиска, "РассчитыватьМестаИспользования");
Если ТипЗнч(РассчитыватьМестаИспользования) <> Тип("Булево") Тогда
РассчитыватьМестаИспользования = Ложь;
КонецЕсли;
СкрыватьНезначимыеДубли = ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(ПараметрыПоиска, "РассчитыватьМестаИспользования");
Если Не ЗначениеЗаполнено(СкрыватьНезначимыеДубли) Тогда
СкрыватьНезначимыеДубли = Истина;
КонецЕсли;
ЕстьПравилаПоиска = Ложь;
ДополнительныеПараметры = ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(ПараметрыПоиска, "ДополнительныеПараметры");
МенеджерОбластиПоиска = Неопределено;
ПрикладныеПараметрыПоиска = ПоискИУдалениеДублей.ПараметрыПоискаДублей(ПараметрыПоиска.ПравилаПоиска,
ПараметрыПоиска.КомпоновщикПредварительногоОтбора);
Если ЕстьПрикладныеПравилаОбластиПоискаДублей(ПолноеИмяОбъектаМетаданных) Тогда
МенеджерОбластиПоиска = ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени(ПолноеИмяОбъектаМетаданных);
МенеджерОбластиПоиска.ПараметрыПоискаДублей(ПрикладныеПараметрыПоиска, ДополнительныеПараметры);
ЕстьПравилаПоиска = ПараметрыПоиска.УчитыватьПрикладныеПравила;
КонецЕсли;
СтандартнаяОбработка = Истина;
ПоискИУдалениеДублейПереопределяемый.ПриОпределенииПараметровПоискаДублей(ПолноеИмяОбъектаМетаданных,
ПрикладныеПараметрыПоиска, ДополнительныеПараметры, СтандартнаяОбработка);
Если Не СтандартнаяОбработка Тогда
ЕстьПравилаПоиска = ЕстьПравилаПоиска Или ПараметрыПоиска.УчитыватьПрикладныеПравила;
КонецЕсли;
ИменаДополнительныхПолей = "";
КоличествоЭлементовДляСравнения = 0;
Если ЕстьПравилаПоиска Тогда
ВсеДополнительныеПоля = Новый Соответствие;
Для Каждого Ограничение Из ПрикладныеПараметрыПоиска.ОграниченияСравнения Цикл
Для Каждого ПолеТаблицы Из Новый Структура(Ограничение.ДополнительныеПоля) Цикл
ИмяПоля = ПолеТаблицы.Ключ;
Если ВсеДополнительныеПоля[ИмяПоля] = Неопределено Тогда
ИменаДополнительныхПолей = ИменаДополнительныхПолей + ", " + ИмяПоля;
ВсеДополнительныеПоля[ИмяПоля] = Истина;
КонецЕсли;
КонецЦикла;
КонецЦикла;
ИменаДополнительныхПолей = Сред(ИменаДополнительныхПолей, 2);
КоличествоЭлементовДляСравнения = ПрикладныеПараметрыПоиска.КоличествоЭлементовДляСравнения;
КонецЕсли;
Характеристики = ХарактеристикиОбъектаМетаданных(ОбъектМетаданных);
СтруктураЗапроса = ТекстЗапросаПоискаДублей(ПараметрыПоиска, Характеристики, ИменаДополнительныхПолей);
СхемаЗапроса = СхемаКомпоновкиДанныхПоискаДублей(ПараметрыПоиска, Характеристики, СтруктураЗапроса, ЭталонныйОбъект);
КоллекцияДублей = КоллекцияДублей(ПараметрыПоиска, СтруктураЗапроса.ИменаПолейДляСравненияНаПодобие,
СтруктураЗапроса.ИменаПолейДляСравненияНаРавенство);
ТаблицаДублей = КоллекцияДублей.ТаблицаДублей;
Результат = Новый Структура;
Результат.Вставить("ТаблицаДублей", ТаблицаДублей);
Результат.Вставить("ОписаниеОшибки");
Результат.Вставить("ВозвращеноМеньшеЧемНайдено", Ложь);
Результат.Вставить("МестаИспользования");
ТаблицаКандидатов = ТаблицаКандидатов();
ПараметрыПоискаПохожихСтрок = Неопределено;
КоличествоДублей = 0;
Пока СледующийЭлементВыборки(СхемаЗапроса.ВыборкаЭталонныхОбъектов) Цикл
ЭталонныйЭлемент = СхемаЗапроса.ВыборкаЭталонныхОбъектов.ТекущийЭлемент;
Для Каждого ЭлементОтбора Из СхемаЗапроса.ОтборыКандидатов Цикл
ЭлементОтбора.Значение.ПравоеЗначение = ЭталонныйЭлемент[ЭлементОтбора.Ключ];
КонецЦикла;
ВыборкаКандидатов = ИнициализироватьВыборкуКД(СхемаЗапроса.СхемаКД, СхемаЗапроса.НастройкиКД);
КандидатыДублей = ВыборкаКандидатов.ПроцессорВыводаКД.Вывести(ВыборкаКандидатов.ПроцессорКД);
Если СтруктураЗапроса.ИменаПолейДляСравненияНаПодобие.Количество() > 0 Тогда
СравнениеСтрокНаПодобие = ПрикладныеПараметрыПоиска.СравнениеСтрокНаПодобие;
Если ПараметрыПоискаПохожихСтрок = Неопределено Тогда
Попытка
ПараметрыПоискаПохожихСтрок = ПоискИУдалениеДублей.ПараметрыПоискаПохожихСтрок();
Исключение
Результат.ОписаниеОшибки =
НСтр("ru = 'Не удалось подключить компоненту для нечеткого поиска дублей. Подробнее см. в журнале регистрации.'");
Возврат Результат;
КонецПопытки;
КонецЕсли;
ЗаполнитьЗначенияСвойств(ПараметрыПоискаПохожихСтрок, СравнениеСтрокНаПодобие);
Для Каждого ИмяПоля Из СтруктураЗапроса.ИменаПолейДляСравненияНаПодобие Цикл
ЗначенияПоля = Новый Массив;
Для каждого СтрокаТаблицы Из КандидатыДублей Цикл
ЗначенияПоля.Добавить(СтрЗаменить(СтрокаТаблицы[ИмяПоля], "~", "\u126"));
КонецЦикла;
ИскомыеСтроки = СтрСоединить(ЗначенияПоля, "~");
СтрокаДляПоиска = ЭталонныйЭлемент[ИмяПоля];
ИндексыСтрок = ПоискИУдалениеДублей.НайтиПохожиеСтроки(ИскомыеСтроки, СтрокаДляПоиска, "~", ПараметрыПоискаПохожихСтрок);
Если ПустаяСтрока(ИндексыСтрок) Тогда
Продолжить;
КонецЕсли;
Для Каждого ИндексСтроки Из СтрРазделить(ИндексыСтрок, ",") Цикл
Если ПустаяСтрока(ИндексСтроки) Тогда
Продолжить;
КонецЕсли;
ЭлементДубль = КандидатыДублей[Число(ИндексСтроки)];
Если ЕстьПравилаПоиска Тогда
ДобавитьСтрокуКандидатов(КоллекцияДублей, ТаблицаКандидатов, ЭталонныйЭлемент, ЭлементДубль,
СтруктураЗапроса);
Если ТаблицаКандидатов.Количество() = КоличествоЭлементовДляСравнения Тогда
ЗарегистрироватьДублиПоПрикладнымПравилам(КоллекцияДублей, ПолноеИмяОбъектаМетаданных,
МенеджерОбластиПоиска, ЭталонныйЭлемент, ТаблицаКандидатов, СтруктураЗапроса,
ДополнительныеПараметры);
ТаблицаКандидатов.Очистить();
КонецЕсли;
Иначе
ЗарегистрироватьДубль(КоллекцияДублей, ЭталонныйЭлемент, ЭлементДубль, СтруктураЗапроса);
КонецЕсли;
КонецЦикла;
КонецЦикла;
Иначе
Для Каждого ЭлементДубль Из КандидатыДублей Цикл
Если ЕстьПравилаПоиска Тогда
ДобавитьСтрокуКандидатов(КоллекцияДублей, ТаблицаКандидатов, ЭталонныйЭлемент, ЭлементДубль,
СтруктураЗапроса);
Если ТаблицаКандидатов.Количество() = КоличествоЭлементовДляСравнения Тогда
ЗарегистрироватьДублиПоПрикладнымПравилам(ТаблицаДублей, ПолноеИмяОбъектаМетаданных,
МенеджерОбластиПоиска, ЭталонныйЭлемент, ТаблицаКандидатов, СтруктураЗапроса,
ДополнительныеПараметры);
ТаблицаКандидатов.Очистить();
КонецЕсли;
Иначе
ЗарегистрироватьДубль(КоллекцияДублей, ЭталонныйЭлемент, ЭлементДубль, СтруктураЗапроса);
КонецЕсли;
КонецЦикла;
КонецЕсли;
Если ЕстьПравилаПоиска Тогда
ЗарегистрироватьДублиПоПрикладнымПравилам(КоллекцияДублей, ПолноеИмяОбъектаМетаданных, МенеджерОбластиПоиска,
ЭталонныйЭлемент, ТаблицаКандидатов, СтруктураЗапроса, ДополнительныеПараметры);
ТаблицаКандидатов.Очистить();
КонецЕсли;
УдалитьНезначимыеДубли(КоллекцияДублей);
УдалитьНезначимыеГруппы(КоллекцияДублей);
Если КоличествоДублей <> ТаблицаДублей.Количество() Тогда
КоличествоДублей = ТаблицаДублей.Количество();
ДлительныеОперации.СообщитьПрогресс(КоличествоДублей, "ЗарегистрироватьДубль");
КонецЕсли;
Если РазмерВозвращаемойПорции > 0 И (ТаблицаДублей.Количество() > РазмерВозвращаемойПорции) Тогда
Результат.ОписаниеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Найдено слишком много дублей. Показаны только первые %1.'"), РазмерВозвращаемойПорции);
Результат.ВозвращеноМеньшеЧемНайдено = Истина;
Прервать;
КонецЕсли;
КонецЦикла;
Если РассчитыватьМестаИспользования Тогда
ДлительныеОперации.СообщитьПрогресс(0, "РассчитыватьМестаИспользования");
СсылкиОбъектов = Новый Массив;
Для Каждого СтрокаДублей Из ТаблицаДублей Цикл
Если ЗначениеЗаполнено(СтрокаДублей.Ссылка) Тогда
СсылкиОбъектов.Добавить(СтрокаДублей.Ссылка);
КонецЕсли;
КонецЦикла;
МестаИспользования = ОбщегоНазначения.МестаИспользования(СсылкиОбъектов);
МестаИспользования = МестаИспользования.Скопировать(
МестаИспользования.НайтиСтроки(Новый Структура("ВспомогательныеДанные", Ложь)));
МестаИспользования.Индексы.Добавить("Ссылка");
Результат.МестаИспользования = МестаИспользования;
КонецЕсли;
Возврат Результат;
КонецФункции
Функция ЕстьПрикладныеПравилаОбластиПоискаДублей(Знач ИмяОбъекта) Экспорт
СведенияОбОбъекте = ПоискИУдалениеДублей.ОбъектыСПоискомДублей()[ИмяОбъекта];
Возврат СведенияОбОбъекте <> Неопределено
И (СведенияОбОбъекте = "" Или СтрНайти(СведенияОбОбъекте, "ПараметрыПоискаДублей") > 0);
КонецФункции
Процедура ФоновыйПоискДублей(Знач Параметры, Знач АдресРезультата) Экспорт
НачалоПоискаДублей = ТекущаяДатаСеанса();
ЗаписьЖурналаРегистрации(ПоискИУдалениеДублей.НаименованиеПодсистемы(Ложь),
УровеньЖурналаРегистрации.Информация,,,
СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Начат поиск дублей для: %1.'"), Параметры.ОбластьПоискаДублей));
КомпоновщикПредварительногоОтбора = Новый КомпоновщикНастроекКомпоновкиДанных;
КомпоновщикПредварительногоОтбора.Инициализировать(Новый ИсточникДоступныхНастроекКомпоновкиДанных(Параметры.СхемаКомпоновки));
КомпоновщикПредварительногоОтбора.ЗагрузитьНастройки(Параметры.НастройкиКомпоновщикаПредварительногоОтбора);
Параметры.Вставить("КомпоновщикПредварительногоОтбора", КомпоновщикПредварительногоОтбора);
ПравилаПоиска = Новый ТаблицаЗначений;
ПравилаПоиска.Колонки.Добавить("Реквизит", Новый ОписаниеТипов("Строка") );
ПравилаПоиска.Колонки.Добавить("Правило", Новый ОписаниеТипов("Строка") );
ПравилаПоиска.Индексы.Добавить("Реквизит");
Для Каждого Правило Из Параметры.ПравилаПоиска Цикл
ЗаполнитьЗначенияСвойств(ПравилаПоиска.Добавить(), Правило);
КонецЦикла;
Параметры.Вставить("ПравилаПоиска", ПравилаПоиска);
Параметры.Вставить("РассчитыватьМестаИспользования", Истина);
Результат = ГруппыДублей(Параметры);
ПоместитьВоВременноеХранилище(Результат, АдресРезультата);
ЗаписьЖурналаРегистрации(ПоискИУдалениеДублей.НаименованиеПодсистемы(Ложь),
УровеньЖурналаРегистрации.Информация,,,
СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Завершен поиск дублей для ""%1"" за %2 мин.'"),
Параметры.ОбластьПоискаДублей,
Формат((ТекущаяДатаСеанса() - НачалоПоискаДублей) / 60, "ЧДЦ=2")));
КонецПроцедуры
Функция ФоновоеУдалениеДублей(Знач Параметры) Экспорт
НачалоУдаленияДублей = ТекущаяДатаСеанса();
КоличествоДублей = Параметры.ПарыЗамен.Количество();
ЗаписьЖурналаРегистрации(ПоискИУдалениеДублей.НаименованиеПодсистемы(Ложь),
УровеньЖурналаРегистрации.Информация,,,
СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Начато удаление дублей: %1.'"), КоличествоДублей));
ПараметрыЗамены = Новый Структура;
ПараметрыЗамены.Вставить("ВключатьБизнесЛогику", Ложь);
ПараметрыЗамены.Вставить("УчитыватьПрикладныеПравила", Параметры.УчитыватьПрикладныеПравила);
ПараметрыЗамены.Вставить("ЗаменаПарыВТранзакции", Ложь);
ПараметрыЗамены.Вставить("СпособУдаления", Параметры.СпособУдаления);
Результат = ОбщегоНазначения.ЗаменитьСсылки(Параметры.ПарыЗамен, ПараметрыЗамены);
ЗаписьЖурналаРегистрации(ПоискИУдалениеДублей.НаименованиеПодсистемы(Ложь),
УровеньЖурналаРегистрации.Информация,,,
СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Завершено удаление дублей %1 за %2 мин.'"),
КоличествоДублей,
Формат((ТекущаяДатаСеанса() - НачалоУдаленияДублей) / 60, "ЧДЦ=2")));
Возврат Результат;
КонецФункции
Функция ОбъектВТаблицуЗначений(Знач ОбъектДанных, Знач РасшифровкаДополнительныхПолей)
Результат = Новый ТаблицаЗначений;
СтрокаДанных = Результат.Добавить();
МетаданныеОбъекты = ОбъектДанных.Метаданные();
Для Каждого МетаРеквизит Из МетаданныеОбъекты.СтандартныеРеквизиты Цикл
Имя = МетаРеквизит.Имя;
Результат.Колонки.Добавить(Имя, МетаРеквизит.Тип);
СтрокаДанных[Имя] = ОбъектДанных[Имя];
КонецЦикла;
Для Каждого МетаРеквизит Из МетаданныеОбъекты.Реквизиты Цикл
Имя = МетаРеквизит.Имя;
Результат.Колонки.Добавить(Имя, МетаРеквизит.Тип);
СтрокаДанных[Имя] = ОбъектДанных[Имя];
КонецЦикла;
Для Каждого КлючИЗначение Из РасшифровкаДополнительныхПолей Цикл
Имя1 = КлючИЗначение.Ключ;
Имя2 = КлючИЗначение.Значение;
Результат.Колонки.Добавить(Имя1, Результат.Колонки[Имя2].ТипЗначения);
СтрокаДанных[Имя1] = СтрокаДанных[Имя2];
КонецЦикла;
Возврат Результат;
КонецФункции
Процедура ЗарегистрироватьДублиПоПрикладнымПравилам(КоллекцияДублей, Знач ПолноеИмяОбъектаМетаданных,
Знач МенеджерОбластиПоиска, Знач ОсновныеДанные, Знач ДублиЭлементов, Знач СтруктураЗапроса, Знач ДополнительныеПараметры)
Если ДублиЭлементов.Количество() = 0 Тогда
Возврат;
КонецЕсли;
Если МенеджерОбластиПоиска <> Неопределено Тогда
МенеджерОбластиПоиска.ПриПоискеДублей(ДублиЭлементов, ДополнительныеПараметры);
КонецЕсли;
ПоискИУдалениеДублейПереопределяемый.ПриПоискеДублей(ПолноеИмяОбъектаМетаданных, ДублиЭлементов, ДополнительныеПараметры);
Данные1 = Новый Структура;
Данные2 = Новый Структура;
НайденныеДубли = ДублиЭлементов.НайтиСтроки(Новый Структура("ЭтоДубли", Истина));
Для Каждого Дубль Из НайденныеДубли Цикл
Данные1.Вставить("Ссылка", Дубль.Ссылка1);
Данные1.Вставить("Код", Дубль.Поля1.Код);
Данные1.Вставить("Наименование", Дубль.Поля1.Наименование);
Данные1.Вставить("ПометкаУдаления", Дубль.Поля1.ПометкаУдаления);
Данные2.Вставить("Ссылка", Дубль.Ссылка2);
Данные2.Вставить("Код", Дубль.Поля2.Код);
Данные2.Вставить("Наименование", Дубль.Поля2.Наименование);
Данные2.Вставить("ПометкаУдаления", Дубль.Поля2.ПометкаУдаления);
Для Каждого ИмяПоля Из СтруктураЗапроса.ИменаПолейДляСравненияНаРавенство Цикл
Данные1.Вставить(ИмяПоля, Дубль.Поля1[ИмяПоля]);
Данные2.Вставить(ИмяПоля, Дубль.Поля2[ИмяПоля]);
КонецЦикла;
Для Каждого ИмяПоля Из СтруктураЗапроса.ИменаПолейДляСравненияНаПодобие Цикл
Данные1.Вставить(ИмяПоля, Дубль.Поля1[ИмяПоля]);
Данные2.Вставить(ИмяПоля, Дубль.Поля2[ИмяПоля]);
КонецЦикла;
ЗарегистрироватьДубль(КоллекцияДублей, Данные1, Данные2, СтруктураЗапроса);
КонецЦикла;
КонецПроцедуры
Процедура ДобавитьСтрокуКандидатов(КоллекцияДублей, ТаблицаКандидатов, Знач ДанныеОсновногоЭлемента,
Знач ДанныеКандидата, Знач СтруктураЗапроса)
Если КоллекцияДублей.НезначимыеДубли[ДанныеОсновногоЭлемента.Ссылка] <> Неопределено
Или КоллекцияДублей.НезначимыеДубли[ДанныеКандидата.Ссылка] <> Неопределено Тогда
Возврат;
КонецЕсли;
Строка = ТаблицаКандидатов.Добавить();
Строка.ЭтоДубли = Ложь;
Строка.Ссылка1 = ДанныеОсновногоЭлемента.Ссылка;
Строка.Ссылка2 = ДанныеКандидата.Ссылка;
Строка.Поля1 = Новый Структура("Код, Наименование, ПометкаУдаления",
ДанныеОсновногоЭлемента.Код, ДанныеОсновногоЭлемента.Наименование, ДанныеОсновногоЭлемента.ПометкаУдаления);
Строка.Поля2 = Новый Структура("Код, Наименование, ПометкаУдаления",
ДанныеКандидата.Код, ДанныеКандидата.Наименование, ДанныеКандидата.ПометкаУдаления);
Для Каждого ИмяПоля Из СтруктураЗапроса.ИменаПолейДляСравненияНаРавенство Цикл
Строка.Поля1.Вставить(ИмяПоля, ДанныеОсновногоЭлемента[ИмяПоля]);
Строка.Поля2.Вставить(ИмяПоля, ДанныеКандидата[ИмяПоля]);
КонецЦикла;
Для Каждого ИмяПоля Из СтруктураЗапроса.ИменаПолейДляСравненияНаПодобие Цикл
Строка.Поля1.Вставить(ИмяПоля, ДанныеОсновногоЭлемента[ИмяПоля]);
Строка.Поля2.Вставить(ИмяПоля, ДанныеКандидата[ИмяПоля]);
КонецЦикла;
Для Каждого КлючЗначение Из СтруктураЗапроса.РасшифровкаДополнительныхПолей Цикл
ИмяКолонки = КлючЗначение.Значение;
ИмяПоля = КлючЗначение.Ключ;
Строка.Поля1.Вставить(ИмяКолонки, ДанныеОсновногоЭлемента[ИмяПоля]);
Строка.Поля2.Вставить(ИмяКолонки, ДанныеКандидата[ИмяПоля]);
КонецЦикла;
КонецПроцедуры
Процедура ЗарегистрироватьДубль(КоллекцияДублей, Знач Элемент1, Знач Элемент2, Знач СтруктураЗапроса)
ТаблицаДублей = КоллекцияДублей.ТаблицаДублей;
НезначимыеДубли = КоллекцияДублей.НезначимыеДубли;
СтрокаДублей1 = ТаблицаДублей.Найти(Элемент1.Ссылка, "Ссылка");
СтрокаДублей2 = ТаблицаДублей.Найти(Элемент2.Ссылка, "Ссылка");
ЕстьНезначимыйДубль1 = КоллекцияДублей.НезначимыеДубли[Элемент1.Ссылка] <> Неопределено;
ЕстьНезначимыйДубль2 = КоллекцияДублей.НезначимыеДубли[Элемент2.Ссылка] <> Неопределено;
Дубль1Зарегистрирован = (СтрокаДублей1 <> Неопределено) Или ЕстьНезначимыйДубль1;
Дубль2Зарегистрирован = (СтрокаДублей2 <> Неопределено) Или ЕстьНезначимыйДубль2;
Если Дубль1Зарегистрирован И Дубль2Зарегистрирован
Или ЕстьНезначимыйДубль1 Или ЕстьНезначимыйДубль2 Тогда
Возврат;
КонецЕсли;
Если Дубль1Зарегистрирован Тогда
СсылкаГруппыДублей = ?(ЗначениеЗаполнено(СтрокаДублей1.Родитель), СтрокаДублей1.Родитель, СтрокаДублей1.Ссылка);
ИначеЕсли Дубль2Зарегистрирован Тогда
СсылкаГруппыДублей = ?(ЗначениеЗаполнено(СтрокаДублей2.Родитель), СтрокаДублей2.Родитель, СтрокаДублей2.Ссылка);
Иначе
ГруппаДублей = ТаблицаДублей.Добавить();
ГруппаДублей.Ссылка = Элемент1.Ссылка;
СсылкаГруппыДублей = ГруппаДублей.Ссылка;
КонецЕсли;
СписокСвойств = "Ссылка,Код,Наименование,ПометкаУдаления,"
+ СтрСоединить(СтруктураЗапроса.ИменаПолейДляСравненияНаРавенство, ",") + ","
+ СтрСоединить(СтруктураЗапроса.ИменаПолейДляСравненияНаПодобие, ",");
Если Не Дубль1Зарегистрирован Тогда
СведенияОДубле = ТаблицаДублей.Добавить();
ЗаполнитьЗначенияСвойств(СведенияОДубле, Элемент1, СписокСвойств);
СведенияОДубле.Родитель = СсылкаГруппыДублей;
Если СведенияОДубле.ПометкаУдаления Тогда
КоллекцияДублей.ДублиКПроверке.Добавить(СведенияОДубле.Ссылка);
КонецЕсли;
КонецЕсли;
Если Не Дубль2Зарегистрирован Тогда
СведенияОДубле = ТаблицаДублей.Добавить();
ЗаполнитьЗначенияСвойств(СведенияОДубле, Элемент2, СписокСвойств);
СведенияОДубле.Родитель = СсылкаГруппыДублей;
Если СведенияОДубле.ПометкаУдаления Тогда
КоллекцияДублей.ДублиКПроверке.Добавить(СведенияОДубле.Ссылка);
КонецЕсли;
КонецЕсли;
Если КоллекцияДублей.ДублиКПроверке.Количество() >= КоллекцияДублей.КоличествоЭлементовДляСравнения Тогда
УдалитьНезначимыеДубли(КоллекцияДублей);
КонецЕсли;
КонецПроцедуры
#Область Прочие
Функция ХарактеристикиОбъектаМетаданных(ОбъектМетаданных)
Результат = Новый Структура;
Результат.Вставить("ДлинаКода", 0);
Результат.Вставить("ДлинаНомера", 0);
Результат.Вставить("ДлинаНаименования", 0);
Результат.Вставить("Иерархический", Ложь);
Результат.Вставить("ВидИерархии", Неопределено);
ЗаполнитьЗначенияСвойств(Результат, ОбъектМетаданных);
Результат.Вставить("ЕстьНаименование", Результат.ДлинаНаименования > 0);
Результат.Вставить("ЕстьКод", Результат.ДлинаКода > 0);
Результат.Вставить("ЕстьНомер", Результат.ДлинаНомера > 0);
Результат.Вставить("ПолноеИмяОбъектаМетаданных", ОбъектМетаданных.ПолноеИмя());
Результат.Вставить("ОбъектМетаданных", ОбъектМетаданных);
Возврат Результат;
КонецФункции
Функция ТекстЗапросаПоискаДублей(ПараметрыПоиска, Характеристики, ИменаДополнительныхПолей)
ИменаПолейДляСравненияНаРавенство = Новый Массив;
ИменаПолейДляСравненияНаПодобие = Новый Массив;
Для Каждого Строка Из ПараметрыПоиска.ПравилаПоиска Цикл
Если Строка.Правило = "Равно" Тогда
ИменаПолейДляСравненияНаРавенство.Добавить(Строка.Реквизит);
ИначеЕсли Строка.Правило = "Подобно" Тогда
ИменаПолейДляСравненияНаПодобие.Добавить(Строка.Реквизит);
КонецЕсли
КонецЦикла;
ИменаПолейВЗапросе = ДоступныеРеквизитыОтбора(Характеристики.ОбъектМетаданных);
Если Не Характеристики.ЕстьКод Тогда
Если Характеристики.ЕстьНомер Тогда
ИменаПолейВЗапросе = ИменаПолейВЗапросе + ", Номер КАК Код";
Иначе
ИменаПолейВЗапросе = ИменаПолейВЗапросе + ", НЕОПРЕДЕЛЕНО КАК Код";
КонецЕсли;
КонецЕсли;
Если Не Характеристики.ЕстьНаименование Тогда
ИменаПолейВЗапросе = ИменаПолейВЗапросе + ", Ссылка КАК Наименование";
КонецЕсли;
ИменаПолейВВыборе = ОбщегоНазначения.СкопироватьРекурсивно(ИменаПолейДляСравненияНаРавенство);
ОбщегоНазначенияКлиентСервер.ДополнитьМассив(ИменаПолейВВыборе, ИменаПолейДляСравненияНаПодобие);
РасшифровкаДополнительныхПолей = Новый Соответствие;
ПорядковыйНомер = 0;
Для Каждого ПолеТаблицы Из Новый Структура(ИменаДополнительныхПолей) Цикл
ИмяПоля = ПолеТаблицы.Ключ;
Псевдоним = "Доп" + Формат(ПорядковыйНомер, "ЧН=; ЧГ=") + "_" + ИмяПоля;
РасшифровкаДополнительныхПолей.Вставить(Псевдоним, ИмяПоля);
ИменаПолейВЗапросе = ИменаПолейВЗапросе + "," + ИмяПоля + " КАК " + Псевдоним;
ИменаПолейВВыборе.Добавить(Псевдоним);
ПорядковыйНомер = ПорядковыйНомер + 1;
КонецЦикла;
ТекстЗапроса = "ВЫБРАТЬ РАЗРЕШЕННЫЕ * ИЗ #Таблица";
ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "*", ИменаПолейВЗапросе);
ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "#Таблица", Характеристики.ПолноеИмяОбъектаМетаданных);
Результат = Новый Структура;
Результат.Вставить("ТекстЗапроса", ТекстЗапроса);
Результат.Вставить("РасшифровкаДополнительныхПолей", РасшифровкаДополнительныхПолей);
Результат.Вставить("ИменаПолейДляСравненияНаРавенство", ИменаПолейДляСравненияНаРавенство);
Результат.Вставить("ИменаПолейДляСравненияНаПодобие", ИменаПолейДляСравненияНаПодобие);
Результат.Вставить("ИменаПолейВВыборе", ИменаПолейВВыборе);
Возврат Результат;
КонецФункции
Функция СхемаКомпоновкиДанныхПоискаДублей(ПараметрыПоиска, Характеристики, СтруктураЗапроса, ЭталонныйОбъект)
СхемаКД = Новый СхемаКомпоновкиДанных;
ИсточникДанныхСхемыКД = СхемаКД.ИсточникиДанных.Добавить();
ИсточникДанныхСхемыКД.Имя = "ИсточникДанных1";
ИсточникДанныхСхемыКД.ТипИсточникаДанных = "Local";
НаборДанных = СхемаКД.НаборыДанных.Добавить(Тип("НаборДанныхЗапросСхемыКомпоновкиДанных"));
НаборДанных.Имя = "НаборДанных1";
НаборДанных.ИсточникДанных = "ИсточникДанных1";
НаборДанных.Запрос = СтруктураЗапроса.ТекстЗапроса;
НаборДанных.АвтоЗаполнениеДоступныхПолей = Истина;
КомпоновщикНастроекКД = Новый КомпоновщикНастроекКомпоновкиДанных;
КомпоновщикНастроекКД.Инициализировать(Новый ИсточникДоступныхНастроекКомпоновкиДанных(СхемаКД));
КомпоновщикНастроекКД.ЗагрузитьНастройки(ПараметрыПоиска.КомпоновщикПредварительногоОтбора.Настройки);
НастройкиКД = КомпоновщикНастроекКД.Настройки;
НастройкиКД.Выбор.Элементы.Очистить();
Для Каждого ИмяПоля Из СтруктураЗапроса.ИменаПолейВВыборе Цикл
ПолеКД = Новый ПолеКомпоновкиДанных(СокрЛП(ИмяПоля));
ДоступноеПолеКД = НастройкиКД.ДоступныеПоляВыбора.НайтиПоле(ПолеКД);
Если ДоступноеПолеКД = Неопределено Тогда
ЗаписьЖурналаРегистрации(ПоискИУдалениеДублей.НаименованиеПодсистемы(Ложь),
УровеньЖурналаРегистрации.Предупреждение, Характеристики.ОбъектМетаданных, ЭталонныйОбъект,
СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Поле ""%1"" не существует.'"), Строка(ПолеКД)));
Продолжить;
КонецЕсли;
ВыбранноеПолеКД = НастройкиКД.Выбор.Элементы.Добавить(Тип("ВыбранноеПолеКомпоновкиДанных"));
ВыбранноеПолеКД.Поле = ПолеКД;
КонецЦикла;
ВыбранноеПолеКД = НастройкиКД.Выбор.Элементы.Добавить(Тип("ВыбранноеПолеКомпоновкиДанных"));
ВыбранноеПолеКД.Поле = Новый ПолеКомпоновкиДанных("Ссылка");
ВыбранноеПолеКД = НастройкиКД.Выбор.Элементы.Добавить(Тип("ВыбранноеПолеКомпоновкиДанных"));
ВыбранноеПолеКД.Поле = Новый ПолеКомпоновкиДанных("Код");
ВыбранноеПолеКД = НастройкиКД.Выбор.Элементы.Добавить(Тип("ВыбранноеПолеКомпоновкиДанных"));
ВыбранноеПолеКД.Поле = Новый ПолеКомпоновкиДанных("Наименование");
ВыбранноеПолеКД = НастройкиКД.Выбор.Элементы.Добавить(Тип("ВыбранноеПолеКомпоновкиДанных"));
ВыбранноеПолеКД.Поле = Новый ПолеКомпоновкиДанных("ПометкаУдаления");
Если Характеристики.Иерархический
И Характеристики.ВидИерархии = Метаданные.СвойстваОбъектов.ВидИерархии.ИерархияГруппИЭлементов Тогда
ВыбранноеПолеКД = НастройкиКД.Выбор.Элементы.Добавить(Тип("ВыбранноеПолеКомпоновкиДанных"));
ВыбранноеПолеКД.Поле = Новый ПолеКомпоновкиДанных("ЭтоГруппа");
ВыбранноеПолеКД = НастройкиКД.Выбор.Элементы.Добавить(Тип("ВыбранноеПолеКомпоновкиДанных"));
ВыбранноеПолеКД.Поле = Новый ПолеКомпоновкиДанных("Родитель");
КонецЕсли;
НастройкиКД.Порядок.Элементы.Очистить();
ЭлементПорядкаКД = НастройкиКД.Порядок.Элементы.Добавить(Тип("ЭлементПорядкаКомпоновкиДанных"));
ЭлементПорядкаКД.Поле = Новый ПолеКомпоновкиДанных("Ссылка");
Если Характеристики.ОбъектМетаданных = Метаданные.Справочники.Пользователи Тогда
ЭлементОтбораКД = НастройкиКД.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
ЭлементОтбораКД.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Служебный");
ЭлементОтбораКД.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
ЭлементОтбораКД.ПравоеЗначение = Ложь;
КонецЕсли;
НастройкиКД.Структура.Очистить();
ГруппировкаКД = НастройкиКД.Структура.Добавить(Тип("ГруппировкаКомпоновкиДанных"));
ГруппировкаКД.Выбор.Элементы.Добавить(Тип("АвтоВыбранноеПолеКомпоновкиДанных"));
ГруппировкаКД.Порядок.Элементы.Добавить(Тип("АвтоЭлементПорядкаКомпоновкиДанных"));
Если ЭталонныйОбъект = Неопределено Тогда
ВыборкаЭталонныхОбъектов = ИнициализироватьВыборкуКД(СхемаКД, КомпоновщикНастроекКД.ПолучитьНастройки());
Иначе
ТаблицаЗначений = ОбъектВТаблицуЗначений(ЭталонныйОбъект, СтруктураЗапроса.РасшифровкаДополнительныхПолей);
Если Не Характеристики.ЕстьКод И Не Характеристики.ЕстьНомер Тогда
ТаблицаЗначений.Колонки.Добавить("Код", Новый ОписаниеТипов("Неопределено"));
КонецЕсли;
ВыборкаЭталонныхОбъектов = ИнициализироватьВыборкуТЗ(ТаблицаЗначений);
КонецЕсли;
ОтборыКандидатов = Новый Соответствие;
Для Каждого ИмяПоля Из СтруктураЗапроса.ИменаПолейДляСравненияНаРавенство Цикл
ИмяПоля = СокрЛП(ИмяПоля);
ЭлементОтбораКД = НастройкиКД.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
ЭлементОтбораКД.ЛевоеЗначение = Новый ПолеКомпоновкиДанных(ИмяПоля);
ЭлементОтбораКД.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
ОтборыКандидатов.Вставить(ИмяПоля, ЭлементОтбораКД);
КонецЦикла;
ЭлементОтбораКД = НастройкиКД.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
ЭлементОтбораКД.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Ссылка");
ЭлементОтбораКД.ВидСравнения = ?(ЭталонныйОбъект = Неопределено, ВидСравненияКомпоновкиДанных.Больше,
ВидСравненияКомпоновкиДанных.НеРавно);
ОтборыКандидатов.Вставить("Ссылка", ЭлементОтбораКД);
Если Характеристики.Иерархический
И Характеристики.ВидИерархии = Метаданные.СвойстваОбъектов.ВидИерархии.ИерархияГруппИЭлементов Тогда
ЭлементОтбораКД = НастройкиКД.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
ЭлементОтбораКД.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("ЭтоГруппа");
ЭлементОтбораКД.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
ОтборыКандидатов.Вставить("ЭтоГруппа", ЭлементОтбораКД);
ГруппаИЛИ = НастройкиКД.Отбор.Элементы.Добавить(Тип("ГруппаЭлементовОтбораКомпоновкиДанных"));
ГруппаИЛИ.ТипГруппы = ТипГруппыЭлементовОтбораКомпоновкиДанных.ГруппаИли;
ГруппаИ = ГруппаИЛИ.Элементы.Добавить(Тип("ГруппаЭлементовОтбораКомпоновкиДанных"));
ГруппаИ.ТипГруппы = ТипГруппыЭлементовОтбораКомпоновкиДанных.ГруппаИ;
ЭлементОтбораКД = ГруппаИ.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
ЭлементОтбораКД.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("ЭтоГруппа");
ЭлементОтбораКД.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
ЭлементОтбораКД.ПравоеЗначение = Ложь;
ГруппаИ = ГруппаИЛИ.Элементы.Добавить(Тип("ГруппаЭлементовОтбораКомпоновкиДанных"));
ГруппаИ.ТипГруппы = ТипГруппыЭлементовОтбораКомпоновкиДанных.ГруппаИ;
ЭлементОтбораКД = ГруппаИ.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
ЭлементОтбораКД.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("ЭтоГруппа");
ЭлементОтбораКД.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
ЭлементОтбораКД.ПравоеЗначение = Истина;
ЭлементОтбораКД = ГруппаИ.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
ЭлементОтбораКД.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Родитель");
ЭлементОтбораКД.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
ОтборыКандидатов.Вставить("Родитель", ЭлементОтбораКД);
КонецЕсли;
Результат = Новый Структура;
Результат.Вставить("СхемаКД", СхемаКД);
Результат.Вставить("НастройкиКД", НастройкиКД);
Результат.Вставить("ВыборкаЭталонныхОбъектов", ВыборкаЭталонныхОбъектов);
Результат.Вставить("ОтборыКандидатов", ОтборыКандидатов);
Возврат Результат;
КонецФункции
Функция ДоступныеРеквизитыОтбора(ОбъектМетаданных)
МассивРеквизитов = Новый Массив;
Для Каждого РеквизитМетаданные Из ОбъектМетаданных.СтандартныеРеквизиты Цикл
Если РеквизитМетаданные.Тип.СодержитТип(Тип("ХранилищеЗначения")) Тогда
Продолжить;
КонецЕсли;
МассивРеквизитов.Добавить(РеквизитМетаданные.Имя);
КонецЦикла;
Для Каждого РеквизитМетаданные Из ОбъектМетаданных.Реквизиты Цикл
Если РеквизитМетаданные.Тип.СодержитТип(Тип("ХранилищеЗначения")) Тогда
Продолжить;
КонецЕсли;
МассивРеквизитов.Добавить(РеквизитМетаданные.Имя);
КонецЦикла;
Возврат СтрСоединить(МассивРеквизитов, ",");
КонецФункции
Функция ИнициализироватьВыборкуКД(СхемаКД, НастройкиКД)
Выборка = Новый Структура("Таблица, ТекущийЭлемент, Индекс, ВГраница, ПроцессорКД, ПроцессорВыводаКД");
КомпоновщикМакетаКД = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКД = КомпоновщикМакетаКД.Выполнить(СхемаКД, НастройкиКД, , , Тип("ГенераторМакетаКомпоновкиДанныхДляКоллекцииЗначений"));
Выборка.ПроцессорКД = Новый ПроцессорКомпоновкиДанных;
Выборка.ПроцессорКД.Инициализировать(МакетКД);
Выборка.Таблица = Новый ТаблицаЗначений;
Выборка.Индекс = -1;
Выборка.ВГраница = -100;
Выборка.ПроцессорВыводаКД = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВКоллекциюЗначений;
Выборка.ПроцессорВыводаКД.УстановитьОбъект(Выборка.Таблица);
Возврат Выборка;
КонецФункции
Функция ИнициализироватьВыборкуТЗ(ТаблицаЗначений)
Выборка = Новый Структура("Таблица, ТекущийЭлемент, Индекс, ВГраница, ПроцессорКД, ПроцессорВыводаКД");
Выборка.Таблица = ТаблицаЗначений;
Выборка.Индекс = -1;
Выборка.ВГраница = ТаблицаЗначений.Количество() - 1;
Возврат Выборка;
КонецФункции
Функция СледующийЭлементВыборки(Выборка)
Если Выборка.Индекс >= Выборка.ВГраница Тогда
Если Выборка.ПроцессорКД = Неопределено Тогда
Возврат Ложь;
КонецЕсли;
Если Выборка.ВГраница = -100 Тогда
Выборка.ПроцессорВыводаКД.НачатьВывод();
КонецЕсли;
Выборка.Таблица.Очистить();
Выборка.Индекс = -1;
Выборка.ВГраница = -1;
Пока Выборка.ВГраница = -1 Цикл
ЭлементРезультатаКД = Выборка.ПроцессорКД.Следующий();
Если ЭлементРезультатаКД = Неопределено Тогда
Выборка.ПроцессорВыводаКД.ЗакончитьВывод();
Возврат Ложь;
КонецЕсли;
Выборка.ПроцессорВыводаКД.ВывестиЭлемент(ЭлементРезультатаКД);
Выборка.ВГраница = Выборка.Таблица.Количество() - 1;
КонецЦикла;
КонецЕсли;
Выборка.Индекс = Выборка.Индекс + 1;
Выборка.ТекущийЭлемент = Выборка.Таблица[Выборка.Индекс];
Возврат Истина;
КонецФункции
Процедура УдалитьНезначимыеДубли(КоллекцияДублей)
Если НЕ КоллекцияДублей.СкрыватьНезначимыеДубли Тогда
Возврат;
КонецЕсли;
ТаблицаДублей = КоллекцияДублей.ТаблицаДублей;
ДублиКПроверке = КоллекцияДублей.ДублиКПроверке;
Если ТаблицаДублей.Количество() - ДублиКПроверке.Количество() <= КоллекцияДублей.КоличествоЭлементовДляСравнения Тогда
МестаИспользования = ОбщегоНазначения.МестаИспользования(ДублиКПроверке);
МестаИспользования.Индексы.Добавить("Ссылка, ВспомогательныеДанные");
ОтборДублей = Новый Структура("Ссылка", Неопределено);
ОтборМестИспользования = Новый Структура("Ссылка, ВспомогательныеДанные", Неопределено, Ложь);
Для Индекс = 0 По ДублиКПроверке.ВГраница() Цикл
ОтборДублей.Ссылка = ДублиКПроверке[Индекс];
ПроверяемыеДубли = ТаблицаДублей.НайтиСтроки(ОтборДублей);
Для каждого Дубль Из ПроверяемыеДубли Цикл
Если Дубль.Родитель = Неопределено Тогда
Продолжить;
КонецЕсли;
ОтборМестИспользования.Ссылка = Дубль.Ссылка;
МестаИспользованияВнутренний = МестаИспользования.НайтиСтроки(ОтборМестИспользования);
Если МестаИспользованияВнутренний.Количество() = 0 И Дубль.ПометкаУдаления Тогда
КоллекцияДублей.НезначимыеДубли[Дубль.Ссылка] = Истина;
КоллекцияДублей.НезначимыеДубли[Дубль.Родитель] = Истина;
КоллекцияДублей.ОбработанныеГруппы.Вставить(Дубль.Родитель);
ТаблицаДублей.Удалить(Дубль);
КонецЕсли;
КонецЦикла;
КонецЦикла;
КонецЕсли;
ДублиКПроверке.Очистить();
КонецПроцедуры
Процедура УдалитьНезначимыеГруппы(КоллекцияДублей)
ТаблицаДублей = КоллекцияДублей.ТаблицаДублей;
ОтборДублей = Новый Структура("Родитель", Неопределено);
Для каждого ГруппаДублей Из КоллекцияДублей.ОбработанныеГруппы Цикл
ОтборДублей.Родитель = ГруппаДублей.Ключ;
Дубли = ТаблицаДублей.НайтиСтроки(ОтборДублей);
Если Дубли.Количество() = 1 Тогда
ТаблицаДублей.Удалить(Дубли[0]);
КонецЕсли;
Группа = ТаблицаДублей.Найти(ГруппаДублей.Ключ, "Ссылка");
Если Группа <> Неопределено Тогда
ТаблицаДублей.Удалить(Группа);
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Функция ТаблицаДублей(ИменаПолейДляСравненияНаПодобие, ИменаПолейДляСравненияНаРавенство)
ТаблицаДублей = Новый ТаблицаЗначений;
ТаблицаДублей.Колонки.Добавить("Ссылка");
Для Каждого ПолеТаблицы Из ИменаПолейДляСравненияНаРавенство Цикл
Если ТаблицаДублей.Колонки.Найти(ПолеТаблицы) = Неопределено Тогда
ТаблицаДублей.Колонки.Добавить(ПолеТаблицы);
КонецЕсли;
КонецЦикла;
Для Каждого ПолеТаблицы Из ИменаПолейДляСравненияНаПодобие Цикл
Если ТаблицаДублей.Колонки.Найти(ПолеТаблицы) = Неопределено Тогда
ТаблицаДублей.Колонки.Добавить(ПолеТаблицы);
КонецЕсли;
КонецЦикла;
ОбязательныеКолонки = СтрРазделить("Код,Наименование,Родитель,ПометкаУдаления,ЭтоГруппа", ",");
Для Каждого ИмяПоляТаблицы Из ОбязательныеКолонки Цикл
Если ТаблицаДублей.Колонки.Найти(ИмяПоляТаблицы) = Неопределено Тогда
ТаблицаДублей.Колонки.Добавить(ИмяПоляТаблицы);
КонецЕсли;
КонецЦикла;
ТаблицаДублей.Индексы.Добавить("Ссылка");
ТаблицаДублей.Индексы.Добавить("Родитель");
ТаблицаДублей.Индексы.Добавить("Ссылка,Родитель,ЭтоГруппа");
Возврат ТаблицаДублей;
КонецФункции
Функция КоллекцияДублей(Знач ПараметрыПоиска, ИменаПолейДляСравненияНаПодобие, ИменаПолейДляСравненияНаРавенство)
КоллекцияДублей = Новый Структура;
КоллекцияДублей.Вставить("ТаблицаДублей", ТаблицаДублей(ИменаПолейДляСравненияНаПодобие, ИменаПолейДляСравненияНаРавенство));
КоллекцияДублей.Вставить("КоличествоЭлементовДляСравнения",
ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(ПараметрыПоиска, "МаксимальноеЧислоДублей", 0));
КоллекцияДублей.Вставить("ДублиКПроверке", Новый Массив);
КоллекцияДублей.Вставить("СкрыватьНезначимыеДубли", Ложь);
Если ПараметрыПоиска.Свойство("СкрыватьНезначимыеДубли")
И ПараметрыПоиска.СкрыватьНезначимыеДубли = Истина
ИЛИ КоллекцияДублей.КоличествоЭлементовДляСравнения = 0 Тогда
КоллекцияДублей.СкрыватьНезначимыеДубли = Истина;
КонецЕсли;
КоллекцияДублей.Вставить("ОбработанныеГруппы", Новый Соответствие);
КоллекцияДублей.Вставить("НезначимыеДубли", Новый Соответствие);
Возврат КоллекцияДублей;
КонецФункции
Функция ТаблицаКандидатов()
ТаблицаКандидатов = Новый ТаблицаЗначений;
КолонкиКандидатов = ТаблицаКандидатов.Колонки;
КолонкиКандидатов.Добавить("Ссылка1");
КолонкиКандидатов.Добавить("Поля1");
КолонкиКандидатов.Добавить("Ссылка2");
КолонкиКандидатов.Добавить("Поля2");
КолонкиКандидатов.Добавить("ЭтоДубли", Новый ОписаниеТипов("Булево"));
ТаблицаКандидатов.Индексы.Добавить("ЭтоДубли");
Возврат ТаблицаКандидатов;
КонецФункции
#КонецОбласти
#КонецОбласти
#Иначе
ВызватьИсключение НСтр("ru = 'Недопустимый вызов объекта на клиенте.'");
#КонецЕсли