Почему обрезается строка при использовании типа «Неопределенный» в 1С 7.7 и как это обойти?

Программист 1С v7.7 IT и автоматизация бизнеса
← На главную

В процессе разработки на платформе 1С:Предприятие 7.7 программисты часто сталкиваются с необходимостью сделать реквизит табличной части «универсальным». Для этого используется тип данных Неопределенный. Однако при попытке записать в такой реквизит строку длиной более 20-23 символов, пользователи обнаруживают, что после сохранения и повторного открытия документа данные оказываются обрезанными. Рассмотрим подробнее, почему это происходит и какими способами можно решить эту проблему.

Выясняем техническую причину ограничения

Для начала проанализируем, как платформа 1С 7.7 хранит данные типа Неопределенный. На уровне базы данных (будь то файлы DBF или таблицы SQL) под такой реквизит всегда выделяется фиксированное поле длиной 23 символа. Это ограничение заложено глубоко в ядре системы и не может быть изменено настройками метаданных.

Распределение этих 23 символов выглядит следующим образом:

  1. Первые 2 символа зарезервированы под внутренний идентификатор типа данных (строка, число, справочник, документ и т.д.).
  2. Оставшиеся 21 символ отводятся непосредственно под значение.

Если вы записываете ссылку на справочник или документ, 1С сохраняет его внутренний идентификатор (ID), который легко умещается в отведенное пространство. Но если вы пытаетесь сохранить строку, то всё, что не влезло в 21-22 символа, просто отсекается. При этом функция НазначитьТип("Реквизит", "Строка", 150) лишь меняет поведение поля ввода на форме (позволяя пользователю напечатать 150 символов), но никак не влияет на физическую структуру таблицы в базе данных.

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

Разберем самый популярный и надежный метод. Суть его заключается в создании дополнительного скрытого реквизита в табличной части, который будет иметь тип Строка нужной вам длины (например, 150 символов). Рассмотрим по шагам, как это реализовать:

  1. В метаданных документа создаем реквизит табличной части ДокументыЗачета (тип Неопределенный) и реквизит ДокументыЗачетаСтрока (тип Строка, длина 150).
  2. На форме оставляем только поле, связанное с ДокументыЗачета.
  3. В модуле формы прописываем логику синхронизации при записи и открытии.

Проанализируем пример кода для предопределенных процедур:


Процедура ПриЗаписи()
    ВыбратьСтроки();
    Пока ПолучитьСтроку() = 1 Цикл
        // Если в универсальном реквизите выбрана строка, копируем её в длинный реквизит
        Если ТипЗначенияСтр(ДокументыЗачета) = "Строка" Тогда
            ДокументыЗачетаСтрока = ДокументыЗачета;
        Иначе
            ДокументыЗачетаСтрока = ""; // Очищаем, если там ссылка
        КонецЕсли;
    КонецЦикла;
КонецПроцедуры

Процедура ПриОткрытии()
    ВыбратьСтроки();
    Пока ПолучитьСтроку() = 1 Цикл
        // Восстанавливаем длинную строку из скрытого реквизита
        Если ПустаяСтрока(ДокументыЗачетаСтрока) = 0 Тогда
            НазначитьТип("ДокументыЗачета", "Строка", 150);
            ДокументыЗачета = ДокументыЗачетаСтрока;
        КонецЕсли;
    КонецЦикла;
КонецПроцедуры

Способ 2: Вывод данных через вычисляемую колонку

Если вам нужно только корректное отображение в табличной части, а редактирование происходит в отдельном окне или через специальную обработку, можно использовать текстовую колонку на форме. Посмотрим на пример реализации:

Добавьте в таблицу формы текстовое поле (без привязки к реквизиту) и в поле «Формула» укажите вызов функции, например: глПоказатьРеквизит(НомерСтроки). В модуле формы опишем эту функцию:


Функция глПоказатьРеквизит(Ном)
    // Обращаемся к текущей строке через контекст
    ПолучитьСтрокуПоНомеру(Ном);
    Если ПустаяСтрока(ДокументыЗачетаСтрока) = 0 Тогда
        Возврат СокрЛП(ДокументыЗачетаСтрока);
    Иначе
        Возврат ДокументыЗачета; // Здесь будет представление документа или справочника
    КонецЕсли;
КонецФункции

Этот метод позволяет избежать «каши» в данных, так как основной реквизит типа Неопределенный будет использоваться только для хранения ссылок на объекты, а длинные строки всегда будут браться из параллельного поля.

Способ 3: Вспомогательный справочник «Хранилище строк»

Этот вариант считается наиболее «профессиональным» в среде разработчиков 1С 7.7, так как он не раздувает размер основной таблицы документа строковыми полями. Рассмотрим ситуацию: если у вас сотни строк в документе и длинные строки встречаются редко, хранить пустые поля по 150 символов в каждой строке накладно.

Алгоритм действий:

  1. Создаем новый справочник ХранилищеТекстов с одним реквизитом Текст (тип Строка, длина неограниченна).
  2. В реквизит табличной части ДокументыЗачета вместо самой строки записываем ссылку на элемент этого справочника.
  3. Поскольку ссылка на справочник занимает всего 13 символов, она идеально помещается в 23-символьное поле типа Неопределенный.

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

Способ 4: Использование механизма ОбработкаВыбораЗначения

Чтобы обеспечить удобство работы пользователя, проанализируем, как правильно перехватить ввод данных в универсальное поле. Мы можем использовать предопределенную процедуру ПриНачалеВыбораЗначения.


Процедура ПриНачалеВыбораЗначения(ИдентРеквизита, ФлагСтандОбр)
    Если ИдентРеквизита = "ДокументыЗачета" Тогда
        // Запрашиваем у пользователя, что он хочет ввести: Документ или Строку
        СписокТипов = СоздатьОбъект("СписокЗначений");
        СписокТипов.ДобавитьЗначение("Документ", "Выбрать реализацию");
        СписокТипов.ДобавитьЗначение("Строка", "Ввести текст вручную");
        
        ВыбрЗнач = "";
        Если СписокТипов.ВыбратьЗначение(ВыбрЗнач, "Тип данных", , , 1) = 1 Тогда
            Если ВыбрЗнач = "Документ" Тогда
                // Стандартный выбор документа
            Иначе
                ФлагСтандОбр = 0;
                ВведитеТекст = "";
                Если ВвестиСтроку(ВведитеТекст, "Введите пояснение", 150) = 1 Тогда
                    НазначитьТип("ДокументыЗачета", "Строка", 150);
                    ДокументыЗачета = ВведитеТекст;
                    // Не забываем обновить скрытый строковый реквизит!
                    ДокументыЗачетаСтрока = ВведитеТекст; 
                КонецЕсли;
            КонецЕсли;
        КонецЕсли;
    КонецЕсли;
КонецПроцедуры

Важные замечания по сериализации

Иногда встречается совет использовать функции ЗначениеВСтрокуВнутр() и ЗначениеИзСтрокиВнутр() для упаковки данных в одну строку. Будьте осторожны: внутреннее представление объекта 1С почти всегда длиннее 23 символов. Если вы попытаетесь применить этот метод к реквизиту типа Неопределенный, вы получите «битую» строку, которую система не сможет расшифровать обратно. Данный метод подходит только если вы записываете результат в поле типа Строка неограниченной длины.

Подводя итог, можно сказать, что ограничение типа Неопределенный — это особенность архитектуры 1С 7.7. Для корректной работы с длинными строками всегда используйте «связку» из универсального реквизита (для ссылок) и дополнительного строкового поля или справочника (для текстов). Это гарантирует сохранность данных и стабильную работу вашей конфигурации.

← На главную