Содержит ссылки на данные, представленные в базе данных. Объект позволяет обойти данные, попавшие в выборку и прочитать их.
Полное описание, параметры и ограничения
ВыборкаДанных (DataSelection)
ВыборкаДанных (DataSelection)
Доступен, начиная с версии 8.0.
Методы:
Получить (Get)
Сбросить (Reset)
Следующий (Next)
Описание:
Содержит ссылки на данные, представленные в базе данных. Объект позволяет обойти данные, попавшие в выборку и прочитать их.
Доступность:
Сервер, толстый клиент, внешнее соединение, мобильное приложение (сервер), мобильный автономный сервер.
См. также:
ПланыОбменаМенеджер, метод ВыбратьИзменения
Использование в версии:
Доступен, начиная с версии 8.0.
Методическая информация
Практические примеры
Своя двухузловая РИБ: регистрация → пакет → actual чтение → ответ → безопасная очистка
Отдельная учебная РИБ A/B с одной собственной строкой и только собственными ссылками. Полный XML-протокол использует настоящие factory writer/reader, нативный начальный образ B и различает регистрацию, отправку, импорт и реально принятый ответ. Код только authored/static, не выполнялся в 1С.
Где и как запускать
Полный ordinary thick модуль собственной формы УчебнаяРИБ85, exact platform8.5.1.1343. Manual два файловых own A/B по указанным UUID путям; actual B только native initial imageA. Никаких actual действий агентом.
Подготовка
НИЧЕГО из этого урока не выполняйте в рабочей базе. Вручную создайте новый каталог C:\1C85_OwnExchangeLab\c88b7ab1-1d4c-4893-b6be-1f16f4b85293 и отдельную совершенно новую пустую файловую базу A внутри него. Каталог B должен отсутствовать полностью. Если UUID-папка уже содержит чужие данные или B существует — выберите другой учебный стенд и адаптируйте все связанные guards вместе; не удаляйте/не переиспользуйте содержимое.
В A, только платформа8.5.1.1343, Имя конфигурации=УчебнаяРИБ85; основное приложение Обычное. Ровно один неиерархический каталог МояСтрока85: Код Строка8, уникальность включена, автоматическая нумерация выключена, Наименование Строка40; собственные реквизиты Количество85 Число(9,0), Метка85 Строка36. Нет иных каталогов, документов, регистров, подписок, фоновых/регламентных заданий, обменов, расширений и рабочих modules.
Ровно один ПланОбмена МояРИБ85: РаспределеннаяИнформационнаяБаза=Да, Код Строка1, Наименование Строка40. В составе только каталог МояСтрока85, его АвтоРегистрация=Запретить. Не включайте узлы плана, константы или другие объекты в состав. После обновления только собственного A откройте его в обычном клиенте: Операции → Планы обмена → МояРИБ85. У своего предопределённого ЭтотУзел задайте Код A, Наименование Мой A c88b7ab1. В том же списке создайте второй actual узел Код B, Наименование Мой B c88b7ab1. Иные узлы/пометки удаления отсутствуют. Не присваивайте выдуманные UUID узлам.
Создайте обработку УчебнаяРИБ85 и Обычную Основную форму. Реквизиты: Исходящее85, Входящее85 и Состояние85 Строка неограниченной длины. Покажите первые два как большие многострочные поля: Исходящее85 только просмотр, Входящее85 принимает лишь XML, вручную скопированный из своей другой формы. Состояние85 только просмотр. Код целиком в модуле этой ordinary формы; ПриОткрытии() назначьте одноимённому событию.
Добавьте кнопки с одноимёнными действиями: СоздатьТолькоСвойНачальныйB85, ЗарегистрироватьТолькоСвоюСтроку85, ПрерватьСвойWriter85, ОтправитьСвоюСтрокуA85, ПосмотретьИПрерватьСвойReader85, ПринятьСвойПакет85, ОтветитьТолькоИзСвоегоB85, ОчиститьТолькоПодтвержденнуюСвоюСтроку85, ОтсоединитьИВосстановитьТолькоСвойChildB85. Обновите только свой A; открывайте thick ordinary клиентом.
Пока каталог МояСтрока85 пуст: A→СоздатьТолькоСвойНачальныйB85. Это настоящий native СоздатьНачальныйОбраз для своего actual nodeB и только несуществующего собственного UUID-dir B. Метод создаёт базу и удаляет регистрации элементов данных/конфигурации данного узла — не запускайте после рабочих регистраций. Агент НЕ выполнял это создание, файловые вызовы или копирование базы.
Зарегистрируйте B в своём launcher по ровно C:\1C85_OwnExchangeLab\c88b7ab1-1d4c-4893-b6be-1f16f4b85293\B, без серверного соединения. A/B пути укажите точно, без завершающего слеша, относительных путей и дополнительных частей File: guard требует точное буквальное имя вместе с Файл.ПолноеИмя; он не обещает разрешать symlinks или альтернативные написания. Откройте тот же код формы из реального образа B: native ЭтотУзел обязан стать B, native ГлавныйУзел=A. Не создавайте независимую B вручную — её actual ссылки/metadata происходят только из начального образа. Сначала обе базы имеют пустой каталог, sent/received counters0.
После создания B вручную только в A через Операции → Справочники → МояСтрока85 создайте единственную свою запись: Код Э85, Наименование Мой обмен85, Количество85=7, Метка85=c88b7ab1-1d4c-4893-b6be-1f16f4b85293. В B она появится только из real импорта. Авторегистрация запрещена, поэтому явную регистрацию выполняет own команда. До завершения упражнения строку, CF, extension, nodes, counters не редактируйте; A-форма остаётся открытой до собственного ответа B.
Два собственных клиента, по одному сеансу на каждую базу; никаких других пользователей, фоновых задач или параллельного обмена. Не вставляйте внешние/чужие XML. Сообщения передаются вручную между строками своих двух форм, не через сеть/файлы/production endpoints.
#Если ТолстыйКлиентОбычноеПриложение Тогда
Перем МояСторона85, МойЭтотУзел85, МойДругойУзел85, МояСсылка85, МойНомерОтправки85, МояВерсияОтправки85, МойПодтвержденныйНомер85;
Процедура ПриОткрытии()
ПроверитьСвойПустойСтенд();
ОпределитьСвоиУзлы85();
МойНомерОтправки85 = 0;
МояВерсияОтправки85 = "";
МойПодтвержденныйНомер85 = 0;
Исходящее85 = "";
Входящее85 = "";
Состояние85 = "Собственный узел " + МояСторона85 + ". Обмен только между собственными A/B; сообщения в строках формы.";
КонецПроцедуры
Процедура ОпределитьСвоиУзлы85()
План = Метаданные.ПланыОбмена.Найти("МояРИБ85");
Каталог = Метаданные.Справочники.Найти("МояСтрока85");
Если План = Неопределено Или Каталог = Неопределено Тогда
ВызватьИсключение "Нужны только собственные МояРИБ85 и МояСтрока85";
КонецЕсли;
Если Не План.РаспределеннаяИнформационнаяБаза Или План.Состав.Количество() <> 1 Или Не План.Состав.Содержит(Каталог) Тогда
ВызватьИсключение "Нужна настоящая РИБ, в составе только собственный каталог";
КонецЕсли;
Если План.Состав.Найти(Каталог).АвтоРегистрация <> АвтоРегистрацияИзменений.Запретить Тогда
ВызватьИсключение "Свой каталог должен иметь запрещённую авторегистрацию для явного учебного контроля";
КонецЕсли;
Проверка = Новый Запрос("ВЫБРАТЬ Ссылка, Код, Наименование, ПометкаУдаления ИЗ ПланОбмена.МояРИБ85");
Узлы = Проверка.Выполнить().Выгрузить();
Если Узлы.Количество() <> 2 Тогда
ВызватьИсключение "Нужны ровно два реально подготовленных собственных узла A/B";
КонецЕсли;
А = Узлы.Найти("A", "Код");
Б = Узлы.Найти("B", "Код");
Если А = Неопределено Или Б = Неопределено Тогда
ВызватьИсключение "Нет точных собственных узлов A/B";
КонецЕсли;
Если А.Наименование <> "Мой A c88b7ab1" Или Б.Наименование <> "Мой B c88b7ab1" Или А.ПометкаУдаления Или Б.ПометкаУдаления Тогда
ВызватьИсключение "Имена или состояние собственных узлов не совпали";
КонецЕсли;
МойЭтотУзел85 = ПланыОбмена.МояРИБ85.ЭтотУзел();
Если МойЭтотУзел85 = А.Ссылка Тогда
МояСторона85 = "A";
МойДругойУзел85 = Б.Ссылка;
ИначеЕсли МойЭтотУзел85 = Б.Ссылка Тогда
МояСторона85 = "B";
МойДругойУзел85 = А.Ссылка;
Иначе
ВызватьИсключение "ЭтотУзел не совпал с одной из двух actual собственных ссылок";
КонецЕсли;
Если МойДругойУзел85 = МойЭтотУзел85 Или Не ЗначениеЗаполнено(МойДругойУзел85) Тогда
ВызватьИсключение "Получатель должен быть реальным другим собственным узлом";
КонецЕсли;
ПроверитьСвойПуть85(МояСторона85);
Главный = ПланыОбмена.ГлавныйУзел();
Если (МояСторона85 = "A" И Главный <> Неопределено) Или (МояСторона85 = "B" И Главный <> МойДругойУзел85) Тогда
ВызватьИсключение "A должен быть actual корнем, B настоящим дочерним образом A";
КонецЕсли;
КонецПроцедуры
Процедура ПроверитьСвойПуть85(Сторона)
Части = СтрРазделить(СтрокаСоединенияИнформационнойБазы(), ";");
Если Части.Количество() <> 1 И Части.Количество() <> 2 Тогда
ВызватьИсключение "Разрешён только единственный File без дополнительных параметров";
КонецЕсли;
Если Части.Количество() = 2 И СокрЛП(Части[1]) <> "" Тогда
ВызватьИсключение "После собственного File допускается лишь пустой завершающий разделитель";
КонецЕсли;
Параметр = СокрЛП(Части[0]);
Если НРег(Лев(Параметр, 5)) <> "file=" Тогда
ВызватьИсключение "Серверная или чужая строка соединения запрещена";
КонецЕсли;
Путь = Сред(Параметр, 6);
Если Лев(Путь, 1) = """" И Прав(Путь, 1) = """" Тогда
Путь = Сред(Путь, 2, СтрДлина(Путь) - 2);
КонецЕсли;
ФайлБазы = Новый Файл(Путь);
Ожидание = "C:\1C85_OwnExchangeLab\c88b7ab1-1d4c-4893-b6be-1f16f4b85293\" + Сторона;
Если НРег(Путь) <> НРег(Ожидание) Или НРег(ФайлБазы.ПолноеИмя) <> НРег(Ожидание) Тогда
ВызватьИсключение "Разрешены только точные собственные UUID-каталоги A/B";
КонецЕсли;
КонецПроцедуры
Процедура ПроверитьСвоюСторону85(Сторона)
ПроверитьСвойПустойСтенд();
ОпределитьСвоиУзлы85();
Если МояСторона85 <> Сторона Тогда
ВызватьИсключение "Команда предназначена только своей стороне " + Сторона;
КонецЕсли;
КонецПроцедуры
Процедура СоздатьТолькоСвойНачальныйB85(Кнопка)
ПроверитьСвоюСторону85("A");
Каталог = Новый Запрос("ВЫБРАТЬ Ссылка ИЗ Справочник.МояСтрока85");
Если Каталог.Выполнить().Выгрузить().Количество() <> 0 Тогда
ВызватьИсключение "Начальный образ создаётся до единственной своей строки, каталог обязан быть пустым";
КонецЕсли;
Цель = "C:\1C85_OwnExchangeLab\c88b7ab1-1d4c-4893-b6be-1f16f4b85293\B";
ФайлЦели = Новый Файл(Цель);
Если НРег(ФайлЦели.ПолноеИмя) <> НРег(Цель) Или ФайлЦели.Существует() Тогда
ВызватьИсключение "Только точный собственный ещё не существующий B; ничего не заменяем и не очищаем";
КонецЕсли;
Если МойДругойУзел85.Код <> "B" Или МойДругойУзел85.ЭтотУзел Или ПланыОбмена.ГлавныйУзел() <> Неопределено Тогда
ВызватьИсключение "Изображение разрешено только своему childB из настоящего корня A";
КонецЕсли;
ПланыОбмена.СоздатьНачальныйОбраз(МойДругойУзел85, "File=""" + Цель + """");
Если Не ФайлЦели.Существует() Тогда
ВызватьИсключение "Native создание образа не подтверждено существованием собственного B; дальнейший обмен запрещён";
КонецЕсли;
Состояние85 = "Создан только собственный начальный B. Native метод удаляет регистрации этого узла при создании образа; это не резервная копия. Откройте именно B, затем вручную подготовьте одну строку в A.";
КонецПроцедуры
Функция ПрочитатьСвоюСтроку85()
Запрос = Новый Запрос("ВЫБРАТЬ Ссылка, Код, Наименование, Количество85, Метка85, ПометкаУдаления ИЗ Справочник.МояСтрока85");
Строки = Запрос.Выполнить().Выгрузить();
Если Строки.Количество() <> 1 Тогда
ВызватьИсключение "Разрешена ровно одна actual собственная строка";
КонецЕсли;
СтрокаДанных = Строки[0];
Если СтрокаДанных.Код <> "Э85" Или СтрокаДанных.Наименование <> "Мой обмен85" Или СтрокаДанных.Количество85 <> 7
Или СтрокаДанных.Метка85 <> "c88b7ab1-1d4c-4893-b6be-1f16f4b85293" Или СтрокаДанных.ПометкаУдаления Тогда
ВызватьИсключение "Own marker/code/name/value не совпали; чужие или изменённые строки запрещены";
КонецЕсли;
Возврат СтрокаДанных.Ссылка;
КонецФункции
Процедура ЗарегистрироватьТолькоСвоюСтроку85(Кнопка)
ПроверитьСвоюСторону85("A");
МояСсылка85 = ПрочитатьСвоюСтроку85();
Если ПланыОбмена.ИзменениеЗарегистрировано(МойДругойУзел85, МояСсылка85) Тогда
ВызватьИсключение "Для отдельного опыта нужна ещё не зарегистрированная own строка; ничего не сбрасываем автоматически";
КонецЕсли;
ПланыОбмена.ЗарегистрироватьИзменения(МойДругойУзел85, МояСсылка85);
Если Не ПланыОбмена.ИзменениеЗарегистрировано(МойДругойУзел85, МояСсылка85) Тогда
ВызватьИсключение "Actual регистрация своей строки не подтверждена readback";
КонецЕсли;
Состояние85 = "Зарегистрирована только одна own ссылка для своего B. Это ещё не отправка, не импорт и не ack.";
КонецПроцедуры
Процедура ПрерватьСвойWriter85(Кнопка)
ПроверитьСвойПустойСтенд();
ОпределитьСвоиУзлы85();
Было = МойДругойУзел85.ПолучитьОбъект().НомерОтправленного;
Поток = Новый ЗаписьXML;
Поток.УстановитьСтроку();
Writer = ПланыОбмена.СоздатьЗаписьСообщения();
Попытка
Writer.НачатьЗапись(Поток, МойДругойУзел85);
ПроверитьСвойАктивныйWriter85(Writer, Поток);
Если Writer.НомерСообщения <> Было + 1 Тогда
ВызватьИсключение "Начатый own writer должен предложить следующий номер";
КонецЕсли;
Writer.ПрерватьЗапись();
Исключение
ПрерватьИЗакрытьСвойWriterПослеОшибки85(Writer, Поток, ОписаниеОшибки());
КонецПопытки;
Поток.Закрыть();
ПроверитьСвойНеактивныйWriter85(Writer);
Если МойДругойУзел85.ПолучитьОбъект().НомерОтправленного <> Было Тогда
ВызватьИсключение "Прерванный writer не должен стать отправленным";
КонецЕсли;
Состояние85 = "Own writer прерван до выборки и записи тела. Номер отправленного не изменился; регистрационные номера выборки здесь вообще не менялись.";
КонецПроцедуры
Процедура ОтправитьСвоюСтрокуA85(Кнопка)
ПроверитьСвоюСторону85("A");
МояСсылка85 = ПрочитатьСвоюСтроку85();
Если МойНомерОтправки85 <> 0 Или Не ПланыОбмена.ИзменениеЗарегистрировано(МойДругойУзел85, МояСсылка85) Тогда
ВызватьИсключение "Сначала одна own регистрация; эта форма отправляет её один раз";
КонецЕсли;
МояВерсияОтправки85 = МояСсылка85.ПолучитьОбъект().ВерсияДанных;
Результат = ЗаписатьСвойПакет85(Истина);
МойНомерОтправки85 = Результат.Номер;
Исходящее85 = Результат.XML;
Если Не ПланыОбмена.ИзменениеЗарегистрировано(МойДругойУзел85, МояСсылка85) Тогда
ВызватьИсключение "Одна отправка не является подтверждённым приёмом, own регистрацию нельзя считать ack";
КонецЕсли;
Состояние85 = "Native пакет A номер " + Строка(МойНомерОтправки85) + " сформирован. Скопируйте только этот own XML в B.Входящее85; форма A должна оставаться открытой до её actual ответа.";
КонецПроцедуры
Функция ЗаписатьСвойПакет85(ВыбратьОднуСтроку)
Было = МойДругойУзел85.ПолучитьОбъект().НомерОтправленного;
Поток = Новый ЗаписьXML;
Поток.УстановитьСтроку();
Writer = ПланыОбмена.СоздатьЗаписьСообщения();
Попытка
Если ТипЗнч(Writer) <> Тип("ЗаписьСообщенияОбмена") Тогда
ВызватьИсключение "Native factory должен вернуть actual writer";
КонецЕсли;
Writer.НачатьЗапись(Поток, МойДругойУзел85);
ПроверитьСвойАктивныйWriter85(Writer, Поток);
Номер = Writer.НомерСообщения;
Ack = Writer.НомерПринятого;
Если ВыбратьОднуСтроку Тогда
Выборка = ПланыОбмена.ВыбратьИзменения(Writer.Получатель, Номер, МояСсылка85);
Количество = 0;
Пока Выборка.Следующий() Цикл
Объект = Выборка.Получить();
Если ТипЗнч(Объект) <> Тип("СправочникОбъект.МояСтрока85") Тогда
ВызватьИсключение "Own фильтр должен выбрать только actual объект своей строки, не удаление или другую metadata";
КонецЕсли;
Если Объект.Ссылка <> МояСсылка85 Или Объект.Метка85 <> "c88b7ab1-1d4c-4893-b6be-1f16f4b85293" Тогда
ВызватьИсключение "Actual выборка не соответствует own ссылке/маркеру";
КонецЕсли;
Количество = Количество + 1;
КонецЦикла;
Если Количество <> 1 Тогда
ВызватьИсключение "Должно быть ровно одно actual изменение своей строки";
КонецЕсли;
КонецЕсли;
ПланыОбмена.ЗаписатьИзменения(Writer, 0);
Writer.ЗакончитьЗапись();
Исключение
ПрерватьИЗакрытьСвойWriterПослеОшибки85(Writer, Поток, ОписаниеОшибки());
КонецПопытки;
XML = Поток.Закрыть();
ПроверитьСвойНеактивныйWriter85(Writer);
Если МойДругойУзел85.ПолучитьОбъект().НомерОтправленного <> Номер Или Номер <> Было + 1 Или СтрДлина(XML) = 0 Тогда
ВызватьИсключение "Own законченный writer/counter/XML не совпали; не объявляем доставку";
КонецЕсли;
Возврат Новый Структура("XML,Номер,Ack", XML, Номер, Ack);
КонецФункции
Процедура ПрерватьИЗакрытьСвойWriterПослеОшибки85(Writer, Поток, ИсходнаяОшибка)
ОшибкиОсвобождения = "";
Попытка
Если Writer.ЗаписьXML <> Неопределено Тогда
Writer.ПрерватьЗапись();
КонецЕсли;
Исключение
ОшибкиОсвобождения = "; прервать writer не удалось: " + ОписаниеОшибки();
КонецПопытки;
Попытка
Поток.Закрыть();
Исключение
ОшибкиОсвобождения = ОшибкиОсвобождения + "; закрыть XML writer не удалось: " + ОписаниеОшибки();
КонецПопытки;
ВызватьИсключение ИсходнаяОшибка + ОшибкиОсвобождения;
КонецПроцедуры
Процедура ПроверитьСвойАктивныйWriter85(Writer, Поток)
Если Writer.ЗаписьXML <> Поток Или Writer.Получатель <> МойДругойУзел85 Или Writer.Получатель = МойЭтотУзел85
Или Writer.НомерСообщения <= 0 Или Writer.НомерПринятого <> МойДругойУзел85.ПолучитьОбъект().НомерПринятого Тогда
ВызватьИсключение "Actual writer XML/recipient/number/own received ack не совпали";
КонецЕсли;
КонецПроцедуры
Процедура ПроверитьСвойНеактивныйWriter85(Writer)
Если Writer.ЗаписьXML <> Неопределено Или Writer.Получатель <> Неопределено
Или Writer.НомерСообщения <> Неопределено Или Writer.НомерПринятого <> 0 Тогда
ВызватьИсключение "После Finish/Abort native writer должен сбросить документированные временные свойства";
КонецЕсли;
КонецПроцедуры
Процедура ПосмотретьИПрерватьСвойReader85(Кнопка)
ПроверитьСвойПустойСтенд();
ОпределитьСвоиУзлы85();
ПроверитьОписаниеСвоегоПакета85(Входящее85);
Состояние85 = "Отдельный native reader прочитал описание и был явно прерван. Узел не принял сообщение; для импорта нужен НОВЫЙ reader на том же own XML.";
КонецПроцедуры
Процедура ПроверитьОписаниеСвоегоПакета85(XML)
Если СтрДлина(XML) = 0 Или СтрДлина(XML) > 2000000 Тогда
ВызватьИсключение "Разрешён только небольшой XML, скопированный из своей второй формы";
КонецЕсли;
Было = МойДругойУзел85.ПолучитьОбъект().НомерПринятого;
Поток = Новый ЧтениеXML;
Поток.УстановитьСтроку(XML);
Reader = ПланыОбмена.СоздатьЧтениеСообщения();
Попытка
Reader.НачатьЧтение(Поток, ДопустимыйНомерСообщения.Очередной);
ПроверитьСвойАктивныйReader85(Reader, Поток);
Описание = ПланыОбмена.ПрочитатьОписаниеИзменений(Reader);
ПроверитьСвоёОписаниеБезConfigChanges85(Описание);
Reader.ПрерватьЧтение();
Исключение
ПрерватьИЗакрытьСвойReaderПослеОшибки85(Reader, Поток, ОписаниеОшибки());
КонецПопытки;
Поток.Закрыть();
ПроверитьСвойНеактивныйReader85(Reader);
Если МойДругойУзел85.ПолучитьОбъект().НомерПринятого <> Было Тогда
ВызватьИсключение "Предварительный reader не должен подтвердить приём";
КонецЕсли;
КонецПроцедуры
Процедура ПринятьСвойПакет85(Кнопка)
ПроверитьСвойПустойСтенд();
ОпределитьСвоиУзлы85();
ПроверитьОписаниеСвоегоПакета85(Входящее85);
Поток = Новый ЧтениеXML;
Поток.УстановитьСтроку(Входящее85);
Reader = ПланыОбмена.СоздатьЧтениеСообщения();
Попытка
Если ТипЗнч(Reader) <> Тип("ЧтениеСообщенияОбмена") Тогда
ВызватьИсключение "Native factory должен вернуть actual reader";
КонецЕсли;
Reader.НачатьЧтение(Поток, ДопустимыйНомерСообщения.Очередной);
ПроверитьСвойАктивныйReader85(Reader, Поток);
Отправитель = Reader.Отправитель;
Номер = Reader.НомерСообщения;
Ack = Reader.НомерПринятого;
Описание = ПланыОбмена.ПрочитатьИзмененияКонфигурацииИРасширенийКонфигурации(Reader);
ПроверитьСвоёОписаниеБезConfigChanges85(Описание);
ПланыОбмена.ПрочитатьИзменения(Reader, 0);
СсылкаПослеЧтения = ПрочитатьСвоюСтроку85();
Если МояСторона85 = "A" И СсылкаПослеЧтения <> МояСсылка85 Тогда
ВызватьИсключение "Ответ B не должен подменить own ссылку A";
КонецЕсли;
Reader.ЗакончитьЧтение();
Исключение
ПрерватьИЗакрытьСвойReaderПослеОшибки85(Reader, Поток, ОписаниеОшибки());
КонецПопытки;
Поток.Закрыть();
ПроверитьСвойНеактивныйReader85(Reader);
Если Отправитель <> МойДругойУзел85 Или МойДругойУзел85.ПолучитьОбъект().НомерПринятого <> Номер Тогда
ВызватьИсключение "Actual FinishedRead не подтверждён своим node received counter";
КонецЕсли;
Если МояСторона85 = "A" Тогда
Если МойНомерОтправки85 = 0 Или Ack < МойНомерОтправки85 Или Ack > МойДругойУзел85.ПолучитьОбъект().НомерОтправленного Тогда
ВызватьИсключение "Реально принят own ответ, но он не подтверждает сохранённую отправку A; очистка запрещена";
КонецЕсли;
МойПодтвержденныйНомер85 = Ack;
КонецЕсли;
Состояние85 = "Native FinishedRead " + МояСторона85 + ": received=" + Строка(Номер) + ", actual peer ack=" + Строка(Ack) + ". Own строка=7. Abort после уже импортированных данных не обещает rollback.";
КонецПроцедуры
Процедура ОтветитьТолькоИзСвоегоB85(Кнопка)
ПроверитьСвоюСторону85("B");
ПрочитатьСвоюСтроку85();
Если МойДругойУзел85.ПолучитьОбъект().НомерПринятого <= 0 Тогда
ВызватьИсключение "B сначала должен закончить actual чтение пакета A; до этого подтверждения нет";
КонецЕсли;
Результат = ЗаписатьСвойПакет85(Ложь);
Если Результат.Ack <> МойДругойУзел85.ПолучитьОбъект().НомерПринятого Тогда
ВызватьИсключение "Own ответ должен нести настоящий accepted number B из node record";
КонецЕсли;
Исходящее85 = Результат.XML;
Состояние85 = "Собственный ответ B номер " + Строка(Результат.Номер) + ", ack=" + Строка(Результат.Ack) + ". Скопируйте его в остающуюся открытой форму A.Входящее85, затем ПринятьСвойПакет85.";
КонецПроцедуры
Процедура ОчиститьТолькоПодтвержденнуюСвоюСтроку85(Кнопка)
ПроверитьСвоюСторону85("A");
Если МояСсылка85 = Неопределено Или МойНомерОтправки85 = 0 Или МойПодтвержденныйНомер85 < МойНомерОтправки85 Тогда
ВызватьИсключение "Без сохранённой own отправки и actual FinishedRead peer ack очистка запрещена";
КонецЕсли;
Если ПрочитатьСвоюСтроку85() <> МояСсылка85 Или МояСсылка85.ПолучитьОбъект().ВерсияДанных <> МояВерсияОтправки85
Или МойДругойУзел85.ПолучитьОбъект().НомерОтправленного <> МойНомерОтправки85 Тогда
ВызватьИсключение "После отправки own объект/версия/номер изменились; нельзя удалить новую регистрацию старым ack";
КонецЕсли;
ПланыОбмена.УдалитьРегистрациюИзменений(МойДругойУзел85, МояСсылка85);
Если ПланыОбмена.ИзменениеЗарегистрировано(МойДругойУзел85, МояСсылка85) Тогда
ВызватьИсключение "Explicit own очистка не подтверждена readback";
КонецЕсли;
Если ПрочитатьСвоюСтроку85() <> МояСсылка85 Тогда
ВызватьИсключение "После очистки регистрации actual собственная запись должна сохраниться";
КонецЕсли;
Состояние85 = "Только одна own регистрация удалена после actual ack; сам объект со значением7 сохранён. Если native импорт уже снял её, эта точная cleanup операция идемпотентна. Blanket node/metadata/произвольный номер не использовались.";
КонецПроцедуры
Процедура ПрерватьИЗакрытьСвойReaderПослеОшибки85(Reader, Поток, ИсходнаяОшибка)
ОшибкиОсвобождения = "";
Попытка
Если Reader.ЧтениеXML <> Неопределено Тогда
Reader.ПрерватьЧтение();
КонецЕсли;
Исключение
ОшибкиОсвобождения = "; прервать reader не удалось: " + ОписаниеОшибки();
КонецПопытки;
Попытка
Поток.Закрыть();
Исключение
ОшибкиОсвобождения = ОшибкиОсвобождения + "; закрыть XML reader не удалось: " + ОписаниеОшибки();
КонецПопытки;
ВызватьИсключение ИсходнаяОшибка + ОшибкиОсвобождения;
КонецПроцедуры
Процедура ПроверитьСвойАктивныйReader85(Reader, Поток)
Если Reader.ЧтениеXML <> Поток Или Reader.Отправитель <> МойДругойУзел85 Или Reader.Отправитель = МойЭтотУзел85
Или Reader.НомерСообщения <= 0 Или Reader.НомерПринятого < 0
Или Reader.НомерПринятого > МойДругойУзел85.ПолучитьОбъект().НомерОтправленного Тогда
ВызватьИсключение "Actual reader source/XML/number/own ack не совпали; импорт запрещён";
КонецЕсли;
КонецПроцедуры
Процедура ПроверитьСвойНеактивныйReader85(Reader)
Если Reader.ЧтениеXML <> Неопределено Или Reader.Отправитель <> Неопределено
Или Reader.НомерСообщения <> Неопределено Или Reader.НомерПринятого <> Неопределено Тогда
ВызватьИсключение "После Finish/Abort native reader должен сбросить свои временные свойства";
КонецЕсли;
КонецПроцедуры
Процедура ПроверитьСвоёОписаниеБезConfigChanges85(Описание)
Если ТипЗнч(Описание) <> Тип("ОписаниеИзмененийКонфигурацииВСообщенииОбмена") Тогда
ВызватьИсключение "Нужен настоящий native description, не искусственные flags";
КонецЕсли;
Если Описание.КонфигурацияИзменена Или Описание.РасширенияКонфигурацииИзменены Или Описание.ИзмененныеМетаданныеРасширенийКонфигурацииИзменяютСтруктуруДанных Тогда
ВызватьИсключение "Свой первоначальный протокол не разрешает config/extensions changes; не продолжайте импорт";
КонецЕсли;
КонецПроцедуры
Процедура ОтсоединитьИВосстановитьТолькоСвойChildB85(Кнопка)
ПроверитьСвоюСторону85("B");
Сохраненный = ПланыОбмена.ГлавныйУзел();
Если Сохраненный <> МойДругойУзел85 Или Сохраненный.Код <> "A" Или МойЭтотУзел85.Код <> "B" Тогда
ВызватьИсключение "Изменение главного узла разрешено только actual childB своего A";
КонецЕсли;
Попытка
ПланыОбмена.УстановитьГлавныйУзел(Неопределено);
Если ПланыОбмена.ГлавныйУзел() <> Неопределено Тогда
ВызватьИсключение "Own detached промежуточное состояние не подтверждено";
КонецЕсли;
ПланыОбмена.УстановитьГлавныйУзел(Сохраненный);
Если ПланыОбмена.ГлавныйУзел() <> Сохраненный Тогда
ВызватьИсключение "Own parent не восстановлен";
КонецЕсли;
Исключение
ИсходнаяОшибка = ОписаниеОшибки();
Текущий = ПланыОбмена.ГлавныйУзел();
Если Текущий = Неопределено Тогда
Попытка
ПланыОбмена.УстановитьГлавныйУзел(Сохраненный);
Если ПланыОбмена.ГлавныйУзел() <> Сохраненный Тогда
ВызватьИсключение "Own восстановление parent не подтверждено";
КонецЕсли;
Исключение
ВызватьИсключение ИсходнаяОшибка + "; own восстановление тоже не удалось: " + ОписаниеОшибки();
КонецПопытки;
ИначеЕсли Текущий <> Сохраненный Тогда
ВызватьИсключение ИсходнаяОшибка + "; обнаружен другой current parent: автоматически не перезаписываем";
КонецЕсли;
ВызватьИсключение ИсходнаяОшибка;
КонецПопытки;
Состояние85 = "Только own childB временно detached и actual parentA восстановлен. Это не обмен, не ack и не откат данных; исходные ошибки не скрывались.";
КонецПроцедуры
Процедура ПроверитьСвойПустойСтенд()
Если Метаданные.Справочники.Количество() <> 1 Или Метаданные.Документы.Количество() <> 0 Или Метаданные.Перечисления.Количество() <> 0 Или Метаданные.РегистрыСведений.Количество() <> 0 Или Метаданные.РегистрыНакопления.Количество() <> 0 Или Метаданные.РегистрыБухгалтерии.Количество() <> 0 Или Метаданные.РегистрыРасчета.Количество() <> 0 Или Метаданные.ПланыВидовХарактеристик.Количество() <> 0 Или Метаданные.ПланыВидовРасчета.Количество() <> 0 Или Метаданные.ПланыСчетов.Количество() <> 0 Или Метаданные.ПланыОбмена.Количество() <> 1 Или Метаданные.Последовательности.Количество() <> 0 Или Метаданные.БизнесПроцессы.Количество() <> 0 Или Метаданные.Задачи.Количество() <> 0 Или Метаданные.ОбщиеРеквизиты.Количество() <> 0 Или Метаданные.ПодпискиНаСобытия.Количество() <> 0 Или Метаданные.РегламентныеЗадания.Количество() <> 0 Или Метаданные.ВнешниеИсточникиДанных.Количество() <> 0 Тогда
ВызватьИсключение "Нужен только свой новый пустой учебный стенд";
КонецЕсли;
Если Метаданные.ЕстьИзмененияРасширениямиКонфигурации() Тогда
ВызватьИсключение "Свой сеанс не должен изменяться расширениями";
КонецЕсли;
Источники = Новый Массив;
Источники.Добавить(ИсточникРасширенийКонфигурации.БазаДанных);
Источники.Добавить(ИсточникРасширенийКонфигурации.СеансАктивные);
Источники.Добавить(ИсточникРасширенийКонфигурации.СеансОтключенные);
Для Каждого Источник Из Источники Цикл
Расширения = РасширенияКонфигурации.Получить(, Источник);
Если ТипЗнч(Расширения) <> Тип("Массив") Тогда
ВызватьИсключение "Native список расширений должен иметь тип Массив";
КонецЕсли;
Если Расширения.Количество() <> 0 Тогда
ВызватьИсключение "В своём новом стенде нет расширений базы или сеанса";
КонецЕсли;
КонецЦикла;
Если ТранзакцияАктивна() Тогда
ВызватьИсключение "Чужая или вложенная активная транзакция не допускается";
КонецЕсли;
КонецПроцедуры
#КонецЕслиРазбор по шагам
ПриОткрытии проверяет exact пустую собственную metadata, единственный RIB состав и запрещённую autoreregistration, два actual узла, native ЭтотУзел и root/child условия. UUID-path guard разбирает собственный File= из текущей строки соединения и разрешает только точное буквальное имя и совпадающее Файл.ПолноеИмя для A/B; серверная или чужая база отклоняется.
A→ПрерватьСвойWriter85 демонстрирует actual Begin/Abort до выбора или записи тела. Сохраняется номер предыдущей отправки; Begin предлагает следующий номер, Abort освобождает writer и не объявляется отправкой. Временные readonly writer свойства после Abort сброшены по native описанию.
A→ЗарегистрироватьТолькоСвоюСтроку85 проверяет всю единственную own запись, сначала отсутствие регистрации, затем вызов ЗарегистрироватьИзменения только для actual nodeB+actual ownref и readback Истина. Это не отправка и не подтверждение доставки.
A→ОтправитьСвоюСтрокуA85: в настоящий writer попадает own nodeB. Пока writer активен, считываются readonly Получатель/ЗаписьXML/НомерСообщения/НомерПринятого. ВыбратьИзменения с фильтром одной actual ссылки читает реальный изменённый объект и проставляет номер в регистрации: эта выборка не read-only. Нативный ЗаписатьИзменения(Writer,0) затем записывает полное RIB тело; вручную дублировать выбранный объект в XML нельзя.
ЗакончитьЗапись делает сообщение считающимся отправленным и обновляет own sent counter; XML строка готова для копирования. Это не доказывает получение B. Номер и собственная версия объекта сохранены до/во время отправки, потому что после Finish временные свойства writer сбрасываются. При ошибке явно Abort только ещё активного writer; регистрационные номера, уже изменённые выборкой, не объявляются откатившимися.
Скопируйте A.Исходящее85 в B.Входящее85. B→ПосмотретьИПрерватьСвойReader85: настоящий reader с допустимым номером Очередной проверяет header/own sender, читает ПрочитатьОписаниеИзменений, требует все три native config/extensions flags Ложь и явно Abort. Номер принятого узла не меняется. После description этот reader НЕЛЬЗЯ использовать для ПрочитатьИзменения.
B→ПринятьСвойПакет85 сначала повторяет отдельный безопасный preview. Для самого импорта создаёт НОВЫЙ reader на том же own XML; active header readonly значения сохраняются заранее. ПрочитатьИзмененияКонфигурацииИРасширенийКонфигурации идёт до ПрочитатьИзменения; если какой-либо config/extension flag не Ложь, дальше не продолжаем. Наши одинаковые A/B не требуют изменения CF или перезапуска.
ПрочитатьИзменения(Reader,0) реально импортирует RIB данные, после чего actual query должен найти одну own запись со всеми точными значениями7/marker. Только затем ЗакончитьЧтение нормально принимает сообщение и обновляет own peer received counter. Отдельный final readback подтверждает этот counter; это не общая транзакция всех reader/DB/config стадий.
B→ОтветитьТолькоИзСвоегоB85 разрешён лишь после actual accepted number>0. Native writer сам помещает этот реальный НомерПринятого в header собственного ответа. Передайте B.Исходящее85 обратно в остающуюся открытой форму A.Входящее85 и выполните ПринятьСвойПакет85. Только после FinishedRead собственного ответа A сохраняет actual ack, подтверждающий её сохранённую отправку и не превышающий реальный sent counter.
A→ОчиститьТолькоПодтвержденнуюСвоюСтроку85 запрещён до actual ack, при новом номере отправки или изменившейся версии own объекта. УдалитьРегистрациюИзменений получает только actual nodeB+одну actual ownref — не весь узел, metadata, Неопределено или пользовательский номер. После этого readback регистрации Ложь, сам объект7 остаётся. Если native импорт уже снял регистрацию, точный cleanup идемпотентен; это прямо отличено от утверждения, будто только данная команда обязательно произвела удаление.
Отдельный опыт только B: ОтсоединитьИВосстановитьТолькоСвойChildB85 сохраняет реальный ГлавныйУзел=A, временно отменяет назначение через Неопределено и восстанавливает тот же actual A. В ошибке автоматическое восстановление разрешено только из собственного промежуточного состояния ГлавныйУзел=Неопределено; если появился другой parent, он не перезаписывается. Исходная ошибка и ошибка восстановления не скрываются. Этот опыт не является доставкой/ack/rollback.
Как проверить результат
В настоящем начальном B native ЭтотУзел=B и ГлавныйУзел=A; обе базы имеют только два own узла. Команда образа второй раз обязана отказать из-за существующей цели. Ничего не удаляется/не перезаписывается.
A registration: Ложь→явная регистрация→Истина. Writer Begin/Abort до тела не меняет sent counter. Нормальная отправка A увеличивает counter на1 и оставляет регистрационное состояние неравнозначным ack.
B preview/Abort не увеличивает accepted counter и не создаёт own строку. Потом новая actual full read/Finish должна создать только запись Э85/Мой обмен85/7/собственный marker и увеличить own accepted counter до номера входящего сообщения.
B reply header carries actual accepted A message; до чтения ответа A очистка запрещена. A после actual FinishedRead ответа может очистить только свою неизменённую отправленную запись; readback регистрации Ложь, число7 и ownref не удалены.
Для безопасного собственного отрицательного опыта: очистка до ack, повторное создание B, запустить A-команду в B, повторно принять тот же пакет с Очередной, поставить неправильный own marker в отдельном disposable стенде. Все нарушения должны прерывать дальнейшие стадии. Не используйте чужой XML/реальный узел для негативного опыта.
Если произошла ошибка после ПрочитатьИзменения, проверьте реальные данные и node counters отдельно: Abort не обещает отменить уже импортированные записи. Не повторяйте сообщение с Любой и не вручную обнуляйте counters для обхода ошибки. Собственные A/B должны быть приведены пользователем к понятному проверенному состоянию.
B detach/restore завершается с тем же actual parentA. При исключении убедитесь, какой parent реально остался; сообщение не должно скрыть частичное изменение или утверждать автоматический rollback. Никакого рабочего parent код не выбирает и не перезаписывает.
Ожидаемый результат
Полный собственный RIB lifecycle с actual A/B образа, реальной регистрацией/выборкой, native XML writer/reader и только подтверждённым завершённым ответом, дающим право на точную очистку собственной неизменённой записи.
На что обратить внимание
СоздатьНачальныйОбраз действительно создаёт базу и удаляет регистрацию изменений для данного узла. Это high-impact native операция, разрешённая здесь только для новой собственной CF и несуществующего точного UUID B. Агент ничего не создавал/копировал/удалял.
ВыбратьИзменения проставляет номер в регистрациях при обходе; это не немутирующая диагностическая выборка. Abort writer до тела и Abort после уже выполненной выборки — разные состояния; обратный rollback регистрационных номеров не обещается.
ПрочитатьОписаниеИзменений делает данный reader непригодным для ПрочитатьИзменения: всегда новый reader для actual import. ПрочитатьИзмененияКонфигурацииИРасширенийКонфигурации допускает последующий import только если не было изменений/исключений; наш protocol требует три flags Ложь.
Параметр ЭлементовВТранзакции=0 относится к данным внутри отдельного native WriteChanges/ReadChanges. Это НЕ доказательство одной транзакции header, configuration updates, импортированных данных, FinishRead, регистрации и последующей cleanup.
ПрерватьЧтение снимает блокировку и не меняет запись узла. Не расширяйте это на rollback всех уже импортированных данных или изменений конфигурации. FinishRead отдельно подтверждает нормальный конец XML тела; отсутствие полного конца не даёт подтверждённого приема.
Временные свойства writer/reader действуют только между Begin и Finish/Abort. Writer НомерПринятого после завершения=0; прочие временные поля сбрасываются в Неопределено. Сохраняйте actual значения заранее, не используйте сброшенные поля для ack.
Число во втором параметре УдалитьРегистрациюИзменений удаляет регистрации этого узла с номером <= указанного, а Неопределено может удалить все. Здесь оба blanket варианта намеренно не используются: только точная собственная ссылка и реальный ack+version gate.
Обмен читает только XML из собственной второй формы; этот пример не является безопасным приемником произвольных недоверенных payload из сети. Общее криптографическое подтверждение доставки, подписи, повторы и конфликтные версии здесь не реализованы и не обещаются.
Source/config/production только read-only. Изготовлены лишь lesson/test источники и статические проверки; реальные 1С, DB, UI, files, сеть и native начальный образ агентом не запускались. Новых backups/archives не создавалось.
Пример не запускался в вашей базе. Перед применением проверьте его в указанном учебном контексте.