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