При проектировании сложных учетных механизмов в 1С:Предприятии перед разработчиком часто встает задача надежной связки строк различных таблиц. В классической объектной модели 1С принято связывать данные через ссылки (документы или справочники). Однако, когда речь заходит о связывании записей в независимых регистрах сведений, строках табличных частей или временных структурах, стандартные подходы могут оказаться неэффективными или избыточными.
В этой статье мы подробно разберем, как правильно связывать неподчиненные напрямую таблицы, проанализируем сильные и слабые стороны использования типа УникальныйИдентификатор (UUID/GUID), числовых кодов строк и подчиненных справочников, а также рассмотрим особенности работы с ними на уровне базы данных и языка запросов.
Рассмотрим классический бизнес-процесс обработки клиентских запросов менеджерами по закупкам:
Предложения). В нем фиксируется исходный запрос клиента, например: «Резистор 0,5 Ом — 100 шт.». Каждой строке присваивается уникальный идентификатор связи — СтрокаИД.ПроработкаПозиций. Поскольку одну и ту же позицию запроса можно закупить у разных поставщиков или предложить аналоги, одна строка исходного запроса может «расщепиться» на несколько строк проработки. Каждой такой строке проработки присваивается свой идентификатор — СтрокаИДПроработки.СтатусыПозиций, который связан со строками проработки по ключу СтрокаИДПроработки.Выясним, какой тип данных лучше всего выбрать для полей СтрокаИД и СтрокаИДПроработки, чтобы обеспечить максимальную производительность, масштабируемость системы и чистоту архитектуры.
Традиционный подход «старой школы» 1С заключается в создании подчиненного справочника (например, справочник ПозицииПредложений, подчиненный справочнику или документу Предложения). В таком случае связь осуществляется через стандартный ссылочный тип.
Преимущества:
Недостатки:
Поэтому для транзакционных и промежуточных данных использование справочников часто называют созданием «чебурашек» — избыточных объектов метаданных, которых лучше избегать.
Использование GUID (Globally Unique Identifier) позволяет связывать записи напрямую в регистрах сведений без создания промежуточных справочников. Поля связи СтрокаИД и СтрокаИДПроработки создаются с типом УникальныйИдентификатор.
Преимущества:
Новый УникальныйИдентификатор().УникальныйИдентификатор транслируется в высокоэффективный бинарный тип binary(16) (16 байт). Это гораздо производительнее, чем хранение UUID в виде строки nvarchar(36), которая занимает 72 байта и существенно замедляет операции JOIN в запросах.Недостатки и нюансы работы:
Ранее в платформе 1С существовали жесткие ограничения на использование UUID в запросах. Разберем, как эти проблемы решены в современных версиях платформы.
В старых релизах платформы нельзя было получить UUID из ссылки прямо в запросе или сгенерировать его «на лету». Разработчикам приходилось прибегать к строковым преобразованиям. Начиная с версии 8.3.22, в языке запросов появились штатные функции:
УникальныйИдентификатор(Ссылка) — позволяет получить UUID любого ссылочного объекта непосредственно в запросе.Ууид() — генерирует новое случайное значение типа UUID на уровне СУБД в процессе выполнения запроса.Рассмотрим практический пример использования UUID во временных таблицах. Важно помнить об одном ограничении платформы: нельзя передавать таблицу значений с колонкой типа УникальныйИдентификатор в качестве параметра запроса для построения временной таблицы. Платформа выдаст ошибку: «Тип не может быть выбран в запросе».
Разберем по шагам, как обойти это ограничение. Для этого перед передачей таблицы значений в запрос мы должны временно преобразовать колонку UUID в строковый тип, а в самом запросе (при необходимости) связать ее с реальными таблицами, где UUID хранится в родном типе. Посмотрим на пример кода:
// 1. Подготавливаем Таблицу Значений для запроса
ТЗ_Данные = Новый ТаблицаЗначений;
ТЗ_Данные.Колонки.Добавить("СтрокаИД_Строка", Новый ОписаниеТипов("Строка",,,, Новый КвалификаторыСтроки(36)));
ТЗ_Данные.Колонки.Добавить("НоменклатураЗапрос", Новый ОписаниеТипов("Строка",,,, Новый КвалификаторыСтроки(150)));
ТЗ_Данные.Колонки.Добавить("Количество", Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 3)));
// Заполняем таблицу данными, преобразуя UUID в строку
НоваяСтрока = ТЗ_Данные.Добавить();
НоваяСтрока.СтрокаИД_Строка = Строка(Новый УникальныйИдентификатор());
НоваяСтрока.НоменклатураЗапрос = "Резистор 0,5Ом";
НоваяСтрока.Количество = 100;
// 2. Передаем таблицу в запрос
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ТЗ.СтрокаИД_Строка КАК СтрокаИД_Строка,
| ТЗ.НоменклатураЗапрос КАК НоменклатураЗапрос,
| ТЗ.Количество КАК Количество
|ПОМЕСТИТЬ ВТ_ИсходныеДанные
|ИЗ
| &ТЗ_Данные КАК ТЗ
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| ВТ.НоменклатураЗапрос,
| ВТ.Количество,
| Проработка.Номенклатура КАК НоменклатураПредложенная,
| Проработка.КоличествоПредложено КАК КоличествоПредложено
|ИЗ
| ВТ_ИсходныеДанные КАК ВТ
| // Выполняем соединение с регистром сведений по UUID, приведенному к строке
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ПроработкаПозиций КАК Проработка
| ПО ВТ.СтрокаИД_Строка = ВЫРАЗИТЬ(Проработка.СтрокаИД КАК СТРОКА(36))";
Запрос.УстановитьПараметр("ТЗ_Данные", ТЗ_Данные);
РезультатЗапроса = Запрос.Выполнить();
Если же временные таблицы формируются внутри запроса исключительно из таблиц базы данных (без передачи внешней ТЗ), никаких ограничений на джоины по полям типа УникальныйИдентификатор нет — СУБД связывает их моментально.
Проанализируем, как эта задача решается разработчиками самой фирмы 1С в типовых конфигурациях (1С:Управление торговлей, 1С:ERP, 1С:Комплексная автоматизация).
В современных ERP-решениях для связи табличных частей документов с движениями по регистрам сведений часто используется комбинированный подход:
КодСтроки (тип Число) — последовательный номер строки. Он удобен тем, что его легко «проверить глазами» при отладке и анализе таблиц.ИдентификаторСтроки (тип УникальныйИдентификатор) — гарантирует абсолютную уникальность связи в распределенных транзакциях и при сложных обменах данными.Для автоматического заполнения таких связей в типовом коде используется специализированный инструментарий общего назначения, например метод ОбщегоНазначенияУТ.ДобавитьИдентификаторСтрокВТаблицу. Это позволяет сохранять жесткую привязку движений регистров к конкретным строкам документов даже при их пересортировке или частичном удалении.
Для наглядности сопоставим все три архитектурных подхода в таблице:
| Критерий сравнения | Справочники-«чебурашки» | Уникальный Идентификатор (UUID) | Числовые коды (КодСтроки) |
|---|---|---|---|
| Нагрузка на базу данных | Высокая (создаются лишние ссылочные объекты) | Минимальная (хранится как 16 байт бинарных данных) | Минимальная (хранится как число) |
| Удобство отладки и чтения глазами | Отличное (видны наименования элементов) | Низкое (длинная шестнадцатеричная строка) | Хорошее (простые числа: 1, 2, 3...) |
| Простота генерации ключа | Средняя (требуется запись нового объекта) | Очень простая (Новый УникальныйИдентификатор()) |
Требует вычисления максимума в рамках документа/таблицы |
| Работа в распределенных базах (РИБ) | Отличная | Идеальная (коллизии исключены по определению) | Высокий риск коллизий без привязки к родителю |
Подводя итог, можно дать следующие рекомендации по выбору инструмента связки:
УникальныйИдентификатор. Это избавит базу данных от «мусора», обеспечит максимальную скорость транзакций и упростит логику закрытия/удаления документов.КодСтроки, как это сделано в ERP-системах фирмы 1С.