При работе с системой маркировки «Честный Знак» (ГИС МТ) программисты 1С часто сталкиваются с неприятной особенностью: коды маркировки (DataMatrix) могут содержать символы в разном регистре, которые критически важны для валидации кода. Однако при попытке записать такие коды в регистр сведений (РС), система может выдать ошибку: «Запись с такими ключевыми полями существует». Это происходит даже в том случае, если коды визуально отличаются, например 0151215+gssC и 0151215+GSsC.
В этой статье мы подробно разберем, почему возникает эта проблема, как настройки сервера баз данных влияют на поведение 1С и какие программные методы позволяют обойти это ограничение без потери целостности данных.
Проанализируем ситуацию с технической стороны. Когда вы создаете РегистрСведений, платформа 1С формирует в СУБД (например, Microsoft SQL Server или PostgreSQL) таблицу с уникальным индексом, в который входят все измерения регистра. Проблема заключается в параметре Collation (сортировка/сравнение) базы данных.
По умолчанию большинство баз данных 1С разворачиваются с настройкой Case Insensitive (CI), например, Cyrillic_General_CI_AS. Буквы «CI» означают нечувствительность к регистру. Для SQL-сервера значения строка и СТРОКА идентичны. При попытке записать вторую строку, отличающуюся только регистром, СУБД блокирует операцию, так как это нарушает уникальность индекса.
Важный нюанс: Встроенный язык 1С (при прямом сравнении переменных в коде) учитывает регистр, а вот запросы и индексы таблиц в БД — нет. Это создает диссонанс, при котором проверка в коде может пройти успешно, а метод Записать() вызовет исключение.
Самый простой и быстрый способ решить проблему «в лоб» — сделать записи уникальными за счет дополнительного поля. Рассмотрим этот вариант подробнее. Если у вас в рамках одного документа или одного сеанса загрузки приходят одинаковые с точки зрения SQL коды, мы можем добавить измерение ИндексСтроки с типом Число.
Разберем по шагам, как это реализовать:
РегистрСведений новое измерение КлючУникальности (тип Число, длина 10, неотрицательное).Посмотрим на пример кода при загрузке данных из файла:
МенеджерЗаписи = РегистрыСведений.КМ_Хранилище.СоздатьМенеджерЗаписи();
Счетчик = 0;
Для Каждого СтрокаДанных Из ТаблицаКодов Цикл
Счетчик = Счетчик + 1;
МенеджерЗаписи.Период = ТекущаяДата();
МенеджерЗаписи.КодМаркировки = СтрокаДанных.Код; // Например, "gssC"
МенеджерЗаписи.КлючУникальности = Счетчик; // Обеспечивает уникальность для SQL
МенеджерЗаписи.Записать();
КонецЦикла;
Этот метод надежен, но имеет минус: если вы захотите быстро найти запись именно по коду маркировки, вам придется перебирать все возможные ключи уникальности или использовать запросы, которые (как мы помним) все равно вернут несколько «похожих» записей.
Проанализируем более профессиональный подход. Чтобы не загромождать регистр бессмысленными числами, можно использовать хэш-сумму от исходного кода. Хэш-функции (например, MD5) крайне чувствительны к регистру: хэш от gssC будет кардинально отличаться от хэша GSsC.
Рассмотрим алгоритм реализации:
ХэшКода (тип Строка, фиксированная длина, например 32 символа).Посмотрим на пример функции для генерации хэша (используя встроенные средства платформы для работы с криптографией):
Функция ПолучитьХэшСтроки(Значение)
Хеш = Новый ХешированиеДанных(ХешФункция.MD5);
Хеш.Добавить(Значение);
Возврат НРег(СтрЗаменить(Строка(Хеш.ХешСумма), " ", ""));
КонецФункции
// При записи:
Запись = РегистрыСведений.КМ_Хранилище.СоздатьМенеджерЗаписи();
Запись.КодМаркировки = ТекущийКод;
Запись.ХэшКода = ПолучитьХэшСтроки(ТекущийКод);
Запись.Записать();
Почему это работает? Для SQL-сервера значения хэшей будут выглядеть как абсолютно разные наборы символов (например, 1a2b3c... и 9f8e7d...). При этом сам исходный код маркировки сохраняется в соседнем ресурсе или измерении в неизменном виде.
Если база данных предполагает хранение миллионов кодов, использование строк в измерениях регистра может привести к раздуванию индексов. Рассмотрим вариант с использованием объекта Справочник.
Проанализируем плюсы этого подхода:
Ссылка (GUID), которая всегда уникальна и имеет фиксированный размер.Однако помните, что стандартный поиск в справочнике по реквизиту Наименование или Код (если это строка) столкнется с той же проблемой регистра в SQL. Чтобы этого избежать, в справочнике также рекомендуется использовать «хэширование» или хранить код в реквизите, а поиск осуществлять программно с дополнительной проверкой Стр1 = Стр2 во встроенном языке.
Рассмотрим ситуацию: вы успешно записали коды gssC и GSsC в регистр, используя хэширование. Теперь вам нужно найти информацию по коду GSsC. Если вы напишете простой запрос:
ВЫБРАТЬ
Рег.КодМаркировки
ИЗ
РегистрСведений.КМ_Хранилище КАК Рег
ГДЕ
Рег.КодМаркировки = &НужныйКод
Внимание: Запрос вернет ОБЕ записи, так как SQL по-прежнему считает их одинаковыми. Чтобы получить точное соответствие, необходимо добавить в условие запроса проверку по хэшу или выполнять постобработку результата в коде 1С.
Разберем правильный метод получения данных:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Рег.КодМаркировки
|ИЗ
| РегистрСведений.КМ_Хранилище КАК Рег
|ГДЕ
| Рег.ХэшКода = &Хэш";
Запрос.УстановитьПараметр("Хэш", ПолучитьХэшСтроки("GSsC"));
Результат = Запрос.Выполнить().Выгрузить();
// Теперь в результате только ОДНА нужная запись
Некоторые системные администраторы предлагают изменить настройку всей базы данных на Case Sensitive (CS). Мы настоятельно не рекомендуем этот путь. Платформа 1С:Предприятие и типовые конфигурации (УТ, ERP, БП) написаны в расчете на нечувствительность к регистру. Если вы измените настройки базы, вы столкнетесь с тем, что:
Администратор и администратор станут разными пользователями.Выборка.Наименование, может вызвать ошибку, если в конфигураторе поле названо НАИМЕНОВАНИЕ.Для корректной работы с кодами маркировки, чувствительными к регистру, в среде 1С следует придерживаться следующих правил:
ВРег() или НРег() для принудительного изменения регистра кодов маркировки — это сделает их невалидными для Честного Знака.Соблюдение этих архитектурных принципов позволит вам избежать ошибок дублирования данных и обеспечит стабильную работу системы маркировки в вашей конфигурации.