При интеграции сторонних приложений с 1С через COM-соединение (V83.COMConnector) программисты часто сталкиваются с ситуацией, когда один и тот же код безупречно работает на серверных базах (Client-Server), но выдает загадочную ошибку в файловых версиях. Одной из самых трудноуловимых является ошибка: «Элемент уже добавлен. Ключ в словаре WRITE, добавляемый ключ WRITE».
Эта проблема обычно возникает в момент обращения к коллекциям движений документа или при попытке добавить новую запись в регистр. В данной статье мы проанализируем причины этого поведения и рассмотрим эффективные методы решения задачи.
Разберем природу проблемы. В файловом варианте 1С работа через COM-интерфейс происходит в рамках единого процесса. Ошибка с ключом WRITE указывает на внутренний конфликт в механизме управления свойствами объектов 1С. Когда мы обращаемся к свойству Движения (Movements) через C# или другой внешний язык, система пытается инициализировать внутренние структуры объекта. В файловом режиме при определенных условиях (например, если объект еще не записан или к нему обращаются повторно через динамические типы) происходит попытка двойной регистрации объекта в таблице изменений, что и приводит к конфликту ключей в словаре платформы.
Самая частая ошибка — попытка заполнить движения у еще не созданного (не записанного в базу) объекта ДокументОбъект. В серверной версии платформа прощает это, кэшируя данные в памяти, но в файловой версии это вызывает сбой. Рассмотрим правильный алгоритм действий.
Сначала мы должны создать и физически записать документ, чтобы он получил ссылку в базе данных, и только после этого приступать к работе с его регистрами. Проанализируем пример кода на C#:
// 1. Создаем объект документа
dynamic новыйДокумент = comConector.Документы.ОперацияБух.СоздатьДокумент();
новыйДокумент.Дата = DateTime.Now;
// ... заполнение реквизитов шапки ...
// 2. ОБЯЗАТЕЛЬНО записываем документ перед работой с движениями
новыйДокумент.Записать();
// 3. Теперь обращаемся к движениям
dynamic набор = новыйДокумент.Движения.ЕПСБУ;
набор.Добавить();
// ... заполнение проводки ...
набор.Записать();
Важный нюанс: в некоторых случаях даже прямое обращение к новыйДокумент.Движения после записи может вызвать ту же ошибку. Если это произошло, переходим к следующему методу.
Если работа через свойство Движения объекта документа продолжает выдавать ошибку, рекомендуется использовать более «низкоуровневый» способ — создание набора записей регистра напрямую через менеджер регистра. Это позволяет избежать обращения к контексту объекта документа, который часто является источником конфликтов WRITE.
Рассмотрим, как реализовать этот подход:
НаборЗаписей для нужного регистра.Пример реализации:
// Записываем документ для получения ссылки
новыйДокумент.Записать();
var ссылкаНаДокумент = новыйДокумент.Ссылка;
// Работаем через набор записей регистра бухгалтерии
dynamic набор = comConector.РегистрыБухгалтерии.ЕПСБУ.СоздатьНаборЗаписей();
набор.Отбор.Регистратор.Установить(ссылкаНаДокумент);
dynamic новаяЗапись = набор.Добавить();
новаяЗапись.Регистратор = ссылкаНаДокумент;
новаяЗапись.Период = новыйДокумент.Дата;
// ... заполнение аналитики (СчетКт, СчетДт, Субконто) ...
набор.Записать();
Этот метод считается более стабильным для файловых баз, так как он минимизирует количество неявных обращений к кэшу объекта документа.
Практика показывает, что наиболее надежный способ работы через COM — это минимизация манипуляций со сложными объектами (такими как таблицы и наборы записей) на стороне внешнего приложения. Вместо того чтобы мучительно отлаживать типы dynamic в C#, мы можем передать всю тяжелую работу внутрь 1С.
Выполним следующие шаги:
ИнтеграцияСВнешнимиСистемами.Пример процедуры в 1С:
Процедура СоздатьПроводкуЕПСБУ(ПараметрыДокумента) Экспорт
ДокОбъект = Документы.ОперацияБух.СоздатьДокумент();
// Заполнение из структуры ПараметрыДокумента
ДокОбъект.Записать();
Движение = ДокОбъект.Движения.ЕПСБУ.Добавить();
// Заполнение движения...
ДокОбъект.Движения.ЕПСБУ.Записать();
КонецПроцедуры
Теперь из C# нам достаточно вызвать одну функцию:
comConector.ИнтеграцияСВнешнимиСистемами.СоздатьПроводкуЕПСБУ(данные);
Это полностью исключает ошибки маршалинга и конфликты словарей в COM-соединении, так как весь цикл жизни объекта проходит внутри платформы 1С.
Проанализируем еще несколько моментов, которые помогут избежать ошибки WRITE:
НайтиПоКоду или НайтиПоНаименованию непосредственно перед использованием. В БГУ 1.0 счета могут быть периодическими, поэтому иногда критично использовать методы получения счета на определенную дату: БухгалтерскийУчет.СчетПоКоду(Код, Дата).System.Runtime.InteropServices.Marshal.ReleaseComObject(obj). Это предотвращает «зависание» транзакций в файловой базе.comConector.BeginTransaction() и comConector.CommitTransaction(). Это может помочь платформе корректно выстроить очередь записи в файловую таблицу.Подводя итог, можно сказать, что ошибка «Ключ в словаре WRITE» — это сигнал о том, что файловый движок 1С не справляется с последовательностью вызовов свойств через COM. Использование наборов записей или общих модулей — самый эффективный способ обойти это ограничение и обеспечить стабильную работу интеграции.