Почему в настройках истории данных 1С не отображаются реквизиты объектов?

Программист 1С v8.3 (Управляемые формы) 1С:Зарплата и Управление Персоналом Управленческий учет
← К списку

Механизм "История данных" в 1С:Предприятии, доступный начиная с версии 8.3.11, является мощным инструментом для отслеживания изменений прикладных данных. Он позволяет нам выяснить, кто и когда изменил данные, сравнить различные версии объектов и при необходимости восстановить их предыдущее состояние. В отличие от версионирования в БСП, платформенный механизм хранит лишь "разницу" между версиями, что значительно экономит дисковое пространство и повышает производительность системы. Однако иногда мы можем столкнуться с ситуацией, когда в настройках истории данных для определенного объекта метаданных не отображаются его реквизиты. Это означает, что мы не можем выборочно включить или отключить отслеживание изменений для конкретных полей, что существенно ограничивает функциональность механизма. Давайте вместе разберемся, почему это происходит и как мы можем решить эту проблему.

Основная причина: некорректное состояние таблицы _DataHistoryMetadata

Мы выяснили, что наиболее частой причиной подобного поведения является некорректное состояние служебной таблицы _DataHistoryMetadata в базе данных. Эта таблица играет ключевую роль, храня версии метаданных объектов, для которых включена история данных. Если история данных "не видит" актуальную структуру метаданных объекта, она не может корректно записывать и отображать изменения по его реквизитам. Проанализируем ситуацию, с которой столкнулся один из наших коллег на форуме. После сброса настроек истории для проблемного объекта он обнаружил в таблице _DataHistoryMetadata несколько записей для одного и того же _MetadataId, причем все они были помечены как актуальные (флаг _IsActual установлен в значение "истина"). Это сбивает платформу с толку, поскольку она ожидает только одну актуальную версию метаданных. Кроме того, поле _Content, которое содержит бинарные данные о структуре объекта, может быть повреждено или устаревшим в некоторых записях. Для понимания, рассмотрим ключевые поля таблицы _DataHistoryMetadata:

  1. _MetadataId – уникальный идентификатор объекта метаданных.
  2. _IsSettings – флаг, указывающий, что данная версия метаданных была сформирована при изменении настроек истории.
  3. _IsActual – флаг, указывающий, является ли версия метаданных актуальной. Для каждого _MetadataId должна быть только одна запись с _IsActual = true.
  4. _MetadataVersionNumber – номер версии метаданных.
  5. _Content – бинарные данные, представляющие собой сериализованную структуру метаданных объекта.

Разберем по шагам решение проблемы, предложенное нашим коллегой, которое включает прямое вмешательство в СУБД PostgreSQL. Важно помнить, что любые прямые изменения в базе данных требуют обязательного предварительного создания резервной копии!

Шаг 1: Диагностика и выявление проблемного _MetadataId

Прежде чем вносить изменения, нам необходимо определить _MetadataId проблемного объекта. Мы можем получить его путем выгрузки конфигурации в файлы и поиска соответствующего UUID. Например, если мы ищем идентификатор для документа "ЗаказПокупателя", мы можем найти его UUID в файлах конфигурации. Далее, мы можем выполнить SQL-запрос для проверки состояния таблицы _DataHistoryMetadata для нашего объекта. Например, для PostgreSQL:


SELECT _metadataid, _issettings, _isactual, _metadataversionnumber
FROM _DataHistoryMetadata
WHERE _metadataid = decode('ВАШ_METADATA_ID', 'hex')
ORDER BY _metadataversionnumber;

Замените 'ВАШ_METADATA_ID' на реальный идентификатор вашего объекта. Если вы увидите несколько строк с _IsActual = true для одного и того же _MetadataId, то это подтверждает проблему.

Шаг 2: Сброс лишних флагов актуальности

Мы обнаружили, что несколько версий метаданных помечены как актуальные. Это ошибочное состояние, и нам необходимо сбросить флаг _IsActual для всех версий, кроме самой последней. Применим следующий SQL-запрос для PostgreSQL, который исправляет все обнаруженные случаи, когда для одного _MetadataId существует несколько актуальных версий, оставляя актуальной только последнюю:


UPDATE _datahistorymetadata AS dh
SET _isactual = false
WHERE _isactual AND EXISTS (
    SELECT 1
    FROM (
        SELECT _metadataid, MAX(_metadataversionnumber) AS maxnumber
        FROM _datahistorymetadata
        GROUP BY _metadataid
    ) AS t
    WHERE t._metadataid = dh._metadataid
      AND dh._metadataversionnumber < t.maxnumber
);

Этот запрос устанавливает _isactual = false для всех записей, которые не являются самой последней версией метаданных для своего _MetadataId, при условии, что они были помечены как актуальные. После выполнения этого запроса мы должны увидеть, что в настройках истории данных начинает отображаться новая, актуальная версия метаданных.

Шаг 3: Перезапись содержимого метаданных (поле _Content)

Наш коллега выяснил, что после сброса флагов актуальности новые события истории данных записываются корректно, но старые версии данных могут оставаться "голыми", то есть их структура не отображается. Это происходит потому, что поле _Content в старых записях могло быть повреждено или содержать устаревшие данные. Мы можем исправить это, перезаписав поле _Content во всех старых версиях метаданных значением из самой последней актуальной версии. Для этого используем следующий SQL-запрос (для PostgreSQL, адаптируйте _metadataid):


WITH last_versions AS (
    SELECT DISTINCT ON (_metadataid)
        _metadataid,
        _metadataversionnumber,
        _content
    FROM _datahistorymetadata
    WHERE _metadataid = decode('9df11f1fa836fabf4e63247590d31026', 'hex') -- Замените на ваш _MetadataId
    ORDER BY _metadataid, _metadataversionnumber DESC
)
UPDATE _datahistorymetadata AS dh
SET _content = lv._content
FROM last_versions AS lv
WHERE dh._metadataid = lv._metadataid
  AND dh._metadataversionnumber < lv._metadataversionnumber;

В этом запросе мы сначала создаем временную таблицу last_versions, которая содержит самую последнюю версию метаданных (_metadataid, _metadataversionnumber, _content) для нашего проблемного объекта. Затем мы обновляем поле _content во всех более ранних версиях метаданных этого объекта, используя значение из самой последней версии. После выполнения этого запроса старые версии данных также должны начать открываться корректно, отображая актуальную структуру метаданных.

Дополнительные причины и методы решения

Помимо основной проблемы, которую мы рассмотрели, существуют и другие факторы, влияющие на корректность работы истории данных. Давайте посмотрим на них.

Проблемы с очередью обработки истории (_DataHistoryQueue0)

Механизм истории данных работает через специальную очередь. Изменения, внесенные пользователями, сначала фиксируются в таблице _DataHistoryQueue0, а затем асинхронно обрабатываются и сохраняются как полноценные версии. Если в этой очереди возникают ошибки, например, некорректные типы значений или незавершенные записи, это может привести к сбоям в обновлении истории данных и нарушению ее работы. В некоторых случаях, если мы наблюдаем постоянные ошибки при обновлении истории данных, может помочь очистка таблицы _DataHistoryQueue0. Однако это очень радикальная мера, которая должна применяться с особой осторожностью, поскольку может привести к потере некоторых незафиксированных изменений истории.

Отсутствие обновления истории данных

Для того чтобы версии истории данных появились и отображались корректно, необходимо, чтобы платформа финализировала запись изменений и обновила информацию о структуре метаданных. Это происходит либо при выполнении метода ИсторияДанных.ОбновитьИсторию(), либо автоматически через регламентное задание по обновлению истории данных. Если это задание не настроено или не выполняется, или если метод не вызывается программно, история может не отображаться. Мы можем вызвать этот метод программно, например, в отдельной обработке:


ИсторияДанных.ОбновитьИсторию();

Убедитесь, что регламентное задание "Обновление истории данных" в вашей конфигурации включено и выполняется с достаточной периодичностью.

Неправильное удаление версий

Некорректное программное удаление версий истории данных, например, если мы случайно удаляем базовую версию документа, может привести к сообщению "Данные истории не найдены" при попытке открыть старую версию. При использовании метода ИсторияДанных.УдалитьВерсии() всегда следует быть крайне осторожными, чтобы не нарушить целостность цепочки версий.

Более безопасные подходы и предотвращение проблемы

Прямое вмешательство в СУБД, хотя и эффективно, всегда сопряжено с рисками повреждения информационной базы. Рассмотрим более безопасные и рекомендованные методы, которые мы можем использовать.

Программный сброс истории

Более безопасным подходом, чем прямое изменение данных в СУБД, является программный сброс истории для проблемного объекта средствами платформы 1С. Мы можем выполнить следующие шаги:

  1. Отключить историю для проблемного объекта через интерфейс настройки истории данных.
  2. Программно удалить все версии истории для этого объекта с помощью метода ИсторияДанных.УдалитьВерсии(). Важно убедиться, что удаление выполнено корректно и не затронута базовая версия объекта.
  3. Повторно включить историю для объекта.

Пример программного удаления версий для объекта:


// Предположим, что ОбъектМетаданных - это ссылка на объект метаданных,
// для которого нужно удалить историю, например:
// ОбъектМетаданных = Метаданные.Документы.РеализацияТоваровУслуг;
// Или можно получить его по имени:
ОбъектМетаданных = Метаданные.НайтиПоПолномуИмени("Документ.ИмяВашегоДокумента");

Если ОбъектМетаданных <> Неопределено Тогда
    ИсторияДанных.УдалитьВерсии(ОбъектМетаданных);
КонецЕсли;

Этот подход позволяет системе самостоятельно перестроить метаданные истории, минимизируя риски.

Регулярное обновление истории данных

Как мы уже упоминали, регулярное выполнение метода ИсторияДанных.ОбновитьИсторию() или настройка соответствующего регламентного задания помогает поддерживать актуальность версий и метаданных истории. Мы настоятельно рекомендуем убедиться в работоспособности этого регламентного задания.

Использование внешних обработок

Существуют специализированные внешние обработки, например, "Редактор настроек истории данных", которые предоставляют удобный визуальный интерфейс для управления настройками версионирования. Такие обработки могут позволить нам выборочно указывать отслеживаемые реквизиты, а также сбрасывать настройки к значениям конфигурации, что может помочь в случае проблем.

Обновление платформы

Мы знаем, что разработчики 1С постоянно улучшают платформу. В версии 8.3.24 и выше планируется ввести пользовательский интерфейс для настройки истории данных непосредственно в режиме 1С:Предприятия. Это значительно упростит управление и настройку без необходимости вносить изменения в конфигурацию или использовать сторонние инструменты, а также потенциально может решить некоторые внутренние проблемы механизма.

Важное предупреждение:

Прямое изменение данных в таблицах СУБД, как это предложено в сообщениях форума, является радикальным решением. Мы должны применять его с особой осторожностью и только при наличии актуальной резервной копии информационной базы. Некорректные действия могут привести к необратимому повреждению данных и потере работоспособности системы.

← К списку