← Назад к вопросам

Реализация версионирования объектов

3.0 Senior🔥 131 комментариев
#Объекты метаданных#Регистры

Условие

Реализуйте механизм версионирования объектов — сохранение истории изменений справочника или документа.

Требования:

  • Сохранение всех версий объекта при каждом изменении
  • Возможность просмотра любой предыдущей версии
  • Сравнение двух версий (показать различия)
  • Восстановление объекта из предыдущей версии

Структура хранения

Регистр сведений "ВерсииОбъектов":

  • Измерения: Объект (ссылка), НомерВерсии
  • Ресурсы: ДанныеОбъекта (ХранилищеЗначения), Автор, ДатаИзменения

Интерфейс

Кнопка "История версий" на форме объекта с переходом к списку версий.

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Решение

1. Структура регистра сведений "ВерсииОбъектов"

РегистрСведений: "ВерсииОбъектов"
  Период: Истина

Измерения:
  - Объект (Ссылка) - УникальныйИдентификатор объекта
  - НомерВерсии (Число, 10)

Ресурсы:
  - ДанныеОбъекта (ХранилищеЗначения) - сохранённые данные
  - Автор (Справочник.Пользователи)
  - ДатаИзменения (ДатаВремя)
  - Комментарий (Строка, 1000)

2. Сохранение версии при записи объекта

Процедура СохранитьВерсиюОбъекта(ОбъектДляСохранения) Экспорт
    
    // Получаем текущие данные
    ДанныеДляХранилища = ПолучитьДанныеДляХранилища(ОбъектДляСохранения);
    
    // Определяем номер новой версии
    НомерВерсии = ПолучитьСледующийНомерВерсии(ОбъектДляСохранения.Ссылка);
    
    // Записываем в регистр
    НаборЗаписей = РегистрСведений.ВерсииОбъектов.СоздатьНаборЗаписей();
    НаборЗаписей.Фильтр.Объект.Значение = ОбъектДляСохранения.Ссылка;
    НаборЗаписей.Фильтр.НомерВерсии.Значение = НомерВерсии;
    
    НоваяЗапись = НаборЗаписей.Добавить();
    НоваяЗапись.Объект = ОбъектДляСохранения.Ссылка;
    НоваяЗапись.НомерВерсии = НомерВерсии;
    НоваяЗапись.ДанныеОбъекта = Новое ХранилищеЗначения(ДанныеДляХранилища);
    НоваяЗапись.Автор = ПользователиСистемы.ТекущийПользователь();
    НоваяЗапись.ДатаИзменения = ТекущаяДата();
    НоваяЗапись.Комментарий = "";
    
    НаборЗаписей.Записать();
    
КонецПроцедуры

Функция ПолучитьДанныеДляХранилища(ОбъектДанных)
    
    ДанныеДляХранилища = Новая Структура();
    
    // Сохраняем все реквизиты объекта
    Для каждого Реквизит Из ОбъектДанных.Метаданные().Реквизиты Цикл
        ДанныеДляХранилища.Вставить(Реквизит.Имя, ОбъектДанных[Реквизит.Имя]);
    КонецЦикла;
    
    // Сохраняем табличные части
    Для каждого ТабличнаяЧасть Из ОбъектДанных.Метаданные().ТабличныеЧасти Цикл
        ТаблицаЗначений = ОбъектДанных[ТабличнаяЧасть.Имя].Выгрузить();
        ДанныеДляХранилища.Вставить(ТабличнаяЧасть.Имя, ТаблицаЗначений);
    КонецЦикла;
    
    Возврат ДанныеДляХранилища;
    
КонецФункции

Функция ПолучитьСледующийНомерВерсии(ОбъектСсылка)
    
    Запрос = Новый Запрос();
    Запрос.Текст = "Выбрать МАКС(НомерВерсии) Как МаксНомер
        |Из РегистрСведений.ВерсииОбъектов
        |Где Объект = Параметр1";
    Запрос.УстановитьПараметр("Параметр1", ОбъектСсылка);
    
    РезультатЗапроса = Запрос.Выполнить();
    
    Если РезультатЗапроса.ЕстьДанные() Тогда
        ВыборкаСтрок = РезультатЗапроса.Выбрать();
        ВыборкаСтрок.Прочитать();
        МаксНомер = ВыборкаСтрок.МаксНомер;
        
        Если МаксНомер = Неопределено Тогда
            Возврат 1;
        Иначе
            Возврат МаксНомер + 1;
        КонецЕсли;
    Иначе
        Возврат 1;
    КонецЕсли;
    
КонецФункции

3. Просмотр версий

Функция ПолучитьСписокВерсий(ОбъектСсылка) Экспорт
    
    Запрос = Новый Запрос();
    Запрос.Текст = "Выбрать
        |    НомерВерсии,
        |    Автор,
        |    ДатаИзменения,
        |    Комментарий
        |Из РегистрСведений.ВерсииОбъектов
        |Где Объект = Параметр1
        |Упорядочить По НомерВерсии Убыв";
    Запрос.УстановитьПараметр("Параметр1", ОбъектСсылка);
    
    РезультатЗапроса = Запрос.Выполнить();
    Возврат РезультатЗапроса.Выгрузить();
    
КонецФункции

Функция ПолучитьДанныеВерсии(ОбъектСсылка, НомерВерсии) Экспорт
    
    НаборЗаписей = РегистрСведений.ВерсииОбъектов.СоздатьНаборЗаписей();
    НаборЗаписей.Фильтр.Объект.Значение = ОбъектСсылка;
    НаборЗаписей.Фильтр.НомерВерсии.Значение = НомерВерсии;
    НаборЗаписей.Прочитать();
    
    Если НаборЗаписей.Количество() > 0 Тогда
        ДанныеХранилища = НаборЗаписей[0].ДанныеОбъекта.Получить();
        Возврат ДанныеХранилища;
    КонецЕсли;
    
    Возврат Неопределено;
    
КонецФункции

4. Сравнение версий

Функция СравнитьВерсии(ОбъектСсылка, НомерВерсии1, НомерВерсии2) Экспорт
    
    ДанныеВерсии1 = ПолучитьДанныеВерсии(ОбъектСсылка, НомерВерсии1);
    ДанныеВерсии2 = ПолучитьДанныеВерсии(ОбъектСсылка, НомерВерсии2);
    
    ТаблицаРазличий = Новый ТаблицаЗначений();
    ТаблицаРазличий.Колонки.Добавить("ИмяПоля", , "Строка");
    ТаблицаРазличий.Колонки.Добавить("Версия1", , "Строка");
    ТаблицаРазличий.Колонки.Добавить("Версия2", , "Строка");
    
    // Сравниваем реквизиты
    Для каждого Пара Из ДанныеВерсии1 Цикл
        Если Пара.Значение <> ДанныеВерсии2[Пара.Ключ] Тогда
            НоваяСтрока = ТаблицаРазличий.Добавить();
            НоваяСтрока.ИмяПоля = Пара.Ключ;
            НоваяСтрока.Версия1 = Пара.Значение;
            НоваяСтрока.Версия2 = ДанныеВерсии2[Пара.Ключ];
        КонецЕсли;
    КонецЦикла;
    
    Возврат ТаблицаРазличий;
    
КонецФункции

5. Восстановление объекта

Процедура ВосстановитьИзВерсии(ОбъектСсылка, НомерВерсии) Экспорт
    
    ДанныеВерсии = ПолучитьДанныеВерсии(ОбъектСсылка, НомерВерсии);
    
    Если ДанныеВерсии = Неопределено Тогда
        Возврат;
    КонецЕсли;
    
    ОбъектДанных = ОбъектСсылка.ПолучитьОбъект();
    
    // Восстанавливаем реквизиты
    Для каждого Пара Из ДанныеВерсии Цикл
        Если ТипЗнч(Пара.Значение) = Тип("ТаблицаЗначений") Тогда
            // Это табличная часть
            ОбъектДанных[Пара.Ключ].Очистить();
            Для каждого СтрокаТаблицы Из Пара.Значение Цикл
                НоваяСтрока = ОбъектДанных[Пара.Ключ].Добавить();
                // Копируем значения из таблицы
            КонецЦикла;
        Иначе
            ОбъектДанных[Пара.Ключ] = Пара.Значение;
        КонецЕсли;
    КонецЦикла;
    
    ОбъектДанных.Записать();
    
    // Сохраняем как новую версию
    СохранитьВерсиюОбъекта(ОбъектДанных);
    
    Сообщить("Объект восстановлен из версии " + НомерВерсии);
    
КонецПроцедуры

6. Интеграция на форме объекта

&НаКлиенте
Процедура КнопкаИсторияВерсий()
    
    ПараметрыОтчёта = Новый Структура();
    ПараметрыОтчёта.Вставить("ОбъектСсылка", Объект.Ссылка);
    
    ОткрытьФорму("ОбщаяФорма.ИсторияВерсий",
        ПараметрыОтчёта,
        ЭтотОбъект);
    
КонецПроцедуры

&НаСервере
Процедура ПриЗаписи(Отмена)
    
    Если НЕ ЭтоНовый() Тогда
        // Только при изменении существующего объекта
        СохранитьВерсиюОбъекта(Объект);
    КонецЕсли;
    
КонецПроцедуры

7. Форма "История версий"

&НаКлиенте
Процедура ОткрытьВерсию()
    
    НомерВерсии = Элементы.СписокВерсий.ТекущаяСтрока.НомерВерсии;
    
    ПараметрыФормы = Новый Структура();
    ПараметрыФормы.Вставить("ОбъектСсылка", ОбъектСсылка);
    ПараметрыФормы.Вставить("НомерВерсии", НомерВерсии);
    
    ОткрытьФорму("ОбщаяФорма.ПросмотрВерсии",
        ПараметрыФормы,
        ЭтотОбъект);
    
КонецПроцедуры

&НаСервере
Процедура ПриОткрытии(Отмена)
    
    СписокВерсий = ПолучитьСписокВерсий(ОбъектСсылка);
    
КонецПроцедуры

Ключевые моменты

  • ХранилищеЗначения для сохранения структурированных данных
  • Номер версии для отслеживания истории
  • Автор и дата для аудита
  • Восстановление = новая версия с восстановленными данными
  • Сравнение версий для анализа изменений
Реализация версионирования объектов | PrepBro