Как реализовать одновременную запись данных несколькими пользователями в один документ 1С

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

В стандартной парадигме платформы 1С:Предприятие заложен принцип пессимистической блокировки. Это означает, что когда один пользователь открывает форму объекта (например, документа) и начинает его редактировать, объект блокируется для всех остальных. При попытке записи другим пользователем система выдаст ошибку: «Объект заблокирован». Однако в реальных бизнес-процессах часто возникает задача, когда несколько менеджеров должны одновременно наполнять одну и ту же табличную часть (ТЧ) данными (например, список контрагентов или спецификацию заказа).

Рассмотрим подробнее, как обойти это ограничение и архитектурно правильно организовать совместную работу, сохранив целостность данных и высокую производительность системы.

Метод 1. Очередь изменений через Регистр Сведений

Проанализируем самый надежный и масштабируемый способ — использование промежуточного «буфера». Вместо того чтобы давать пользователям прямой доступ к форме документа, мы создаем вспомогательный РегистрСведений (например, ОчередьИзмененийТЧ).

Разберем алгоритм по шагам:

  1. Создание АРМ (Рабочего места): Пользователи работают не с самим документом, а со специальной обработкой или формой. В этой форме они видят текущий список данных и поле для ввода новых записей.
  2. Фиксация намерения: При нажатии кнопки «Добавить» данные не записываются в документ. Вместо этого создается запись в РегистрСведений. Каждая запись должна содержать ссылку на целевой документ, данные строки ТЧ и уникальный идентификатор пользователя (или сеанса).
  3. Асинхронная запись: На сервере настраивается регламентное задание (фоновый процесс), которое раз в несколько секунд «опрашивает» регистр.

Посмотрим на пример логики фонового задания:


// Фрагмент кода фонового задания
Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |   Очередь.СсылкаНаДокумент,
    |   Очередь.Контрагент,
    |   Очередь.Количество
    |ИЗ
    |   РегистрСведений.ОчередьИзмененийТЧ КАК Очередь
    |ДЛЯ ИЗМЕНЕНИЯ";

Результат = Запрос.Выполнить();
Выборка = Результат.Выбрать();

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

Преимущество: Пользователи никогда не сталкиваются с блокировками, так как пишут в независимые записи регистра.

Метод 2. Паттерн «Мастер-документ и Подчиненные документы»

Выясним причину, по которой иногда стоит изменить саму структуру данных. Если бизнес-логика допускает, что данные могут поступать частями, лучше использовать разделение объектов. Вместо одной огромной табличной части в одном документе, мы вводим понятие «Лист правок» или «Заявка на добавление».

Проанализируем ситуацию: каждый менеджер создает свой собственный документ ЗаявкаНаКонтрагента, в котором указывает ссылку на основной (мастер) документ. Основной документ в этом случае становится лишь «контейнером», который собирает данные из подчиненных объектов.

Как это работает технически:

Метод 3. Программное слияние (Merge) и оптимистическая блокировка

Рассмотрим случай, когда нужно сохранить стандартный интерфейс, но минимизировать время блокировки. В 1С по умолчанию используется пессимистическая модель (блокировка при открытии). Мы можем программно перейти к оптимистической модели.

Разберем логику реализации в модуле формы:

  1. Отключаем автоматическую блокировку данных формы.
  2. В момент нажатия пользователем кнопки «Записать» выполняем следующий алгоритм:

// В обработчике команды записи
&НаСервере
Процедура ЗаписатьБезБлокировкиНаСервере()
    // 1. Читаем актуальное состояние объекта из БД
    ТекущийОбъект = РеквизитФормыВЗначение("Объект").Ссылка.ПолучитьОбъект();
    
    // 2. Блокируем объект только на миллисекунды
    ТекущийОбъект.Заблокировать();
    
    // 3. Сравниваем ТЧ на форме и ТЧ в объекте
    // Добавляем только те строки, которых еще нет в БД
    Для Каждого СтрокаФормы Из Объект.Контрагенты Цикл
        Если ТекущийОбъект.Контрагенты.Найти(СтрокаФормы.Контрагент, "Контрагент") = Неопределено Тогда
            НоваяСтр = ТекущийОбъект.Контрагенты.Добавить();
            ЗаполнитьЗначенияСвойств(НоваяСтр, СтрокаФормы);
        КонецЕсли;
    КонецЦикла;
    
    // 4. Записываем и уведомляем форму
    ТекущийОбъект.Записать();
    ЗначениеВРеквизитФормы(ТекущийОбъект, "Объект");
КонецПроцедуры

Важный нюанс: Для реализации такого «слияния» строк необходимо иметь в табличной части уникальный идентификатор строки (UID), чтобы система понимала, какие строки были изменены, какие добавлены, а какие удалены другими пользователями, пока форма была открыта.

Технические рекомендации и особенности платформы

При реализации любого из этих методов следует учитывать системные механизмы 1С:

1. Использование метода ЗаблокироватьДанныеДляРедактирования(). Если вы решили писать код, который работает напрямую с объектом, вызывайте этот метод непосредственно перед выполнением транзакции записи, а не в начале работы пользователя. Это сокращает окно конфликтов.

2. Разделение итогов (версии 8.3.20+). Если ваша задача сводится к накоплению числовых показателей (например, объемы поставок в рамках одного заказа), используйте РегистрыСведений с включенным свойством Разделение итогов. Это позволит СУБД записывать данные в разные физические таблицы параллельно, «схлопывая» их только при чтении.

3. Сериализация данных. При работе через промежуточное хранилище (например, ХранилищеЗначений или длинную строку JSON) важно предусмотреть механизм десериализации, чтобы фоновое задание корректно восстановило структуру таблицы значений перед интеграцией в документ.

Подведем итог

Выбор конкретного решения зависит от требований к интерфейсу и объема данных:

Помните, что запись в один объект из разных сеансов всегда несет риск потери данных (проблема «последнего записавшего»), поэтому алгоритм слияния данных должен быть тщательно отлажен на предмет идентификации строк.

← На главную