Тип: ПараметрыЗаписиИсторииДанных. Используется для управления записью версии истории данных.
Полное описание, параметры и ограничения
РегистрСведенийМенеджерЗаписи.<Имя регистра сведений>.ЗаписьИсторииДанных (InformationRegisterRecordManager.<Information register name>.WriteDataHistory)
РегистрСведенийМенеджерЗаписи.<Имя регистра сведений> (InformationRegisterRecordManager.<Information register name>)
ЗаписьИсторииДанных (WriteDataHistory)
Доступен, начиная с версии 8.3.15.
Использование:
Только чтение.
Описание:
Тип: ПараметрыЗаписиИсторииДанных.
Используется для управления записью версии истории данных.
Доступность:
Сервер, толстый клиент, внешнее соединение, мобильное приложение (сервер), мобильный автономный сервер.
Использование в версии:
Доступен, начиная с версии 8.3.15.
Методическая информация
Практические примеры
Загрузить свою цену, проверить две реальные версии и удалить только собственную запись
Полный процесс250→300→отсутствие: собственный UUID, реально вызванный обработчик заполнения, раздельная проверка подготовленного комментария и сохраненной истории.
Где и как запускать
Два полных собственных серверных модуля и реальный модуль набора записей в новой отдельной файловойИБ8.5.1.1343; runtime не выполнялся.
Подготовка
Ничего не добавляйте в рабочие КА2/УНФ/УТ/БП. Вручную создайте новую отдельную файловую учебную ИБ платформы 8.5.1.1343, пустую конфигурацию с именем УчебныйЖизненныйЦиклЦен85, режим совместимости НеИспользовать. Здесь приводится авторский код, а не результат его выполнения в 1С.
Создайте единственного своего пользователя guide-record-cycle. В новой собственной конфигурации создайте учебную роль с полными правами только этого одноразового стенда и назначьте ее только этому пользователю. Нужны Администрирование, чтение/изменение собственных регистров, добавление/чтение собственного документа и все права истории данных, включая точно названное в native право ЧтениеИсторииОтсутствующихДанных. Не включайте RLS. В эту ИБ не должны входить другие пользователи/сеансы.
Все расширения базы/сеанса, подписки на события, регламентные задания, планы обмена, общие реквизиты/разделители, внешние источники/сервисы отсутствуют. Список пользователей/изоляция стенда проверяются человеком, код не доказывает отсутствие параллельного вмешательства.
Регистры сведений → УчебныеЦены85: режим записи Независимый, периодичность Непериодический, история данных Использовать. Только измерение UUIDОпыта85: Строка, длина 36, индексировать, проверка заполнения ПоказыватьОшибку. Только ресурс Цена: Число, 15 цифр, 2 дробных, неотрицательное. Реквизитов нет. Для UUID/цены включите участие в истории данных.
Документы → УчебнаяУстановкаЦен85: номер Строка, длина 40, автонумерация выключена, проведение Разрешить, запись движений при проведении ЗаписыватьВыбранные. Только реквизит UUIDОпыта85: УникальныйИдентификатор; табличных частей нет. История документа не используется. Модуль документа оставьте пустым: проведения/перепроведения здесь не вызываются.
Регистры сведений → УчебныеСтрокиЦен85: ПодчинениеРегистратору, периодичность ВПределахСекунды, единственный регистратор УчебнаяУстановкаЦен85. История НеИспользовать. Измерения UUIDОпыта85: Строка, длина 36, и КодТовара: Строка, длина 10; ресурсы Количество: Число, 10 цифр, 0 дробных, неотрицательное; Цена: Число, 15 цифр, 2 дробных, неотрицательное; других реквизитов нет. В документе в Движения добавьте только этот регистр.
В уроке цены в модуле набора записейУчебныеЦены85 вставьте полный вспомогательный блокОбработкаЗаполнения для цены; второй модуль пока пустой. В уроке строк заполните только модуль набора записейУчебныеСтрокиЦен85 его полным вспомогательным блоком. Оба обработчика имеют два настоящих аргумента и реально вызываются методомЗаполнить; вручную вызывать события не нужно. Остальные события этих модулей оставьте пустыми.
ОбщиеМодули → УчебныеЦеныЦикл85 иУчебныеСтрокиЦикл85: Сервер=Да, ВызовСервера=Да, остальные клиентские/внешнее соединение/глобальный/привилегированный флагиНет; повторное использование возвращаемых значенийНеИспользовать. Основной полный код текущего урока вставьте в соответствующий модуль; другой модуль до его урока оставьте пустым. Не вставляйте код внутрь чужих процедур.
Общие формы → УчебныйЦикл85: управляемая форма. Реквизиты UUIDОпыта85: Строка 36, UUIDДокумента85: Строка 36, Подтверждение85: Строка 100, Результат85: Строка 2048, ОшибкаЭтапа85: Булево (Ложь). Выведите UUID/подтверждение/результат полями, UUIDДокумента показывайте только для чтения. Открывайте форму через ВсеФункции/ФункцииДляТехническогоСпециалиста в своем толстом управляемом клиенте.
Для первого урока модуль общей формы полностью PRICE_FORM. Создайте командыНовыйUUID85, СоздатьПервую85, ЗаписатьВторую85, ПрочитатьДве85, УдалитьСвою85, назначьте одноименные действия и выведите кнопки. UUID создается только клиентской командой, не подставляется из чужой базы.
Между отдельными изменяющими командами вручную вводите точноеПодтверждение85: имя этапа без85, двоеточие и UUID. НапримерСоздатьПервую:вашUUID. Код очищает подтверждение до серверного вызова. ПрочитатьДве/ПрочитатьИтог не изменяют данные и подтверждения не требуют.
Первый урок: НовыйUUID85 → СоздатьПервую → ЗаписатьВторую → ПрочитатьДве → УдалитьСвою. Не меняйте UUID между этапами. Начальные регистры/документы должны быть пусты; код полного регистра/истории отклоняет неизвестные строки/версии, а не фильтрует их из вида.
НастройкиИсторииДанных включаются только для собственного нового регистра с 0 строк/0 версий; профиль UUID/Цена остается включенным после урока и намеренно не восстанавливается. ОбновитьИсторию вызывается только вне транзакции с конкретным своим КлючомЗаписи, Ложь/Ложь: нет общей обработки очереди, 20-дневной очистки или глобального обновления.
По native справке ПолучитьНастройки кэширует результат первого обращения до изменения конфигурации/версии. В коде первый getter следует после установки своего начального профиля. Повторный getter не объявляется свежей проверкой чужого изменения настроек: изоляция стенда обязательна. Наличие нужных сохраненных версий, UUID, цен и комментариев доказывается отдельно настоящей выборкой истории и снимками, а не этим кэшем.
Не запускайте фоновые обновления истории. Во всех собственных объектахОбновлятьИсториюСразуПослеЗаписи=Ложь, ВыполнятьОбработкуПослеЗаписиВерсии=Ложь. После каждой записи/удаления синхронный конкретныйОбновитьИсторию и независимая выборка подтверждают реальные версии. Номера не обещаются1/2/3, а берутся из фактических данных.
Для второго урока после завершения первого замените только модуль общей формы на полный ROWS_FORM и команды наНовыйUUID85, СоздатьДокумент85, НеВыбирать85, ВыбратьДве85, Отключить85, Включить85, ИсправитьКнигу85, УдалитьРучку85, ПрочитатьИтог85. Закройте старую форму, обновите конфигурацию и откройте новую с пустыми реквизитами; создайте новыйUUID. Независимый регистр к этому моменту пуст, его история остается.
Второй урок выполняйте вручную именноСоздатьДокумент → НеВыбирать → ВыбратьДве → Отключить → Включить → ИсправитьКнигу → УдалитьРучку → ПрочитатьИтог. UUIDДокумента появляется только после настоящегоСохранить/Записать документа и не выдумывается. Не меняйте возвращенный UUID, не подставляйте чужую ссылку.
Все запросы контроля данных читают целиком только три фиксированных собственных источника. Один собственный документ, собственныйUUID/период/два кода/реальные номера строк должны совпадать. Эти проверки не заменяют изоляцию или блокировки конкурентной системы.
После ошибки форма запрещает последующие/повторные команды. Запись/настройка могла уже завершиться; ничего автоматически не откатывается и не очищается. Вручную проверьте только этот учебныйUUID/ключ/документ и фактические версии в одноразовойИБ; не снимайте блокировку формы и не повторяйте изменения вслепую.
Новых резервных копий/архивов урок не создает. Итоговые учебные данные/история намеренно остаются в собственной отдельнойИБ; удаление самойИБ/документа/всей истории не является частью кода.
Функция ВыполнитьЦену85(Этап, UUID, Подтверждение) Экспорт
ПроверитьСвоюСхему85(UUID);
Если СтрРазделить("СоздатьПервую,ЗаписатьВторую,ПрочитатьДве,УдалитьСвою", ",").Найти(Этап) = Неопределено Тогда
ВызватьИсключение "Неизвестный ручной этап цены";
КонецЕсли;
Если Этап <> "ПрочитатьДве" И Подтверждение <> Этап + ":" + UUID Тогда
ВызватьИсключение "Введите точное отдельное подтверждение Этап:UUID";
КонецЕсли;
Ключ = РегистрыСведений.УчебныеЦены85.СоздатьКлючЗаписи(Новый Структура("UUIDОпыта85", UUID));
Если Этап = "СоздатьПервую" Тогда
ПроверитьТолькоСвоюЦену85(UUID, 0, 0);
Если ПолучитьСвоиДанные85("РегистрСведений.УчебныеСтрокиЦен85").Количество() <> 0
Или ПолучитьСвоиДанные85("Документ.УчебнаяУстановкаЦен85").Количество() <> 0 Тогда
ВызватьИсключение "Первая цена только в новом стенде без документов/подчиненных строк";
КонецЕсли;
ПроверитьСвоюИсторию85(Ключ, UUID, 0);
Настройки = Новый НастройкиИсторииДанных;
Настройки.Использование = Истина;
Поля = Новый Соответствие;
Поля.Вставить("UUIDОпыта85", Истина);
Поля.Вставить("Цена", Истина);
Настройки.ИспользованиеПолей = Поля;
ИсторияДанных.УстановитьНастройки(Метаданные.РегистрыСведений.УчебныеЦены85, Настройки);
ПроверитьСвойПрофильИстории85();
Запись = РегистрыСведений.УчебныеЦены85.СоздатьМенеджерЗаписи();
Запись.Заполнить(Новый Структура("UUIDОпыта85,Цена", UUID, 250));
Если Запись.UUIDОпыта85 <> UUID Или Запись.Цена <> 250 Тогда
ВызватьИсключение "Собственный обработчик заполнения менеджера не подтвердил UUID/цену250";
КонецЕсли;
Запись.УстановитьКомментарийВерсииИсторииДанных("price85-first:" + UUID);
КомментарийДоЗаписи = Запись.ПолучитьКомментарийВерсииИсторииДанных();
Если ТипЗнч(КомментарийДоЗаписи) <> Тип("Строка")
Или КомментарийДоЗаписи <> "price85-first:" + UUID
Или Запись.ЗаписьИсторииДанных.КомментарийВерсии <> КомментарийДоЗаписи Тогда
ВызватьИсключение "Проверка подготовленного комментария совместимости не прошла; это еще не история базы";
КонецЕсли;
Запись.ЗаписьИсторииДанных.Отказ = Ложь;
Запись.ЗаписьИсторииДанных.ОбновлятьИсториюСразуПослеЗаписи = Ложь;
Запись.ЗаписьИсторииДанных.ВыполнятьОбработкуПослеЗаписиВерсии = Ложь;
Запись.Записать(Ложь);
ПроверитьТолькоСвоюЦену85(UUID, 1, 250);
ИсторияДанных.ОбновитьИсторию(Ключ, Ложь, Ложь);
Версии = ПроверитьСвоюИсторию85(Ключ, UUID, 1);
Возврат "Первая цена250 сохранена. Фактический номер версии=" + Строка(Версии[0].НомерВерсии) + "; комментарий проверен по материализованной истории.";
КонецЕсли;
ПроверитьСвойПрофильИстории85();
Если Этап = "ЗаписатьВторую" Тогда
ПроверитьТолькоСвоюЦену85(UUID, 1, 250);
ПроверитьСвоюИсторию85(Ключ, UUID, 1);
Набор = РегистрыСведений.УчебныеЦены85.СоздатьНаборЗаписей();
Набор.Отбор.UUIDОпыта85.Установить(UUID);
Набор.Добавить();
Набор.Заполнить(Новый Структура("UUIDОпыта85,Цена", UUID, 300));
Если Набор.Количество() <> 1 Или Набор.Получить(0).UUIDОпыта85 <> UUID Или Набор.Получить(0).Цена <> 300
Или Набор.ОбменДанными.Загрузка Тогда
ВызватьИсключение "Нужна ровно своя цена300 без режима загрузки обмена";
КонецЕсли;
Набор.УстановитьКомментарийВерсииИсторииДанных("price85-second:" + UUID);
Если Набор.ЗаписьИсторииДанных.КомментарийВерсии <> "price85-second:" + UUID Тогда
ВызватьИсключение "Deprecated setter не подтвердил подготовленный комментарий набора";
КонецЕсли;
Набор.ЗаписьИсторииДанных.Отказ = Ложь;
Набор.ЗаписьИсторииДанных.ОбновлятьИсториюСразуПослеЗаписи = Ложь;
Набор.ЗаписьИсторииДанных.ВыполнятьОбработкуПослеЗаписиВерсии = Ложь;
Набор.Записать(РежимЗамещения.Обновление);
ПроверитьТолькоСвоюЦену85(UUID, 1, 300);
ИсторияДанных.ОбновитьИсторию(Ключ, Ложь, Ложь);
Версии = ПроверитьСвоюИсторию85(Ключ, UUID, 2);
Возврат СтрШаблон("Цена250→300; фактические номера=%1,%2, оба сохраненных комментария проверены.", Версии[0].НомерВерсии, Версии[1].НомерВерсии);
КонецЕсли;
ПроверитьТолькоСвоюЦену85(UUID, 1, 300);
Версии = ПроверитьСвоюИсторию85(Ключ, UUID, 2);
Если Этап = "ПрочитатьДве" Тогда
Возврат СтрШаблон("Историческая цена250 и300; текущая300. Номера=%1,%2 получены из настоящего отбора, а не придуманы.", Версии[0].НомерВерсии, Версии[1].НомерВерсии);
КонецЕсли;
Запись = РегистрыСведений.УчебныеЦены85.СоздатьМенеджерЗаписи();
Запись.UUIDОпыта85 = UUID;
Запись.Прочитать();
Если Не Запись.Выбран() Или Запись.Цена <> 300 Тогда
ВызватьИсключение "Новый менеджер должен прочитать нашу существующую цену300 перед точным удалением";
КонецЕсли;
Запись.ЗаписьИсторииДанных.КомментарийВерсии = "price85-delete:" + UUID;
Запись.ЗаписьИсторииДанных.Отказ = Ложь;
Запись.ЗаписьИсторииДанных.ОбновлятьИсториюСразуПослеЗаписи = Ложь;
Запись.ЗаписьИсторииДанных.ВыполнятьОбработкуПослеЗаписиВерсии = Ложь;
Запись.Удалить();
ПроверитьТолькоСвоюЦену85(UUID, 0, 0);
После = РегистрыСведений.УчебныеЦены85.СоздатьМенеджерЗаписи();
После.UUIDОпыта85 = UUID;
После.Прочитать();
Если После.Выбран() Тогда
ВызватьИсключение "Удаление своей цены не подтверждено свежим менеджером";
КонецЕсли;
ИсторияДанных.ОбновитьИсторию(Ключ, Ложь, Ложь);
Версии = ПроверитьСвоюИсторию85(Ключ, UUID, 3);
Возврат "Своей текущей цены больше нет. Две версии250/300 и фактическая версия удаления сохранены; история не удалялась.";
КонецФункции
Процедура ПроверитьСвойПрофильИстории85()
Настройки = ИсторияДанных.ПолучитьНастройки(Метаданные.РегистрыСведений.УчебныеЦены85);
Если Настройки = Неопределено Или Настройки.Использование <> Истина
Или Настройки.ИспользованиеПолей.Получить("UUIDОпыта85") <> Истина
Или Настройки.ИспользованиеПолей.Получить("Цена") <> Истина Тогда
ВызватьИсключение "Полученные настройки не подтверждают историю своей цены/UUID; чужой профиль автоматически не включаем";
КонецЕсли;
КонецПроцедуры
Процедура ПроверитьТолькоСвоюЦену85(UUID, ОжидаемыеСтроки, ОжидаемаяЦена)
Данные = ПолучитьСвоиДанные85("РегистрСведений.УчебныеЦены85");
Если Данные.Количество() <> ОжидаемыеСтроки Тогда
ВызватьИсключение "Во всем своем регистре другое число строк; неизвестные данные не изменяем";
КонецЕсли;
Для Каждого СтрокаЦены Из Данные Цикл
Если СтрокаЦены.UUIDОпыта85 <> UUID Или СтрокаЦены.Цена <> ОжидаемаяЦена Тогда
ВызватьИсключение "В регистре чужой UUID или цена не равна последнему подтвержденному этапу";
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Функция ПроверитьСвоюИсторию85(Ключ, UUID, ОжидаемыеВерсии)
Если ТранзакцияАктивна() Тогда
ВызватьИсключение "Обновление/проверка истории только вне чужой или своей активной транзакции";
КонецЕсли;
Отбор = Новый Структура("Метаданные", Метаданные.РегистрыСведений.УчебныеЦены85);
Версии = ИсторияДанных.ВыбратьВерсии(Отбор, "Данные,НомерВерсии,Комментарий", "НомерВерсии Возр", 4);
Если ТипЗнч(Версии) <> Тип("ТаблицаЗначений") Или Версии.Количество() <> ОжидаемыеВерсии Тогда
ВызватьИсключение "Во всей истории своего нового регистра другое число версий; автоматически не повторять запись";
КонецЕсли;
ПредыдущийНомер = 0;
Для Индекс = 0 По Версии.Количество() - 1 Цикл
Версия = Версии.Получить(Индекс);
Если ТипЗнч(Версия.Данные) <> Тип("РегистрСведенийКлючЗаписи.УчебныеЦены85")
Или Версия.Данные.UUIDОпыта85 <> UUID Или Версия.НомерВерсии <= ПредыдущийНомер Тогда
ВызватьИсключение "Чужой ключ или нарушенный порядок фактических номеров истории";
КонецЕсли;
ПредыдущийНомер = Версия.НомерВерсии;
ДанныеВерсии = ИсторияДанных.ПолучитьДанныеВерсии(Ключ, Версия.НомерВерсии);
Если Индекс = 2 Тогда
Если ДанныеВерсии <> Неопределено Или Версия.Комментарий <> "price85-delete:" + UUID Тогда
ВызватьИсключение "Удаление должно иметь свою фактическую версию без снимка данных";
КонецЕсли;
Иначе
ОжидаемаяЦена = ?(Индекс = 0, 250, 300);
ОжидаемыйКомментарий = ?(Индекс = 0, "price85-first:", "price85-second:") + UUID;
Если ТипЗнч(ДанныеВерсии) <> Тип("Структура") Или Не ДанныеВерсии.Свойство("UUIDОпыта85")
Или Не ДанныеВерсии.Свойство("Цена") Или ДанныеВерсии.UUIDОпыта85 <> UUID
Или ДанныеВерсии.Цена <> ОжидаемаяЦена Или Версия.Комментарий <> ОжидаемыйКомментарий Тогда
ВызватьИсключение "Материализованный исторический снимок/комментарий не равен своему ожидаемому250/300";
КонецЕсли;
КонецЕсли;
КонецЦикла;
Возврат Версии;
КонецФункции
Процедура ПроверитьСвоюСхему85(UUID)
ПроверитьСвойПустойСтенд();
Если ИмяПользователя() <> "guide-record-cycle" Тогда
ВызватьИсключение "Нужен единственный собственный учебный пользователь guide-record-cycle";
КонецЕсли;
Если ТипЗнч(UUID) <> Тип("Строка") Или СтрДлина(UUID) <> 36 Тогда
ВызватьИсключение "UUID опыта должен быть настоящей строкой из36символов";
КонецЕсли;
ПроверкаUUID = Новый УникальныйИдентификатор(UUID);
Если НРег(Строка(ПроверкаUUID)) <> НРег(UUID) Тогда
ВызватьИсключение "Недопустимый UUID опыта";
КонецЕсли;
Если Метаданные.ОбщиеМодули.Количество() <> 2 Или Метаданные.ОбщиеФормы.Количество() <> 1 Тогда
ВызватьИсключение "Нужны только два собственных серверных модуля и одна учебная общая форма";
КонецЕсли;
ИменаМодулей = СтрРазделить("УчебныеЦеныЦикл85,УчебныеСтрокиЦикл85", ",");
Для Каждого ИмяМодуля Из ИменаМодулей Цикл
Модуль = Метаданные.ОбщиеМодули.Найти(ИмяМодуля);
Если Модуль = Неопределено Или Не Модуль.Сервер Или Не Модуль.ВызовСервера
Или Модуль.Привилегированный
Или Модуль.ПовторноеИспользованиеВозвращаемыхЗначений <> Метаданные.СвойстваОбъектов.ПовторноеИспользованиеВозвращаемыхЗначений.НеИспользовать Тогда
ВызватьИсключение "Только свои непривилегированные серверные модули без кеширования";
КонецЕсли;
КонецЦикла;
Если Метаданные.ОбщиеФормы.Найти("УчебныйЦикл85") = Неопределено Тогда
ВызватьИсключение "Не подготовлена собственная общая форма";
КонецЕсли;
Цены = Метаданные.РегистрыСведений.Найти("УчебныеЦены85");
Строки = Метаданные.РегистрыСведений.Найти("УчебныеСтрокиЦен85");
Документ = Метаданные.Документы.Найти("УчебнаяУстановкаЦен85");
Если Цены = Неопределено Или Строки = Неопределено Или Документ = Неопределено Тогда
ВызватьИсключение "Нужны только два именованных собственных регистра и собственный документ";
КонецЕсли;
Если Цены.РежимЗаписи <> Метаданные.СвойстваОбъектов.РежимЗаписиРегистра.Независимый
Или Цены.ПериодичностьРегистраСведений <> Метаданные.СвойстваОбъектов.ПериодичностьРегистраСведений.Непериодический
Или Цены.Измерения.Количество() <> 1 Или Цены.Ресурсы.Количество() <> 1 Или Цены.Реквизиты.Количество() <> 0
Или Цены.ИсторияДанных <> Метаданные.СвойстваОбъектов.ИспользованиеИсторииДанных.Использовать Тогда
ВызватьИсключение "Независимый непериодический регистр цены должен иметь историю и только UUID/цену";
КонецЕсли;
Если Строки.РежимЗаписи <> Метаданные.СвойстваОбъектов.РежимЗаписиРегистра.ПодчинениеРегистратору
Или Строки.ПериодичностьРегистраСведений <> Метаданные.СвойстваОбъектов.ПериодичностьРегистраСведений.Секунда
Или Строки.Измерения.Количество() <> 2 Или Строки.Ресурсы.Количество() <> 2 Или Строки.Реквизиты.Количество() <> 0
Или Строки.ИсторияДанных <> Метаданные.СвойстваОбъектов.ИспользованиеИсторииДанных.НеИспользовать Тогда
ВызватьИсключение "Подчиненные строки должны иметь секундный период, UUID/код, количество/цену и не использовать историю";
КонецЕсли;
Если Документ.Реквизиты.Количество() <> 1 Или Документ.Реквизиты.Найти("UUIDОпыта85") = Неопределено
Или Документ.ТабличныеЧасти.Количество() <> 0 Или Документ.Движения.Количество() <> 1
Или Не Документ.Движения.Содержит(Строки)
Или Документ.ЗаписьДвиженийПриПроведении <> Метаданные.СвойстваОбъектов.ЗаписьДвиженийПриПроведении.ЗаписыватьВыбранные Тогда
ВызватьИсключение "Документ должен использовать только свой регистр и выбранные движения";
КонецЕсли;
Для Каждого Регистр Из Метаданные.РегистрыСведений Цикл
Метка = Регистр.Измерения.Найти("UUIDОпыта85");
Цена = Регистр.Ресурсы.Найти("Цена");
Если Метка = Неопределено Или Цена = Неопределено Тогда
ВызватьИсключение "Отсутствуют обязательные именованные поля";
КонецЕсли;
Если Метка.Тип.Типы().Количество() <> 1 Или Не Метка.Тип.СодержитТип(Тип("Строка"))
Или Метка.Тип.КвалификаторыСтроки.Длина <> 36
Или Цена.Тип.Типы().Количество() <> 1 Или Не Цена.Тип.СодержитТип(Тип("Число"))
Или Цена.Тип.КвалификаторыЧисла.Разрядность <> 15 Или Цена.Тип.КвалификаторыЧисла.РазрядностьДробнойЧасти <> 2 Тогда
ВызватьИсключение "UUID толькоСтрока36, цена толькоЧисло15,2";
КонецЕсли;
КонецЦикла;
Код = Строки.Измерения.Найти("КодТовара");
Количество = Строки.Ресурсы.Найти("Количество");
Если Код = Неопределено Или Количество = Неопределено Тогда
ВызватьИсключение "Не подготовлены код/количество своих строк";
КонецЕсли;
Если Код.Тип.Типы().Количество() <> 1 Или Не Код.Тип.СодержитТип(Тип("Строка"))
Или Код.Тип.КвалификаторыСтроки.Длина <> 10
Или Количество.Тип.Типы().Количество() <> 1 Или Не Количество.Тип.СодержитТип(Тип("Число"))
Или Количество.Тип.КвалификаторыЧисла.Разрядность <> 10
Или Количество.Тип.КвалификаторыЧисла.РазрядностьДробнойЧасти <> 0
Или Документ.Реквизиты.UUIDОпыта85.Тип.Типы().Количество() <> 1
Или Не Документ.Реквизиты.UUIDОпыта85.Тип.СодержитТип(Тип("УникальныйИдентификатор")) Тогда
ВызватьИсключение "Проверьте точные типы кода/количества/UUID документа";
КонецЕсли;
КонецПроцедуры
Функция ПолучитьСвоиДанные85(Источник)
Если СтрРазделить("РегистрСведений.УчебныеЦены85,РегистрСведений.УчебныеСтрокиЦен85,Документ.УчебнаяУстановкаЦен85", ",").Найти(Источник) = Неопределено Тогда
ВызватьИсключение "Запрос допускает только три собственных фиксированных источника";
КонецЕсли;
Запрос = Новый Запрос("ВЫБРАТЬ Д.* ИЗ " + Источник + " КАК Д");
Возврат Запрос.Выполнить().Выгрузить();
КонецФункции
Процедура ПроверитьСвойПустойСтенд()
Если Метаданные.Справочники.Количество() <> 0 Или Метаданные.Документы.Количество() <> 1 Или Метаданные.Перечисления.Количество() <> 0 Или Метаданные.РегистрыСведений.Количество() <> 2 Или Метаданные.РегистрыНакопления.Количество() <> 0 Или Метаданные.РегистрыБухгалтерии.Количество() <> 0 Или Метаданные.РегистрыРасчета.Количество() <> 0 Или Метаданные.ПланыВидовХарактеристик.Количество() <> 0 Или Метаданные.ПланыВидовРасчета.Количество() <> 0 Или Метаданные.ПланыСчетов.Количество() <> 0 Или Метаданные.ПланыОбмена.Количество() <> 0 Или Метаданные.Последовательности.Количество() <> 0 Или Метаданные.БизнесПроцессы.Количество() <> 0 Или Метаданные.Задачи.Количество() <> 0 Или Метаданные.ОбщиеРеквизиты.Количество() <> 0 Или Метаданные.ПодпискиНаСобытия.Количество() <> 0 Или Метаданные.РегламентныеЗадания.Количество() <> 0 Или Метаданные.ВнешниеИсточникиДанных.Количество() <> 0 Тогда
ВызватьИсключение "Нужен только свой новый пустой учебный стенд";
КонецЕсли;
Если Метаданные.ЕстьИзмененияРасширениямиКонфигурации() Тогда
ВызватьИсключение "Свой сеанс не должен изменяться расширениями";
КонецЕсли;
Источники = Новый Массив;
Источники.Добавить(ИсточникРасширенийКонфигурации.БазаДанных);
Источники.Добавить(ИсточникРасширенийКонфигурации.СеансАктивные);
Источники.Добавить(ИсточникРасширенийКонфигурации.СеансОтключенные);
Для Каждого Источник Из Источники Цикл
Расширения = РасширенияКонфигурации.Получить(, Источник);
Если ТипЗнч(Расширения) <> Тип("Массив") Тогда
ВызватьИсключение "Native список расширений должен иметь тип Массив";
КонецЕсли;
Если Расширения.Количество() <> 0 Тогда
ВызватьИсключение "В своём новом стенде нет расширений базы или сеанса";
КонецЕсли;
КонецЦикла;
Если ТранзакцияАктивна() Тогда
ВызватьИсключение "Чужая или вложенная активная транзакция не допускается";
КонецЕсли;
КонецПроцедурыМодуль набора записейУчебныеЦены85
Собственная CF → Регистры сведений → УчебныеЦены85 → Модуль набора записей, целиком.
Реальный серверный модуль набора записей собственного регистра; ОбработкаЗаполнения вызывается платформой, не вручную.
Процедура ОбработкаЗаполнения(ДанныеЗаполнения, СтандартнаяОбработка)
СтандартнаяОбработка = Ложь;
Если ТипЗнч(ДанныеЗаполнения) <> Тип("Структура") Или ДанныеЗаполнения.Количество() <> 2
Или Не ДанныеЗаполнения.Свойство("UUIDОпыта85") Или Не ДанныеЗаполнения.Свойство("Цена")
Или ТипЗнч(ДанныеЗаполнения.UUIDОпыта85) <> Тип("Строка") Или СтрДлина(ДанныеЗаполнения.UUIDОпыта85) <> 36
Или ТипЗнч(ДанныеЗаполнения.Цена) <> Тип("Число")
Или (ДанныеЗаполнения.Цена <> 250 И ДанныеЗаполнения.Цена <> 300) Или ЭтотОбъект.Количество() <> 1 Тогда
ВызватьИсключение "Заполнение только собственным точным форматомUUID/цена250или300 и единственной строкой";
КонецЕсли;
ПроверкаUUID = Новый УникальныйИдентификатор(ДанныеЗаполнения.UUIDОпыта85);
Если НРег(Строка(ПроверкаUUID)) <> НРег(ДанныеЗаполнения.UUIDОпыта85) Тогда
ВызватьИсключение "Недопустимый UUID заполнения";
КонецЕсли;
Если ЭтотОбъект.ОбменДанными.Загрузка Тогда
ВызватьИсключение "Учебное заполнение не использует обход проверок черезЗагрузка";
КонецЕсли;
СтрокаЦены = ЭтотОбъект.Получить(0);
СтрокаЦены.UUIDОпыта85 = ДанныеЗаполнения.UUIDОпыта85;
СтрокаЦены.Цена = ДанныеЗаполнения.Цена;
КонецПроцедурыМодуль управляемой общей формы для цены
Собственная CF → Общие формы → УчебныйЦикл85 → Модуль формы, целиком; текущий вариант для этого урока.
Модуль собственной управляемой общей формы УчебныйЦикл85, клиентские команды и реальные вызовы своих серверных общих модулей.
&НаКлиенте
Процедура НовыйUUID85(Команда)
Если ЗначениеЗаполнено(UUIDОпыта85) Тогда
ВызватьИсключение "Существующий UUID не заменяется. Новую попытку после ошибки автоматически не запускайте";
КонецЕсли;
UUIDОпыта85 = Строка(Новый УникальныйИдентификатор);
Результат85 = "Скопируйте UUID и вводите отдельное подтверждение перед каждой изменяющей командой.";
КонецПроцедуры
&НаКлиенте
Процедура СоздатьПервую85(Команда)
ЗапуститьЦену85("СоздатьПервую");
КонецПроцедуры
&НаКлиенте
Процедура ЗаписатьВторую85(Команда)
ЗапуститьЦену85("ЗаписатьВторую");
КонецПроцедуры
&НаКлиенте
Процедура ПрочитатьДве85(Команда)
ЗапуститьЦену85("ПрочитатьДве");
КонецПроцедуры
&НаКлиенте
Процедура УдалитьСвою85(Команда)
ЗапуститьЦену85("УдалитьСвою");
КонецПроцедуры
&НаКлиенте
Процедура ЗапуститьЦену85(Этап)
Если ОшибкаЭтапа85 Тогда
ВызватьИсключение "Прошлый этап завершился ошибкой: результат может быть частичным; сначала вручную исследуйте собственный стенд";
КонецЕсли;
ТекущееПодтверждение = Подтверждение85;
Подтверждение85 = "";
Попытка
Результат85 = УчебныеЦеныЦикл85.ВыполнитьЦену85(Этап, UUIDОпыта85, ТекущееПодтверждение);
Исключение
ОшибкаЭтапа85 = Истина;
Результат85 = "СТОП: частичный результат возможен. " + ОписаниеОшибки();
КонецПопытки;
КонецПроцедурыРазбор по шагам
Менеджер записи применяется только независимому регистру. Заполнить передает нашу структуру в событиеОбработкаЗаполнения с одной записью; собственный обработчик устанавливаетUUID/цену, а не получает неизвестный готовый объект.
СоздатьПервую требует0своих/чужих строк во всех источниках и0версий всего регистра. Включается только профиль своего нового регистра и проверяется отдельнымGetSettings; профиль намеренно остается.
МетодыУстановитьКомментарийВерсииИсторииДанных у менеджера/набора не рекомендуются с8.3.15. Здесь это отдельная совместимость старого кода: сначала проверяется pending-комментарий. Для нового кода используйте readonly-контейнерЗаписьИсторииДанных и его RWКомментарийВерсии.
После фактической записи250 конкретныйОбновитьИсторию материализует историю вне транзакции. ВыбратьВерсии/ПолучитьДанныеВерсии независимо проверяютUUID, цену и сохраненный комментарий; getter менеджера до записи не считается persisted-proof.
ЗаписатьВторую строит собственный набор из единственной строки, задает точный отборUUID иЗаполнить с ценой300. РежимОбновление не добавляет новую строку при отсутствии соответствующего ключа. ЗагрузкаОбмена остаетсяЛожь.
ПрочитатьДве выполняет только чтение: текущая300 и реальные исторические250/300. Номера строго возрастают, но не принимаются равными1/2.
УдалитьСвою отдельная подтвержденная команда: fresh менеджер прочитал собственную300, затемDelete без аргументов удаляет именно этот ключ. Второй fresh менеджер и общий raw-запрос доказывают отсутствие.
Фактическая версия удаления имеетНеопределено вместо снимка данных. Первые две версии и их комментарии сохранены; методов удаления истории нет. Ошибка останавливает цепочку без слепого rollback/retry.
Как проверить результат
ПослеСоздатьПервую: весь независимый регистр содержит ровноUUID/250; одна фактическая версия сprice85-first:UUID и снимком250.
ПослеЗаписатьВторую: весь регистрUUID/300; ровно две настоящие версии250/300, сохраненные комментарииprice85-first:UUID/price85-second:UUID.
ПрочитатьДве возвращает реальные номера из таблицы версий и не записывает данные.
ПослеУдалитьСвою: raw0, свежийВыбран=Ложь, история3 с прежними250/300 иНеопределено в снимке удаления; price85-delete:UUID.
ДругойUUID/профиль/количество строк/чужая версия/неверное подтверждение/активная транзакция останавливают урок до соответствующего воздействия.
Ожидаемый результат
При успешном ручном выполнении на своём стенде ожидается: цена250→300→отсутствие текущей записи; реальные версии и комментарии истории сохранены. Здесь только подготовлен и статически проверен код, запуск1С не выполнялся.
На что обратить внимание
Полная роль/правоЧтениеИсторииОтсутствующихДанных обязательны для начальных0версий и чтения истории после удаления; без них возможны исключение или исключение отсутствующих данных из выборки.
Нельзя переносить менеджер записи в подчиненный регистр: native описание разрешает его только независимому. Активность/НомерСтроки/Регистратор менеджера записи намеренно не используются.
0строк/0версий и UUID не являются атомарной блокировкой. УчебнаяИБ должна быть изолирована; при параллельном вмешательстве не продолжать.
Успешный pending-getter не доказывает созданную историю. Синхронное обновление/полная выборка/реальные снимки — отдельные проверки.
Начальные настройки своего регистра действительно изменяются и не возвращаются; никакой атомарности/очистки после неуспеха не обещается.
Пример не запускался в вашей базе. Перед применением проверьте его в указанном учебном контексте.