При работе в конфигураторе 1С:Предприятие 8.3 разработчики часто сталкиваются с ситуацией, когда необходимо создать реквизит, способный хранить как ссылку на объект (например, справочник или документ), так и произвольное текстовое описание. Такой подход реализуется через составной тип данных. Однако стандартный интерфейс настройки типа может сбить с толку: если для обычной строки флаг неограниченной длины и поле количества символов находятся на виду, то в составном типе эти настройки «прячутся». Рассмотрим подробно, как управлять длиной строки в таких случаях и почему к архитектуре «строка + ссылка» нужно относиться с осторожностью.
Разберем по шагам процесс изменения длины строки, когда она включена в составной тип вместе с другими объектами. Проблема автора темы заключалась в том, что при выборе нескольких типов поле настройки длины кажется недоступным. На самом деле, оно контекстно зависит от выбранного элемента в списке типов.
Тип.Строка и установим на нем флажок.Проанализируем ситуацию, почему многие не замечают это поле. В обычном режиме (когда тип только один — строка) параметры отображаются сразу в окне свойств реквизита. В составном же типе параметры индивидуальны для каждого примитивного типа (числа, даты или строки), поэтому платформа показывает их только при активации конкретной строки в списке.
Многие разработчики замечают, что при использовании составного типа данных флажок «Неограниченная длина» для строки становится недоступным или его установка приводит к ошибке при сохранении конфигурации. Выясним причину этого ограничения.
Это связано с тем, как данные хранятся на уровне СУБД (SQL). Когда реквизит имеет фиксированный тип «Строка (неограниченная)», 1С создает в таблице базы данных специальное поле типа NTEXT или NVARCHAR(MAX). Однако для составного типа платформа должна хранить не только само значение, но и информацию о его типе.
Если мы попытаемся смешать ссылочный тип (GUID) и неограниченную строку в одном поле, структура таблиц станет чрезмерно сложной. Платформа 1С накладывает жесткое ограничение: строка в составе составного типа всегда должна иметь фиксированную максимальную длину. Если вам действительно нужен огромный текст, придется пересмотреть архитектуру решения.
В процессе обсуждения опытные разработчики справедливо указывают на то, что использование составного типа, смешивающего примитивные (строка) и ссылочные (справочник) типы, может привести к проблемам в будущем (так называемым «аукам»). Рассмотрим подробнее, с какими сложностями мы можем столкнуться:
Реквизит.Наименование) в SQL-запросе происходит неявное левое соединение (LEFT JOIN) со всеми таблицами, входящими в состав типа. Если в типе указано 10 справочников, запрос станет очень «тяжелым».ВЫРАЗИТЬ(... КАК ...), чтобы корректно обрабатывать значения. Разделение логики «когда это строка» и «когда это ссылка» усложняет код программных модулей.Если задача позволяет, лучше воспользоваться одним из проверенных методов проектирования данных, которые избавят нас от использования «опасного» составного типа.
Вместо одного реквизита ДополнительнаяИнформация с составным типом, создадим два отдельных реквизита объекта:
ОбъектИнформации (тип: СправочникСсылка, ДокументСсылка).ТекстовоеОписание (тип: Строка, можно неограниченной длины).Для пользователя на форме это можно представить как одно поле ввода (через реквизит формы), но в базе данных они будут храниться чисто и раздельно. Это упростит построение отчетов и обеспечит высокую скорость работы базы.
Разберем технический трюк, который позволяет сохранить удобство для пользователя, не портя структуру данных. Мы можем создать на форме реквизит формы (не путать с реквизитом объекта) с составным типом. Посмотрим на пример реализации логики:
В процедуре ПриЧтенииНаСервере мы заполняем реквизит формы из двух физических полей объекта:
&НаСервере
Процедура ПриЧтенииНаСервере(ТекущийОбъект)
Если ЗначениеЗаполнено(ТекущийОбъект.ОбъектИнформации) Тогда
СоставнойРеквизитФормы = ТекущийОбъект.ОбъектИнформации;
Иначе
СоставнойРеквизитФормы = ТекущийОбъект.ТекстовоеОписание;
КонецЕсли;
КонецПроцедуры
А в процедуре ПередЗаписьюНаСервере мы распределяем данные обратно:
&НаСервере
Процедура ПередЗаписьюНаСервере(ТекущийОбъект)
ТипЗначения = ТипЗнч(СоставнойРеквизитФормы);
Если ТипЗначения = Тип("Строка") Тогда
ТекущийОбъект.ТекстовоеОписание = СоставнойРеквизитФормы;
ТекущийОбъект.ОбъектИнформации = Справочники.Контрагенты.ПустаяСсылка();
Иначе
ТекущийОбъект.ОбъектИнформации = СоставнойРеквизитФормы;
ТекущийОбъект.ТекстовоеОписание = "";
КонецЕсли;
КонецПроцедуры
Этот метод позволяет обойти ограничение на длину строки (в поле ТекстовоеОписание она может быть любой) и при этом оставить интерфейс привычным для пользователя. Рассмотрим этот вариант как наиболее профессиональный с точки зрения архитектуры 1С:Предприятия.
Мы выяснили, что увеличить длину строки в составном типе можно в окне выбора типов, просто выделив нужный пункт списка. Однако, помня о десятилетнем опыте коллег и специфике работы СУБД, всегда стоит задаться вопросом: действительно ли здесь нужен составной тип? В большинстве случаев разделение данных на два реквизита или использование механизмов ПВХ (Планов видов характеристик) окажется более надежным и производительным решением в долгосрочной перспективе.