Ситуация, когда после нескольких часов кропотливого заполнения сложного документа или справочника система выдает ошибку «Данные были изменены или удалены другим пользователем», является одной из самых стрессовых для пользователя и ответственных для программиста. В этот момент стандартная кнопка «Записать» блокируется, а закрытие формы приведет к безвозвратной потере введенной информации. В данной статье мы подробно разберем, почему возникает эта ошибка, и рассмотрим пошаговые алгоритмы спасения данных с помощью инструментов отладки и программных механизмов 1С.
Прежде чем приступать к спасению данных, проанализируем ситуацию. В платформе 1С реализован механизм оптимистической блокировки. Его суть заключается в том, что система не блокирует объект в базе данных в тот момент, когда пользователь открывает форму для редактирования. Вместо этого в каждой таблице объектных данных существует скрытое системное поле DataVersion (Версия данных).
Рассмотрим алгоритм работы этого механизма:
Если перед нами открытая форма с данными, которые нельзя потерять, наиболее надежным методом будет использование отладки. Разберем, как выгрузить состояние объекта в текстовую строку, которую потом можно будет восстановить. Мы будем использовать СериализаторXDTO, так как он более стабилен по сравнению с устаревшим методом ЗначениеВСтрокуВнутр.
Пошаговый алгоритм действий:
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.УстановитьСтроку();
СериализаторXDTO.ЗаписатьXML(ЗаписьXML, Объект); // Где "Объект" — это СправочникОбъект или ДокументОбъект
СтрокаДанных = ЗаписьXML.Закрыть();
Полученную длинную строку необходимо скопировать в обычный текстовый файл. Теперь данные в безопасности. После того как вы закроете форму и заново откроете объект, вы сможете программно восстановить данные, выполнив обратную операцию:
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.УстановитьСтроку(СтрокаДанных);
ВосстановленныйОбъект = СериализаторXDTO.ПрочитатьXML(ЧтениеXML);
КопироватьДанныеОбъекта(ВосстановленныйОбъект, Объект);
Проанализируем ситуацию: если мы точно знаем, что наши изменения в форме приоритетнее тех, что были внесены в базу данных, мы можем обмануть механизм проверки версий. Для этого нам нужно программно подменить версию данных в нашем объекте на ту, которая сейчас актуальна в базе.
Рассмотрим пример кода, который можно выполнить в отладке или через внешнюю обработку:
// 1. Получим актуальную версию напрямую из базы данных
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ ВерсияДанных ИЗ Справочник.Номенклатура ГДЕ Ссылка = &Ссылка";
Запрос.УстановитьПараметр("Ссылка", Объект.Ссылка);
Результат = Запрос.Выполнить().Выбрать();
Если Результат.Следующий() Тогда
АктуальнаяВерсия = Результат.ВерсияДанных;
КонецЕсли;
// 2. Установим актуальную версию нашему объекту в памяти
Объект.ДополнительныеСвойства.Вставить("ВерсияДанных", АктуальнаяВерсия);
// В некоторых случаях может потребоваться использование Рефлексии или прямое присвоение через отладчик
После этой манипуляции платформа при вызове метода Записать() увидит, что версии совпадают, и позволит сохранить данные. Внимание: используйте этот метод осторожно, так как вы полностью затрете изменения того пользователя, который успел записать объект раньше вас.
Если вы — не программист, а пользователь, и помощи ждать некогда, воспользуйтесь стандартным функционалом платформы для спасения табличных частей. Почти в любой форме списка или табличной части документа есть кнопка «Еще» — «Вывести список».
Теперь, даже если форма будет закрыта, у вас останется файл со всеми данными табличной части, которые можно будет перенести обратно вручную или с помощью обработки загрузки из Excel.
Рассмотрим системные решения, которые помогут предотвратить потерю данных в многопользовательской среде.
Для объектов, работа с которыми занимает длительное время (например, медицинские протоколы или сметы), рекомендуется внедрить механизм пессимистической блокировки. В отличие от оптимистической, она блокирует объект в базе сразу при открытии формы.
Для этого в модуле формы в обработчике ПриОткрытии или при начале редактирования используется метод:
Объект.Заблокировать();
В этом случае другой пользователь, попытавшийся открыть этот же объект, сразу получит предупреждение, что документ занят, и не сможет вносить в него изменения до тех пор, пока первый пользователь не закроет форму.
Посмотрим на пример реализации простого автосохранения. Можно создать фоновое задание или использовать обработчик ожидания в форме, который каждые несколько минут будет выгружать текущее состояние данных во временное хранилище или в специальный регистр сведений «Черновики».
Проанализируем структуру такого решения:
ЧерновикиОбъектов с измерениями Пользователь, ОбъектСсылка и ресурсом Данные (Тип: ХранилищеЗначения).ПодключитьОбработчикОжидания("ЗаписатьЧерновик", 300); (раз в 5 минут).В современной платформе 1С (начиная с версии 8.3.11) доступен стандартный механизм «История данных». Если он включен для конкретного объекта, система автоматически сохраняет все версии объекта при каждой записи. Даже если один пользователь нечаянно перезаписал данные другого, администратор может открыть историю, сравнить версии и выполнить откат к нужному состоянию, используя стандартные интерфейсные формы.
Резюме: Ошибка блокировки — это защитный механизм платформы, а не программный сбой. Для спасения «зависших» данных используйте отладку и XML-сериализацию, а для стабильной работы в будущем внедряйте пессимистические блокировки или подсистемы автосохранения.