ВнешнийИсточникДанныхТаблицаОбъект.<Имя внешнего источника>.<Имя таблицы внешнего источника данных>.Метаданные

Методы · Metadata

Получает объект описания метаданных таблицы.

Синтаксис

Метаданные()
Полное описание, параметры и ограничения

ВнешнийИсточникДанныхТаблицаОбъект.<Имя внешнего источника>.<Имя таблицы внешнего источника данных>.Метаданные (ExternalDataSourceTableObject.<External source name>.<External data source table name>.Metadata)

ВнешнийИсточникДанныхТаблицаОбъект.<Имя внешнего источника>.<Имя таблицы внешнего источника данных> (ExternalDataSourceTableObject.<External source name>.<External data source table name>)

Метаданные (Metadata)

Доступен, начиная с версии 8.2.

Синтаксис:
Метаданные()
Возвращаемое значение:
Тип: ОбъектМетаданных: Таблица.

Описание:

Получает объект описания метаданных таблицы.

Доступность:

Сервер, толстый клиент, внешнее соединение.

Использование в версии:

Доступен, начиная с версии 8.2.

Методическая информация

Практические примеры

Собственный SQL-товар: реальная ссылка, черновик, копия, блокировка и обновление

Создаем свою строку SQL отдельным полным seed-блоком, получаем реальную платформенную ссылку запросом по обоим собственным UUID, изменяем только этот объект и удаляем его после readback. Представление rawKey для ссылки не угадывается.

Где и как запускать

Полный серверный общий модуль новой собственной CF, отдельно полный модуль объекта Товары85 и модуль своей формы. SQL seed исполняется человеком только в своей VM, здесь ни один пример не исполнялся.

Подготовка

  1. Не запускайте в рабочей базе. Создайте новую изолированную Windows VM без рабочих источников и сетевых маршрутов наружу, собственный экземпляр SQL Server на localhost и новую пустую файловую базу 1С 8.5.1.1343 с конфигурацией УчебныеВнешниеТаблицы85. Никакие команды из урока в этой работе не выполнялись.

  2. Собственный Windows-пользователь Уч85SQL запускает только этот учебный клиент/SQL. В базе 1С создайте единственного пользователя Уч85SQL с ПолнымиПравами. SQL Windows-аутентификация должна давать ему права на новую собственную базу; не выдавайте доступ к чужим базам. Для начала можно использовать отдельный собственный локальный экземпляр без иных пользовательских баз.

  3. В SSMS именно на своем localhost экземпляре откройте master и вручную выполните отдельный блок SQL ниже. Он отказывается заменять существующую Уч85ВнешнийSQL, создает ровно две новые таблицы dbo.guide_lines и dbo.guide_items. SQL-блок — подготовка среды, не BSL. Имена/типы/PK/CHECK реальны, миграции существующей БД и DROP DATABASE отсутствуют.

  4. Через ODBC Data Sources нужной разрядности процесса 1С создайте только собственный System DSN Уч85LocalSQL: SQL Server на localhost, default database Уч85ВнешнийSQL, Windows authentication. Настройте реальный сертификат/доверие драйвера внутри VM; не отключайте общую TLS-проверку и не перепривязывайте существующий DSN. Успешная ODBC проверка относится только к вашему DSN, не доказывает запуск BSL.

  5. В Конфигураторе: ВнешниеИсточникиДанных → УчебныйSQL85. Режим управления блокировкой данных Автоматический; общая строка соединения сначала пустая. Таблица Строки85: имя dbo.guide_lines, НеобъектныеДанные, ТолькоЧтение=Ложь. Поля Метка=run_id Строка36, Номер=line_no Число9.0, Название=title Строка100, Количество=quantity Число9.0; Null запрещен. ПоляКлюча и ПоляБлокировкиДанных: Метка,Номер. Название: проверка заполнения показывать ошибку. Не используйте nullable, identity, computed, timestamp или server-generated поля в этом опыте.

  6. Таблица Товары85: имя dbo.guide_items, ОбъектныеДанные, ТолькоЧтение=Ложь. Поля Код=item_id Строка36, Метка=run_id Строка36, Название=title Строка100, Количество=quantity Число9.0; Null запрещен. Единственное ПолеКлюча Код, поля блокировки Код, представление Название, родитель/версия не заданы. Не включайте автообновление/формы списка, работающие без ownUUID фильтра.

  7. В Функции внешнего источника создайте МеткаСтенда85: ВозвращаетЗначение=Истина, Тип=Строка128, ВыражениеВИсточникеДанных=SELECT CAST(DB_NAME() AS nvarchar(128)). Код вызовет реальную функцию, заданную в метаданных, и сравнит имя базы с Уч85ВнешнийSQL. Кубов нет: API Кубы здесь дает менеджер дерева, не запускает фиктивный OLAP-запрос.

  8. Создайте серверный общий модуль УчебныеВнешниеТаблицы85, Сервер=Истина, Клиент=Ложь; вставьте весь основной блок на уровень модуля, не внутрь процедуры. Создайте учебную обработку с управляемой формой и командой; серверный обработчик команды вызывает УчебныеВнешниеТаблицы85.ВыполнитьУчебныеСтроки85(). Режим последовательный, единственный сеанс/пользователь, нет расширений, регламентных заданий, подписок, иной бизнес-метадаты.

  9. Для объекта таблицы замените модуль общего модуля основным блоком именно этого урока; одинаковый COMMON дважды в один модуль не вставляйте. ВыполнитьУчебныйТовар85 принимает только два UUID собственной строки, созданной отдельным SQL seed-блоком ниже, не неизвестный ИсходныйОбъект и не произвольную ссылку рабочей базы.

  10. В SSMS своей Уч85ВнешнийSQL выполните SQL seed-блок: NEWID генерирует run/item UUID, INSERT создает ровно одну собственную Уч85Книга с количеством3, SELECT выводит оба ключа. Сохраните их; второй запуск создает другую строку, поэтому seed не повторяйте автоматически. Не вводите чужие GUID.

  11. В таблице Товары85 создайте макет Паспорт85 типа ТекстовыйДокумент, ровно одна строка Уч85ВнешнийSQL | dbo.guide_items | own. Создайте модуль объекта Товары85 и вставьте весь отдельный BSL-block ОбработкаЗаполнения/ОбработкаПроверкиЗаполнения. Другие события/подписки пустые; обновите только собственную CF.

  12. У формы собственной обработки создайте реквизиты Метка85 и Код85 типа Строка36, поля ввода с теми же реквизитами, команду ВыполнитьТовар85 и кнопку. Вставьте отдельный полный модуль формы ниже; клиент передает запрос серверному обработчику, затем серверный общий модуль. Введите обе реальные строки UUID из SQL seed SELECT и нажмите команду ровно один раз.

Процедура ПроверитьСвойПустойСтенд()
    Если Метаданные.Справочники.Количество() <> 0 Или Метаданные.Документы.Количество() <> 0 Или Метаданные.Перечисления.Количество() <> 0 Или Метаданные.РегистрыСведений.Количество() <> 0 Или Метаданные.РегистрыНакопления.Количество() <> 0 Или Метаданные.РегистрыБухгалтерии.Количество() <> 0 Или Метаданные.РегистрыРасчета.Количество() <> 0 Или Метаданные.ПланыВидовХарактеристик.Количество() <> 0 Или Метаданные.ПланыВидовРасчета.Количество() <> 0 Или Метаданные.ПланыСчетов.Количество() <> 0 Или Метаданные.ПланыОбмена.Количество() <> 0 Или Метаданные.Последовательности.Количество() <> 0 Или Метаданные.БизнесПроцессы.Количество() <> 0 Или Метаданные.Задачи.Количество() <> 0 Или Метаданные.ОбщиеРеквизиты.Количество() <> 0 Или Метаданные.ПодпискиНаСобытия.Количество() <> 0 Или Метаданные.РегламентныеЗадания.Количество() <> 0 Или Метаданные.ВнешниеИсточникиДанных.Количество() <> 1 Тогда
        ВызватьИсключение "Нужен только свой новый пустой учебный стенд";
    КонецЕсли;
    Если Метаданные.ЕстьИзмененияРасширениямиКонфигурации() Тогда
        ВызватьИсключение "Свой сеанс не должен изменяться расширениями";
    КонецЕсли;
    Источники = Новый Массив;
    Источники.Добавить(ИсточникРасширенийКонфигурации.БазаДанных);
    Источники.Добавить(ИсточникРасширенийКонфигурации.СеансАктивные);
    Источники.Добавить(ИсточникРасширенийКонфигурации.СеансОтключенные);
    Для Каждого Источник Из Источники Цикл
        Расширения = РасширенияКонфигурации.Получить(, Источник);
        Если ТипЗнч(Расширения) <> Тип("Массив") Тогда
            ВызватьИсключение "Native список расширений должен иметь тип Массив";
        КонецЕсли;
        Если Расширения.Количество() <> 0 Тогда
            ВызватьИсключение "В своём новом стенде нет расширений базы или сеанса";
        КонецЕсли;
    КонецЦикла;
    Если ТранзакцияАктивна() Тогда
        ВызватьИсключение "Чужая или вложенная активная транзакция не допускается";
    КонецЕсли;
КонецПроцедуры

Процедура ПроверитьОписаниеТаблицы85(Таблица, ИмяSQL, ТипДанных, ОписанияПолей, ИменаКлючей)
    Если Таблица.ИмяВИсточникеДанных <> ИмяSQL Или Таблица.ТипДанныхТаблицы <> ТипДанных Или Таблица.ТолькоЧтение
        Или Таблица.Поля.Количество() <> ОписанияПолей.Количество() Или Таблица.ПоляКлюча.Количество() <> ИменаКлючей.Количество()
        Или Таблица.ВидТаблицы <> Метаданные.СвойстваОбъектов.ВидТаблицыВнешнегоИсточникаДанных.Таблица Тогда
        ВызватьИсключение "Описание собственной таблицы не соответствует учебному SQL";
    КонецЕсли;
    Для Каждого Описание Из ОписанияПолей Цикл
        Поле = Таблица.Поля.Найти(Описание.Ключ);
        Если Поле = Неопределено Тогда
            ВызватьИсключение "Нет заранее созданного собственного поля";
        КонецЕсли;
        Детали = СтрРазделить(Описание.Значение, ",");
        Если Поле.ИмяВИсточникеДанных <> Детали[0] Или Поле.РазрешитьNull Или Поле.ТолькоЧтение
            Или Поле.Тип.Типы().Количество() <> 1 Или Не Поле.Тип.СодержитТип(Тип(Детали[1])) Тогда
            ВызватьИсключение "Поле не соответствует собственному SQL имени/типу";
        КонецЕсли;
        Если Детали[1] = "Строка" Тогда
            Если Поле.Тип.КвалификаторыСтроки.Длина <> Число(Детали[2]) Тогда
                ВызватьИсключение "Неверная длина собственного строкового поля";
            КонецЕсли;
        Иначе
            Если Поле.Тип.КвалификаторыЧисла.Разрядность <> 9 Или Поле.Тип.КвалификаторыЧисла.РазрядностьДробнойЧасти <> 0 Тогда
                ВызватьИсключение "Нужно числовое собственное поле9.0";
            КонецЕсли;
        КонецЕсли;
    КонецЦикла;
    Для Индекс = 0 По ИменаКлючей.Количество() - 1 Цикл
        Если Таблица.ПоляКлюча[Индекс].Имя <> ИменаКлючей[Индекс] Тогда
            ВызватьИсключение "Порядок собственного ключа не совпадает с SQL PK";
        КонецЕсли;
    КонецЦикла;
КонецПроцедуры

Функция ОткрытьСвойИсточник85()
    ПроверитьСвойПустойСтенд();
    Пользователь = ПользователиИнформационнойБазы.ТекущийПользователь();
    Если Пользователь = Неопределено Или Пользователь.Имя <> "Уч85SQL" Тогда
        ВызватьИсключение "Войдите единственным собственным учебным пользователем Уч85SQL";
    КонецЕсли;
    МетаИсточник = Метаданные.ВнешниеИсточникиДанных.Найти("УчебныйSQL85");
    Если МетаИсточник = Неопределено Или МетаИсточник.Таблицы.Количество() <> 2 Или МетаИсточник.Кубы.Количество() <> 0 Тогда
        ВызватьИсключение "Нужны ровно две собственные таблицы без кубов";
    КонецЕсли;
    Если МетаИсточник.Таблицы.Найти("Строки85") = Неопределено Или МетаИсточник.Таблицы.Найти("Товары85") = Неопределено Тогда
        ВызватьИсключение "Создайте учебные описания Строки85 и Товары85";
    КонецЕсли;
    ПоляСтрок = Новый Структура("Метка,Номер,Название,Количество", "run_id,Строка,36", "line_no,Число,9", "title,Строка,100", "quantity,Число,9");
    ПоляТоваров = Новый Структура("Код,Метка,Название,Количество", "item_id,Строка,36", "run_id,Строка,36", "title,Строка,100", "quantity,Число,9");
    ПроверитьОписаниеТаблицы85(МетаИсточник.Таблицы.Найти("Строки85"), "dbo.guide_lines", Метаданные.СвойстваОбъектов.ТипДанныхТаблицыВнешнегоИсточникаДанных.НеобъектныеДанные, ПоляСтрок, СтрРазделить("Метка,Номер", ","));
    ПроверитьОписаниеТаблицы85(МетаИсточник.Таблицы.Найти("Товары85"), "dbo.guide_items", Метаданные.СвойстваОбъектов.ТипДанныхТаблицыВнешнегоИсточникаДанных.ОбъектныеДанные, ПоляТоваров, СтрРазделить("Код", ","));
    МетаФункция = МетаИсточник.Функции.Найти("МеткаСтенда85");
    Если МетаФункция = Неопределено Тогда
        ВызватьИсключение "Нет собственной заранее описанной функции";
    КонецЕсли;
    Если Не МетаФункция.ВозвращаетЗначение Или МетаФункция.ВыражениеВИсточникеДанных <> "SELECT CAST(DB_NAME() AS nvarchar(128))"
        Или МетаФункция.Тип.Типы().Количество() <> 1 Или Не МетаФункция.Тип.СодержитТип(Тип("Строка"))
        Или МетаФункция.Тип.КвалификаторыСтроки.Длина <> 128 Тогда
        ВызватьИсключение "Функция должна только читать имя собственной базы";
    КонецЕсли;
    Источник = ВнешниеИсточникиДанных.УчебныйSQL85;
    Если Источник.ТранзакцияАктивна() Или Источник.ПолучитьСостояние() <> СостояниеВнешнегоИсточникаДанных.Отключен Тогда
        ВызватьИсключение "Чужое или ранее открытое соединение не используется и не закрывается";
    КонецЕсли;
    Если ТипЗнч(Источник.Кубы) <> Тип("ВнешнийИсточникДанныхКубыМенеджер.УчебныйSQL85") Тогда
        ВызватьИсключение "Не получен локальный менеджер кубов; кубов в собственном дереве нет";
    КонецЕсли;
    Общие = Источник.ПолучитьОбщиеПараметрыСоединения();
    Пользовательские = Источник.ПолучитьПараметрыСоединенияПользователя(Пользователь.Имя);
    Сеансовые = Источник.ПолучитьПараметрыСоединенияСеанса();
    Уровни = Новый Массив;
    Уровни.Добавить(Общие);
    Уровни.Добавить(Пользовательские);
    Уровни.Добавить(Сеансовые);
    Для Каждого Параметры Из Уровни Цикл
        Если Параметры.СтрокаСоединения <> Неопределено И Параметры.СтрокаСоединения <> "" И Параметры.СтрокаСоединения <> "DSN=Уч85LocalSQL;" Тогда
            ВызватьИсключение "Нельзя заменять непустое чужое подключение";
        КонецЕсли;
        Параметры.СУБД = "MSSQLServer";
        Параметры.СтрокаСоединения = "DSN=Уч85LocalSQL;";
        Параметры.АутентификацияОС = Истина;
        Параметры.АутентификацияСтандартная = Ложь;
        Параметры.ИмяПользователя = "";
        Параметры.Пароль = "";
    КонецЦикла;
    Источник.УстановитьОбщиеПараметрыСоединения(Общие);
    Источник.УстановитьПараметрыСоединенияПользователя(Пользователь.Имя, Пользовательские);
    Источник.УстановитьПараметрыСоединенияСеанса(Сеансовые);
    Если Источник.ПолучитьОбщиеПараметрыСоединения().СтрокаСоединения <> "DSN=Уч85LocalSQL;"
        Или Источник.ПолучитьПараметрыСоединенияПользователя(Пользователь.Имя).СтрокаСоединения <> "DSN=Уч85LocalSQL;"
        Или Источник.ПолучитьПараметрыСоединенияСеанса().СтрокаСоединения <> "DSN=Уч85LocalSQL;" Тогда
        ВызватьИсключение "Собственные настройки трёх уровней не прочитаны обратно";
    КонецЕсли;
    СоединениеМоглоОткрыться = Ложь;
    Попытка
        СоединениеМоглоОткрыться = Истина;
        Источник.УстановитьСоединение();
        Если Источник.ПолучитьСостояние() <> СостояниеВнешнегоИсточникаДанных.Подключен Тогда
            ВызватьИсключение "Открытие собственного источника не подтверждено";
        КонецЕсли;
        Если Источник.МеткаСтенда85() <> "Уч85ВнешнийSQL" Тогда
            ВызватьИсключение "Источник не подтвердил собственную базу SQL";
        КонецЕсли;
    Исключение
        Если СоединениеМоглоОткрыться Тогда
            Попытка
                Источник.РазорватьСоединение();
            Исключение
                Сообщить("Разрыв своего неудавшегося подключения тоже не подтвержден");
            КонецПопытки;
        КонецЕсли;
        ВызватьИсключение "Открытие собственного стенда не подтверждено; неизвестный исход не считается успехом";
    КонецПопытки;
    Возврат Источник;
КонецФункции



Функция НайтиСвоюСсылку85(Метка, Код)
    Запрос = Новый Запрос;
    Запрос.Текст = "ВЫБРАТЬ Т.Ссылка КАК Ссылка
    |ИЗ ВнешнийИсточникДанных.УчебныйSQL85.Таблица.Товары85 КАК Т
    |ГДЕ Т.Метка = &Метка И Т.Код = &Код";
    Запрос.УстановитьПараметр("Метка", Метка);
    Запрос.УстановитьПараметр("Код", Код);
    Найденные = Запрос.Выполнить().Выгрузить();
    Если Найденные.Количество() > 1 Тогда
        ВызватьИсключение "Собственный уникальный ключ не уникален";
    КонецЕсли;
    Если Найденные.Количество() = 0 Тогда
        Возврат Неопределено;
    КонецЕсли;
    Возврат Найденные[0].Ссылка;
КонецФункции

Процедура ПроверитьСвойТовар85(Объект, Метка, Код, Количество)
    Если Объект = Неопределено Тогда
        ВызватьИсключение "Собственный SQL-объект отсутствует";
    КонецЕсли;
    Если Объект.Код <> Код Или Объект.Метка <> Метка Или Объект.Название <> "Уч85Книга" Или Объект.Количество <> Количество Тогда
        ВызватьИсключение "Собственные поля товара не совпадают";
    КонецЕсли;
КонецПроцедуры

Процедура ВыполнитьУчебныйТовар85(Метка, Код) Экспорт
    Если ТипЗнч(Метка) <> Тип("Строка") Или ТипЗнч(Код) <> Тип("Строка") Или СтрДлина(Метка) <> 36 Или СтрДлина(Код) <> 36 Тогда
        ВызватьИсключение "Введите оба собственных UUID из SQL-блока создания строки";
    КонецЕсли;
    ПроверкаМетки = Новый УникальныйИдентификатор(Метка);
    ПроверкаКода = Новый УникальныйИдентификатор(Код);
    Если НРег(Строка(ПроверкаМетки)) <> НРег(Метка) Или НРег(Строка(ПроверкаКода)) <> НРег(Код) Тогда
        ВызватьИсключение "Только канонические собственные UUID";
    КонецЕсли;
    Источник = ОткрытьСвойИсточник85();
    Сообщить("Свой опыт: " + Метка + " / " + Код);
    СвояТранзакция = Ложь;
    СвояБлокировка = Ложь;
    Объект = Неопределено;
    Попытка
        Ссылка = НайтиСвоюСсылку85(Метка, Код);
        Если Ссылка = Неопределено Тогда
            ВызватьИсключение "Создайте собственную строку SQL и передайте ее точные UUID";
        КонецЕсли;
        Объект = Ссылка.ПолучитьОбъект();
        ПроверитьСвойТовар85(Объект, Метка, Код, 3);
        Если Объект.ЭтоНовый() Или Объект.Метаданные().Имя <> "Товары85" Или Объект.Ссылка <> Ссылка Тогда
            ВызватьИсключение "Нужен существующий собственный объект правильной таблицы";
        КонецЕсли;
        Макет = Объект.ПолучитьМакет("Паспорт85");
        Если ТипЗнч(Макет) <> Тип("ТекстовыйДокумент") Или СокрЛП(Макет.ПолучитьТекст()) <> "Уч85ВнешнийSQL | dbo.guide_items | own" Тогда
            ВызватьИсключение "Паспорт собственной таблицы не совпадает";
        КонецЕсли;
        Объект.ДополнительныеСвойства.Вставить("УчебнаяМетка", Метка);
        Если Не Объект.ДополнительныеСвойства.Свойство("УчебнаяМетка", МеткаИзСвойств) Или МеткаИзСвойств <> Метка Тогда
            ВызватьИсключение "Не подтверждена собственная временная метка";
        КонецЕсли;
        Черновик = Источник.Таблицы.Товары85.СоздатьОбъект();
        Черновик.Заполнить(Новый Структура("Код,Метка,Название,Количество", Код, Метка, "Уч85Книга", 3));
        Если Не Черновик.ЭтоНовый() Или Не Черновик.ПроверитьЗаполнение() Тогда
            ВызватьИсключение "Собственный незаписанный черновик не прошел проверку";
        КонецЕсли;
        Черновик.УстановитьСсылкуНового(Ссылка);
        Если Черновик.ПолучитьСсылкуНового() <> Ссылка Тогда
            ВызватьИсключение "Ранее установленная реальная ссылка не прочитана обратно";
        КонецЕсли;
        Сообщить("Ссылка уже существует: этот черновик никогда не записывается; при записи действовал бы контроль уникальности");
        Копия = Объект.Скопировать();
        Если Не Копия.ЭтоНовый() Тогда
            ВызватьИсключение "Копирование должно дать новый объект только в памяти";
        КонецЕсли;
        Поля = Новый Массив;
        Поля.Добавить("Количество");
        Копия.УстановитьЗаписываемыеПоля(Поля);
        Копия.УстановитьИзменяемыеПоля(Поля);
        Разрешенные = Копия.ПолучитьИзменяемыеПоля();
        Если Разрешенные.Количество() <> 1 Или Разрешенные[0] <> "Количество" Тогда
            ВызватьИсключение "Не подтвержден переход от устаревшего API к изменяемым полям";
        КонецЕсли;
        Копия.Количество = 4;
        Если Не Копия.Модифицированность() Тогда
            ВызватьИсключение "Измененная копия не отмечена как измененная";
        КонецЕсли;
        Сообщить("Копия и черновик не записаны. Новые raw-key ссылки не угадывались");
        Если Источник.ТранзакцияАктивна() Тогда
            ВызватьИсключение "Чужая транзакция не допускается";
        КонецЕсли;
        Источник.НачатьТранзакцию();
        СвояТранзакция = Истина;
        Объект.Заблокировать();
        СвояБлокировка = Истина;
        Если Не Объект.Заблокирован() Тогда
            ВызватьИсключение "Собственная блокировка не подтверждена";
        КонецЕсли;
        Объект.Прочитать();
        ПроверитьСвойТовар85(Объект, Метка, Код, 3);
        Объект.УстановитьИзменяемыеПоля(Поля);
        Объект.Количество = 4;
        Если Не Объект.Модифицированность() Или Не Объект.ПроверитьЗаполнение() Тогда
            ВызватьИсключение "Проверка собственного изменения не прошла";
        КонецЕсли;
        Объект.Записать();
        ПроверитьСвойТовар85(Ссылка.ПолучитьОбъект(), Метка, Код, 4);
        Объект.Разблокировать();
        СвояБлокировка = Ложь;
        Источник.ЗафиксироватьТранзакцию();
        СвояТранзакция = Ложь;
        Объект = НайтиСвоюСсылку85(Метка, Код).ПолучитьОбъект();
        ПроверитьСвойТовар85(Объект, Метка, Код, 4);
        Если Источник.ТранзакцияАктивна() Тогда
            ВызватьИсключение "Чужая транзакция удаления не допускается";
        КонецЕсли;
        Источник.НачатьТранзакцию();
        СвояТранзакция = Истина;
        Объект.Заблокировать();
        СвояБлокировка = Истина;
        Объект.Прочитать();
        ПроверитьСвойТовар85(Объект, Метка, Код, 4);
        Объект.Удалить();
        Объект.Разблокировать();
        СвояБлокировка = Ложь;
        Если НайтиСвоюСсылку85(Метка, Код) <> Неопределено Тогда
            ВызватьИсключение "Удаление собственного объекта не подтверждено";
        КонецЕсли;
        Источник.ЗафиксироватьТранзакцию();
        СвояТранзакция = Ложь;
        Если НайтиСвоюСсылку85(Метка, Код) <> Неопределено Тогда
            ВызватьИсключение "После фиксации собственный объект остался";
        КонецЕсли;
    Исключение
        СбойЗавершения = Ложь;
        Если СвояБлокировка И Объект <> Неопределено Тогда
            Попытка
                Объект.Разблокировать();
            Исключение
                СбойЗавершения = Истина;
            КонецПопытки;
        КонецЕсли;
        Если СвояТранзакция И Источник.ТранзакцияАктивна() Тогда
            Попытка
                Источник.ОтменитьТранзакцию();
            Исключение
                СбойЗавершения = Истина;
            КонецПопытки;
        КонецЕсли;
        Попытка
            Источник.РазорватьСоединение();
        Исключение
            СбойЗавершения = Истина;
        КонецПопытки;
        Если СбойЗавершения Тогда
            Сообщить("Собственная блокировка, откат или закрытие тоже не подтверждены");
        КонецЕсли;
        ВызватьИсключение "Опыт не завершен. Проверьте только оба собственных UUID; автоматического повторения/чужого удаления нет";
    КонецПопытки;
    Источник.РазорватьСоединение();
    Если Источник.ПолучитьСостояние() <> СостояниеВнешнегоИсточникаДанных.Отключен Тогда
        ВызватьИсключение "Собственное соединение не закрыто";
    КонецЕсли;
    Сообщить("Собственный товар3→4→удален, подтвержден чтением. Черновик/копия SQL не меняли");
КонецПроцедуры
SQL Server: создание собственной новой базы и двух таблиц

Вручную в SSMS своего нового localhost экземпляра. Не BSL, здесь не выполнялось.

Вручную в SSMS своего нового localhost экземпляра. Не BSL, здесь не выполнялось.

IF DB_NAME() <> N'master' THROW 51000, N'Open master on the own isolated local instance', 1;
IF DB_ID(N'Уч85ВнешнийSQL') IS NOT NULL THROW 51001, N'Existing database is not replaced', 1;
GO
CREATE DATABASE [Уч85ВнешнийSQL];
GO
USE [Уч85ВнешнийSQL];
GO
CREATE TABLE dbo.guide_lines (
    run_id nvarchar(36) NOT NULL,
    line_no numeric(9,0) NOT NULL,
    title nvarchar(100) NOT NULL,
    quantity numeric(9,0) NOT NULL,
    CONSTRAINT PK_guide_lines PRIMARY KEY (run_id, line_no),
    CONSTRAINT CK_guide_lines_run CHECK (TRY_CONVERT(uniqueidentifier, run_id) IS NOT NULL),
    CONSTRAINT CK_guide_lines_no CHECK (line_no IN (1,2)),
    CONSTRAINT CK_guide_lines_quantity CHECK (quantity >= 0)
);
CREATE TABLE dbo.guide_items (
    item_id nvarchar(36) NOT NULL,
    run_id nvarchar(36) NOT NULL,
    title nvarchar(100) NOT NULL,
    quantity numeric(9,0) NOT NULL,
    CONSTRAINT PK_guide_items PRIMARY KEY (item_id),
    CONSTRAINT CK_guide_items_id CHECK (TRY_CONVERT(uniqueidentifier, item_id) IS NOT NULL),
    CONSTRAINT CK_guide_items_run CHECK (TRY_CONVERT(uniqueidentifier, run_id) IS NOT NULL),
    CONSTRAINT CK_guide_items_quantity CHECK (quantity >= 0)
);
SELECT DB_NAME() AS own_database, COUNT(*) AS own_user_tables FROM sys.tables;
SQL Server: новый собственный seed-товар с действительными UUID

После создания собственной базы; вручную в своей SSMS. Не BSL, здесь не выполнялось.

После создания собственной базы; вручную в своей SSMS. Не BSL, здесь не выполнялось.

USE [Уч85ВнешнийSQL];
GO
IF DB_NAME() <> N'Уч85ВнешнийSQL' THROW 51002, N'Only the own new database is allowed', 1;
DECLARE @run nvarchar(36) = CONVERT(nvarchar(36), NEWID());
DECLARE @item nvarchar(36) = CONVERT(nvarchar(36), NEWID());
INSERT INTO dbo.guide_items (item_id, run_id, title, quantity)
VALUES (@item, @run, N'Уч85Книга', 3);
SELECT @run AS own_run_uuid, @item AS own_item_uuid;
Модуль объекта Товары85

УчебныйSQL85 → Таблицы → Товары85 → Модуль объекта.

УчебныйSQL85 → Таблицы → Товары85 → Модуль объекта.

Процедура ОбработкаЗаполнения(СтандартнаяОбработка, ДанныеЗаполнения)
    СтандартнаяОбработка = Ложь;
    Если ТипЗнч(ДанныеЗаполнения) <> Тип("Структура") Тогда
        ВызватьИсключение "Нужно собственное основание заполнения";
    КонецЕсли;
    Для Каждого Поле Из СтрРазделить("Код,Метка,Название,Количество", ",") Цикл
        Если Не ДанныеЗаполнения.Свойство(Поле, ЗначениеПоля) Тогда
            ВызватьИсключение "Не хватает собственного поля " + Поле;
        КонецЕсли;
        ЭтотОбъект[Поле] = ЗначениеПоля;
    КонецЦикла;
КонецПроцедуры

Процедура ОбработкаПроверкиЗаполнения(Отказ, ПроверяемыеРеквизиты)
    Если СтрДлина(Код) <> 36 Или СтрДлина(Метка) <> 36 Или Название <> "Уч85Книга" Или Количество < 0 Тогда
        Отказ = Истина;
    КонецЕсли;
КонецПроцедуры
Полный модуль собственной управляемой формы

Собственные реквизиты Метка85/Код85 Строка36 и команда ВыполнитьТовар85.

Собственные реквизиты Метка85/Код85 Строка36 и команда ВыполнитьТовар85.

&НаКлиенте
Процедура ВыполнитьТовар85(Команда)
    ВыполнитьТоварНаСервере85();
КонецПроцедуры

&НаСервере
Процедура ВыполнитьТоварНаСервере85()
    УчебныеВнешниеТаблицы85.ВыполнитьУчебныйТовар85(Метка85, Код85);
КонецПроцедуры

Разбор по шагам

  1. Оба UUID создаются действительным NEWID/INSERT в supporting SQL. Код проверяет строковый тип/длину/канонический UUID перед открытием собственного DSN. Все guard и настройки трех уровней подключения такие же, как в пакетном уроке; первая собственная запись3 действительно уже существует.

  2. Параметризованный запрос1С выбирает Т.Ссылка из точной внешней таблицы, где одновременно Метка и Код равны значениям собственного seed. Результат0 — явный отказ, больше1 — отказ от неуникального ключа. Используется настоящий объект Ссылка, возвращенный платформой, а не выдуманный массив/строка сырого ключа.

  3. ПолучитьОбъект может вернуть Неопределено: отдельная проверка предшествует всем полям. Проверяются Код/Метка/Название/Количество3, ЭтоНовый=Ложь, метаданные Товары85, readonly Ссылка и ЭтотОбъект. Макет читается по реальному имени Паспорт85 и сверяется с фиксированным текстом.

  4. ДополнительныеСвойства хранит лишь временную собственную метку в памяти. Новый черновик получен СоздатьОбъект, Заполнить вызывает полностью приведенный module event; данные заполнения — конкретные поля своего seed. ПроверитьЗаполнение вызывает штатные проверки и приведенный отказ отрицательному количеству/неправильному имени.

  5. УстановитьСсылкуНового принимает именно уже полученную реальную ссылку. ПолучитьСсылкуНового читает ранее установленное значение. Здесь это намеренно отрицательный пример уникальности: данный черновик НИКОГДА НЕ ЗАПИСЫВАЕТСЯ, потому что ссылка принадлежит существующей own строке. Нет заявления, что raw UUID является форматом ссылки, и нет попытки затереть существующую запись.

  6. Скопировать создает новый объект только в памяти; копия не вставляет SQL строку. Устаревший УстановитьЗаписываемыеПоля демонстрируется на этой незаписываемой копии только с явным Массив("Количество"), затем заменяется УстановитьИзменяемыеПоля. ПолучитьИзменяемыеПоля подтверждает одно поле; изменение копии до4 и ее Модифицированность не считаются изменением источника.

  7. Для настоящего обновления начинается своя внешняя транзакция и Заблокировать применяется только к подтвержденному исходному объекту. Заблокирован проверяет блокировку именно этим BSL-объектом; не является проверкой всех чужих пользователей. Прочитать после блокировки перечитывает существующий объект, никогда не вызывается на новом.

  8. Исходному объекту разрешено изменять только Количество. После записи4 данные проверяются другим ПолучитьОбъект до commit, блокировка снимается, собственная транзакция фиксируется, затем новый параметризованный запрос и объект вновь подтверждают4.

  9. Удаление — отдельная своя транзакция: блокировка, перечитывание и точная сверка обоихUUID/названия/4 предшествуют Удалить. Это удаление одного объекта, не набора и не всего источника. Отсутствие собственной ссылки проверяется до и после фиксации.

  10. Исключение снимает только собственную отмеченную блокировку, отменяет только собственную активную транзакцию и закрывает собственное соединение. Если фиксация имела неизвестный итог, оба UUID остаются у пользователя для чтения/диагностики; retry или автоматическое повторное удаление отсутствуют.

  11. ЭтотОбъект используется как глобальный контекст именно в полном модуле Модуль объекта Товары85. Внешний общий модуль не обращается к Набор.ЭтотОбъект или Объект.ЭтотОбъект. При заполнении изменяется собственное содержимое объекта/набора, не readonly ссылка на него.

Как проверить результат

  1. Положительный seed3: реальная ссылка найдена, readonly принадлежность совпадает, текст макета точный, черновик и копия новые только в памяти. Ни копия, ни черновик не должны создавать дополнительную SQL строку.

  2. После настоящего обновления количество4 подтверждено отдельным объектом до/после фиксации. После удаления запрос по обоим ownUUID не должен вернуть строк. Другой собственный seed с другимиUUID должен остаться: урок его не читает и не удаляет.

  3. Повторный запуск с уже удаленнымиUUID должен отказать с отсутствием собственного объекта, без добавления/обновления/удаления. Запись черновика с уже существующей ссылкой намеренно не вызывается, а контроль уникальности описан как ограничение контракта, не будто бы проверенное SQL исключение.

  4. Если обаUUID перепутать или ввести один чужой, запрос должен вернуть0, без выбора случайного первого объекта. В собственной VM удалите/измените учебный макет — код откажет до транзакции обновления.

  5. Не назначайте readonly Ссылка/ЭтотОбъект/ДополнительныеСвойства; setter для нового объекта отличается от присваивания Ссылка. Не запускайте Прочитать у незаписанного черновика: native прямо запрещает этот вызов для нового.

Ожидаемый результат

Подтвержденный собственный товар изменен3→4, затем удален по настоящей ссылке с readback. Незаписываемые копия/черновик демонстрируют память, заполнение, ограничение полей и недопустимость дублирования существующей ссылки без изготовления raw-key значения.

На что обратить внимание

  1. Код не запускался в1С/SQL/ODBC. runtimeVerifiedScenarios=0. Проверка rawKey/конструктора TableRef не заявляется: реальная ссылка получена запросом, а ее внутреннее представление не используется.

  2. Удалить физически удаляет объект внешнего источника. Сценарий допустим только в новой own SQL базе/VM, созданной подготовкой, с единственным сеансом и собственной строкой. GUID не дает прав и не доказывает владельца на рабочем источнике.

  3. Модифицированность относится к одному объекту памяти; Заблокирован — к его собственной блокировке. Чтобы не считать устаревшие данные актуальными, перед update/delete есть блокировка/перечитывание/точная сверка. Это не обещание межсистемной распределенной транзакции или доказательство поведения конкретного ODBC-драйвера.

  4. Чтение макета здесь не печать и не запись файла. Deprecated setter используется только в незаписываемом учебном draft для понимания миграции; нормальный путь записи использует УстановитьИзменяемыеПоля и никогда не изменяет PK/owner UUID.

  5. При ошибке снятия блокировки/отмены/разрыва нельзя обещать завершение очистки: итог остается неизвестным. Не повторяйте commit или DELETE автоматически; сохраненные ownUUID предназначены для ручной проверочной выборки, не для слепого общего удаления.

Пример не запускался в вашей базе. Перед применением проверьте его в указанном учебном контексте.

Не хотите разбираться сами?

Адаптируем это решение под вашу базу. Оценка бесплатно.

Оставить задачу

1С, 1С:Предприятие — товарные знаки ООО «1С». Сайт не является официальным представительством фирмы «1С» и не аффилирован с ней.