Как записать повторяющиеся данные в базу 1С и исправить ошибку перемножения полей («Преобразование значения к типу Число не может быть выполнено»)?

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

Разработка прикладных решений на платформе «1С:Предприятие 8.3» существенно отличается от программирования на классических языках (таких как C#, Java, Python или PHP) с использованием традиционных реляционных баз данных. Начинающие разработчики, переходящие в среду 1С, часто совершают две фундаментальные ошибки: пытаются использовать регистры сведений как обычные таблицы SQL для записи любых повторяющихся данных и пытаются выполнять математические операции непосредственно со ссылочными типами данных на форме. В рамках этой статьи мы подробно разберем обе эти проблемы, выясним причины их возникновения и найдем элегантные и правильные решения в соответствии со стандартами разработки фирмы «1С».

Часть 1. Архитектура хранения данных: как записывать повторяющиеся данные без ошибок уникальности

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

В платформе 1С регистр сведений — это не просто плоская таблица, а объект, предназначенный для хранения информации в разрезе определенных ключевых полей — Измерений. Уникальность каждой записи в регистре сведений жестко контролируется платформой по комбинации значений всех его измерений (а для периодических регистров — еще и по дате/времени периода). Если вы создали регистр сведений с единственным измерением Предприятие, то платформа физически не позволит записать две строки с одинаковым значением в этом поле, так как их ключевые поля совпадают.

Давайте разберем по шагам, какими способами можно решить задачу хранения повторяющихся данных в зависимости от бизнес-логики приложения.

Способ 1. Использование справочников вместо регистров

Если ваша задача — хранить карточки объектов (в данном случае предприятий, контрагентов, товаров или сотрудников), то правильным решением будет использование объекта метаданных Справочник. Платформа 1С автоматически генерирует для каждого нового элемента справочника уникальный внутренний идентификатор (GUID) — Ссылка. Благодаря этому в справочнике может храниться неограниченное количество элементов с абсолютно одинаковыми наименованиями и реквизитами. Для пользователя они будут выглядеть одинаково, но для системы это будут разные сущности с уникальными ссылками.

Проанализируем преимущества использования справочников:

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

Способ 2. Добавление уникального измерения в Регистр сведений

Если бизнес-логика все же требует использования именно регистра сведений, нам необходимо искусственно сделать каждую запись уникальной. Для этого добавим в регистр дополнительное измерение, выполняющее роль первичного ключа:

  1. Создайте новое измерение регистра (например, с именем ИдентификаторЗаписи) с типом данных Строка (длина 36) или УникальныйИдентификатор.
  2. При записи данных генерируйте новый уникальный идентификатор программно с помощью функции Новый УникальныйИдентификатор().
  3. Теперь, даже если все полезные данные (название организации, адрес, телефон) будут полностью совпадать, записи будут успешно сохранены, так как они отличаются уникальным идентификатором в ключевом поле.

Способ 3. Использование периодичности регистра

Если данные должны записываться хронологически (например, история изменения цен, курсов валют или статусов предприятий), сделайте регистр сведений периодическим. В этом случае уникальность записи будет проверяться по комбинации Измерения + Период. Вы сможете записывать данные по одному и тому же предприятию многократно, если у записей будет разное время (вплоть до секунды или миллисекунды).

Часть 2. Математические операции на форме: устранение ошибки преобразования к типу Число

Теперь разберем вторую проблему, с которой часто сталкиваются начинающие разработчики. На форме документа или обработки есть три поля: СпецКоличество, СпецЦенаЗаЕд и СпецСумма. Нам необходимо сделать так, чтобы при изменении количества или цены в третьем поле автоматически рассчитывалась сумма по формуле:

Объект.СпецСумма = Объект.СпецКоличество * Объект.СпецЦенаЗаЕд;

При выполнении этого кода система выдает ошибку: «Преобразование значения к типу Число не может быть выполнено». Выясним причину этой ошибки.

Эта ошибка возникает из-за несовпадения типов данных. Разработчик ошибочно назначает реквизитам СпецКоличество и СпецЦенаЗаЕд ссылочный тип данных (например, тип СправочникСсылка.ФизическиеПоказатели или аналогичный), предполагая, что раз код или наименование внутри справочника является числом, то система сама преобразует ссылку в число при умножении. Но в 1С тип СправочникСсылка — это сложный объект (указатель на запись в таблице базы данных), и платформа физически не может умножить одну ссылку на другую.

Давайте посмотрим на пример правильной реализации расчетов на форме.

Решение А. Использование примитивного типа «Число» (для простых форм)

Если ваши поля на форме предназначены исключительно для ввода числовых значений пользователем, измените тип реквизитов объекта на Число в дереве конфигуратора. Задайте им необходимую длину и точность (например, Длина 15, Точность 2). После этого код расчета суммы на клиенте будет работать безупречно:


&НаКлиенте
Процедура СпецКоличествоПриИзменении(Элемент)
    // Реквизиты Объект.СпецКоличество и Объект.СпецЦенаЗаЕд имеют тип Число
    Объект.СпецСумма = Объект.СпецКоличество * Объект.СпецЦенаЗаЕд;
КонецПроцедуры

&НаКлиенте
Процедура СпецЦенаЗаЕдПриИзменении(Элемент)
    Объект.СпецСумма = Объект.СпецКоличество * Объект.СпецЦенаЗаЕд;
КонецПроцедуры

Решение Б. Расчет суммы в табличной части документа

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


&НаКлиенте
Процедура ТЧТоварыКоличествоПриИзменении(Элемент)
    
    // Получаем текущую строку табличной части
    ТекСтрока = Элементы.Товары.ТекущиеДанные;
    
    Если ТекСтрока <> Неопределено Тогда
        // Производим расчет числовых полей текущей строки
        ТекСтрока.Сумма = ТекСтрока.Цена * ТекСтрока.Количество;
    КонецЕсли;
    
КонецПроцедуры

Решение В. Получение числовых данных из справочника на сервере

Что делать, если в поле формы действительно должна выбираться ссылка на справочник (например, конкретная номенклатура), а цену или коэффициент нужно вытащить из этой ссылки для расчета суммы? Напрямую на клиенте обращаться к реквизитам ссылки через точку (например, написать Объект.Номенклатура.Цена) крайне не рекомендуется, так как это вызывает неявные и тяжелые серверные вызовы. Правильный подход — получить данные на сервере с помощью функции.

Рассмотрим подробнее реализацию этого метода:


&НаКлиенте
Процедура НоменклатураПриИзменении(Элемент)
    
    // Проверяем, заполнена ли ссылка на номенклатуру
    Если ЗначениеЗаполнено(Объект.Номенклатура) Тогда
        // Вызываем серверную функцию без контекста для получения цены
        ЦенаНоменклатуры = ПолучитьЦенуНаСервере(Объект.Номенклатура);
        Объект.СпецЦенаЗаЕд = ЦенаНоменклатуры;
        
        // Пересчитываем итоговую сумму
        Объект.СпецСумма = Объект.СпецКоличество * Объект.СпецЦенаЗаЕд;
    КонецЕсли;
    
КонецПроцедуры

&НаСервереБезКонтекста
Функция ПолучитьЦенуНаСервере(СсылкаНаНоменклатуру)
    // Извлекаем числовое значение реквизита непосредственно из базы данных
    Возврат СсылкаНаНоменклатуру.Цена;
КонецФункции

Использование директивы &НаСервереБезКонтекста является стандартом качественной разработки в системе 1С:Предприятие. Такие функции работают максимально быстро, так как они не передают всю форму с клиента на сервер и обратно, а оперируют только переданными параметрами.

Подводя итог, всегда четко разделяйте сущности базы данных: используйте Справочники для условно-постоянной информации и списков, Документы — для фиксации хозяйственных операций, а Регистры — для накопления итогов или хранения срезов сведений. И никогда не забывайте контролировать типы данных при написании математических формул на клиенте!

← На главную