Как сохранить в регистре сведений 1С коды маркировки, различающиеся только регистром символов?

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

При работе с системой маркировки «Честный Знак» (ГИС МТ) программисты 1С часто сталкиваются с неприятной особенностью: коды маркировки (DataMatrix) могут содержать символы в разном регистре, которые критически важны для валидации кода. Однако при попытке записать такие коды в регистр сведений (РС), система может выдать ошибку: «Запись с такими ключевыми полями существует». Это происходит даже в том случае, если коды визуально отличаются, например 0151215+gssC и 0151215+GSsC.

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

Выясним причину: почему 1С «не видит» разницу в регистре?

Проанализируем ситуацию с технической стороны. Когда вы создаете РегистрСведений, платформа 1С формирует в СУБД (например, Microsoft SQL Server или PostgreSQL) таблицу с уникальным индексом, в который входят все измерения регистра. Проблема заключается в параметре Collation (сортировка/сравнение) базы данных.

По умолчанию большинство баз данных 1С разворачиваются с настройкой Case Insensitive (CI), например, Cyrillic_General_CI_AS. Буквы «CI» означают нечувствительность к регистру. Для SQL-сервера значения строка и СТРОКА идентичны. При попытке записать вторую строку, отличающуюся только регистром, СУБД блокирует операцию, так как это нарушает уникальность индекса.

Важный нюанс: Встроенный язык 1С (при прямом сравнении переменных в коде) учитывает регистр, а вот запросы и индексы таблиц в БД — нет. Это создает диссонанс, при котором проверка в коде может пройти успешно, а метод Записать() вызовет исключение.

Решение №1: Добавление дополнительного измерения-счетчика

Самый простой и быстрый способ решить проблему «в лоб» — сделать записи уникальными за счет дополнительного поля. Рассмотрим этот вариант подробнее. Если у вас в рамках одного документа или одного сеанса загрузки приходят одинаковые с точки зрения SQL коды, мы можем добавить измерение ИндексСтроки с типом Число.

Разберем по шагам, как это реализовать:

  1. Добавьте в РегистрСведений новое измерение КлючУникальности (тип Число, длина 10, неотрицательное).
  2. При записи данных программно увеличивайте этот счетчик для каждой строки.

Посмотрим на пример кода при загрузке данных из файла:


МенеджерЗаписи = РегистрыСведений.КМ_Хранилище.СоздатьМенеджерЗаписи();
Счетчик = 0;

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

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

Решение №2: Использование вычисляемого хэша (Рекомендуется)

Проанализируем более профессиональный подход. Чтобы не загромождать регистр бессмысленными числами, можно использовать хэш-сумму от исходного кода. Хэш-функции (например, MD5) крайне чувствительны к регистру: хэш от gssC будет кардинально отличаться от хэша GSsC.

Рассмотрим алгоритм реализации:

  1. Добавьте измерение ХэшКода (тип Строка, фиксированная длина, например 32 символа).
  2. Перед записью вычисляйте хэш от строки кода маркировки.
  3. Используйте это поле как основное для обеспечения уникальности.

Посмотрим на пример функции для генерации хэша (используя встроенные средства платформы для работы с криптографией):


Функция ПолучитьХэшСтроки(Значение)
    Хеш = Новый ХешированиеДанных(ХешФункция.MD5);
    Хеш.Добавить(Значение);
    Возврат НРег(СтрЗаменить(Строка(Хеш.ХешСумма), " ", ""));
КонецФункции

// При записи:
Запись = РегистрыСведений.КМ_Хранилище.СоздатьМенеджерЗаписи();
Запись.КодМаркировки = ТекущийКод;
Запись.ХэшКода = ПолучитьХэшСтроки(ТекущийКод);
Запись.Записать();

Почему это работает? Для SQL-сервера значения хэшей будут выглядеть как абсолютно разные наборы символов (например, 1a2b3c... и 9f8e7d...). При этом сам исходный код маркировки сохраняется в соседнем ресурсе или измерении в неизменном виде.

Решение №3: Создание вспомогательного справочника

Если база данных предполагает хранение миллионов кодов, использование строк в измерениях регистра может привести к раздуванию индексов. Рассмотрим вариант с использованием объекта Справочник.

Проанализируем плюсы этого подхода:

Однако помните, что стандартный поиск в справочнике по реквизиту Наименование или Код (если это строка) столкнется с той же проблемой регистра в SQL. Чтобы этого избежать, в справочнике также рекомендуется использовать «хэширование» или хранить код в реквизите, а поиск осуществлять программно с дополнительной проверкой Стр1 = Стр2 во встроенном языке.

Важные особенности поиска данных в запросах

Рассмотрим ситуацию: вы успешно записали коды gssC и GSsC в регистр, используя хэширование. Теперь вам нужно найти информацию по коду GSsC. Если вы напишете простой запрос:


ВЫБРАТЬ
    Рег.КодМаркировки
ИЗ
    РегистрСведений.КМ_Хранилище КАК Рег
ГДЕ
    Рег.КодМаркировки = &НужныйКод

Внимание: Запрос вернет ОБЕ записи, так как SQL по-прежнему считает их одинаковыми. Чтобы получить точное соответствие, необходимо добавить в условие запроса проверку по хэшу или выполнять постобработку результата в коде 1С.

Разберем правильный метод получения данных:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |   Рег.КодМаркировки
    |ИЗ
    |   РегистрСведений.КМ_Хранилище КАК Рег
    |ГДЕ
    |   Рег.ХэшКода = &Хэш";

Запрос.УстановитьПараметр("Хэш", ПолучитьХэшСтроки("GSsC"));
Результат = Запрос.Выполнить().Выгрузить();
// Теперь в результате только ОДНА нужная запись

Почему нельзя просто изменить настройки SQL (Collation)?

Некоторые системные администраторы предлагают изменить настройку всей базы данных на Case Sensitive (CS). Мы настоятельно не рекомендуем этот путь. Платформа 1С:Предприятие и типовые конфигурации (УТ, ERP, БП) написаны в расчете на нечувствительность к регистру. Если вы измените настройки базы, вы столкнетесь с тем, что:

Резюме

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

  1. Никогда не используйте функции ВРег() или НРег() для принудительного изменения регистра кодов маркировки — это сделает их невалидными для Честного Знака.
  2. Для обеспечения уникальности в регистрах сведений используйте дополнительное измерение с хэш-суммой (MD5/SHA) или числовой индекс.
  3. При поиске данных в запросах всегда задействуйте поле с хэшем для точного позиционирования.
  4. Если объем данных велик, рассмотрите возможность выноса кодов в отдельный справочник, где в качестве ключевого поля используется ссылка.

Соблюдение этих архитектурных принципов позволит вам избежать ошибок дублирования данных и обеспечит стабильную работу системы маркировки в вашей конфигурации.

← На главную