← Назад к вопросам
Реализация версионирования объектов
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. Форма "История версий"
&НаКлиенте
Процедура ОткрытьВерсию()
НомерВерсии = Элементы.СписокВерсий.ТекущаяСтрока.НомерВерсии;
ПараметрыФормы = Новый Структура();
ПараметрыФормы.Вставить("ОбъектСсылка", ОбъектСсылка);
ПараметрыФормы.Вставить("НомерВерсии", НомерВерсии);
ОткрытьФорму("ОбщаяФорма.ПросмотрВерсии",
ПараметрыФормы,
ЭтотОбъект);
КонецПроцедуры
&НаСервере
Процедура ПриОткрытии(Отмена)
СписокВерсий = ПолучитьСписокВерсий(ОбъектСсылка);
КонецПроцедуры
Ключевые моменты
- ХранилищеЗначения для сохранения структурированных данных
- Номер версии для отслеживания истории
- Автор и дата для аудита
- Восстановление = новая версия с восстановленными данными
- Сравнение версий для анализа изменений