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