ВнешнийИсточникДанныхМенеджер.<Имя внешнего источника>

Типы · <External source name>

Предназначен для управления внешним источником данных.

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

ВнешнийИсточникДанныхМенеджер.<Имя внешнего источника> (ExternalDataSourceManager.<External source name>)

ВнешнийИсточникДанныхМенеджер.<Имя внешнего источника> (ExternalDataSourceManager.<External source name>)

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

Свойства:
Кубы (Cubes)
Таблицы (Tables)

Методы:
<Имя функции> (<Function name>)
ЗафиксироватьТранзакцию (CommitTransaction)
НачатьТранзакцию (BeginTransaction)
ОтменитьТранзакцию (RollbackTransaction)
ПолучитьОбщиеПараметрыСоединения (GetCommonConnectionParameters)
ПолучитьПараметрыСоединенияПользователя (GetUserConnectionParameters)
ПолучитьПараметрыСоединенияСеанса (GetSessionConnectionParameters)
ПолучитьСостояние (GetState)
РазорватьСоединение (Disconnect)
ТранзакцияАктивна (TransactionActive)
УстановитьОбщиеПараметрыСоединения (SetCommonConnectionParameters)
УстановитьПараметрыСоединенияПользователя (SetUserConnectionParameters)
УстановитьПараметрыСоединенияСеанса (SetSessionConnectionParameters)
УстановитьСоединение (Connect)

Описание:

Предназначен для управления внешним источником данных.

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

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

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

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

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

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

Собственный SQL-пакет: две строки, фиксация, откат и удаление только своего UUID

Полный серверный опыт с действительной ODBC подготовкой и двумя собственными строками. Менеджер отвечает за соединение/транзакцию; набор отдельно меняется в памяти и отдельно записывается в свою SQL-базу.

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

Полный серверный общий модуль УчебныеВнешниеТаблицы85 собственной новой файловой CF. Запуск только явно человеком из серверной команды собственной формы; supporting SQL и модуль набора вставляются раздельно.

Подготовка

  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. Вставьте supporting BSL module именно в модуль набора записей Строки85. Обработчики привяжите к соответствующим событиям через Конфигуратор. Сначала обновите только собственную CF. Запись через Заполнить не объявляется автоматическим импортом: обработчик полностью приведен отдельно.

Процедура ПроверитьСвойПустойСтенд()
    Если Метаданные.Справочники.Количество() <> 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(Источник, Метка)
    Набор = Источник.Таблицы.Строки85.СоздатьНаборЗаписей();
    Набор.Отбор.Метка.Установить(Метка);
    Набор.Прочитать();
    Если Не Набор.Выбран() Или Набор.Отбор.Метка.Значение <> Метка Или Не Набор.Отбор.Метка.Использование Тогда
        ВызватьИсключение "Равенство собственному UUID не подтверждено";
    КонецЕсли;
    Если Набор.Количество() > 2 Тогда
        ВызватьИсключение "Слишком много строк для собственного учебного UUID";
    КонецЕсли;
    Для Каждого Запись Из Набор Цикл
        Если Запись.Метка <> Метка Или (Запись.Номер <> 1 И Запись.Номер <> 2) Тогда
            ВызватьИсключение "Отказ от использования чужой строки";
        КонецЕсли;
    КонецЦикла;
    Возврат Набор;
КонецФункции


Процедура ВыполнитьУчебныеСтроки85() Экспорт
    Источник = ОткрытьСвойИсточник85();
    Метка = Строка(Новый УникальныйИдентификатор);
    Сообщить("Сохраните собственный UUID для ручной проверки: " + Метка);
    СвояТранзакция = Ложь;
    Попытка
        Набор = СчитатьСвойНабор85(Источник, Метка);
        Если Набор.Количество() <> 0 Тогда
            ВызватьИсключение "UUID уже существует; нет обновления или удаления";
        КонецЕсли;
        Набор.ДополнительныеСвойства.Вставить("УчебнаяМетка", Метка);
        Набор.Заполнить(Новый Структура("Метка", Метка));
        Первая = Набор.Добавить();
        Первая.Метка = Метка;
        Первая.Номер = 1;
        Первая.Название = "Книга";
        Первая.Количество = 3;
        Вторая = Набор.Вставить(0);
        Вторая.Метка = Метка;
        Вторая.Номер = 2;
        Вторая.Название = "Ручка";
        Вторая.Количество = 2;
        Набор.Сдвинуть(Вторая, 1);
        Если Набор.Индекс(Первая) <> 0 Или Набор.Получить(1) <> Вторая Или Набор.Итог("Количество") <> 5 Тогда
            ВызватьИсключение "Не совпали порядок или сумма собственного пакета";
        КонецЕсли;
        Количества = Набор.ВыгрузитьКолонку("Количество");
        Набор.ЗагрузитьКолонку(Количества, "Количество");
        СтруктураКолонок = Набор.ВыгрузитьКолонки("Метка,Номер,Название,Количество");
        Если СтруктураКолонок.Количество() <> 0 Или СтруктураКолонок.Колонки.Количество() <> 4 Тогда
            ВызватьИсключение "ВыгрузитьКолонки должно вернуть только структуру";
        КонецЕсли;
        Данные = Набор.Выгрузить();
        Набор.Удалить(Вторая);
        Набор.Очистить();
        Набор.Загрузить(Данные);
        Если Набор.Количество() <> 2 Или Не Набор.Модифицированность() Или Не Набор.ПроверитьЗаполнение()
            Или Набор.Метаданные().Имя <> "Строки85" Тогда
            ВызватьИсключение "Не подтвержден собственный измененный набор";
        КонецЕсли;
        Если Источник.ТранзакцияАктивна() Тогда
            ВызватьИсключение "Нельзя присоединяться к чужой транзакции";
        КонецЕсли;
        Источник.НачатьТранзакцию();
        СвояТранзакция = Истина;
        Набор.Записать(Ложь);
        Проверка = СчитатьСвойНабор85(Источник, Метка);
        Если Проверка.Количество() <> 2 Или Проверка.Итог("Количество") <> 5 Тогда
            ВызватьИсключение "Внутри собственной транзакции нет двух учебных строк";
        КонецЕсли;
        Источник.ЗафиксироватьТранзакцию();
        СвояТранзакция = Ложь;
        Проверка = СчитатьСвойНабор85(Источник, Метка);
        Если Проверка.Количество() <> 2 Или Проверка.Итог("Количество") <> 5 Тогда
            ВызватьИсключение "Фиксация не подтверждена повторным чтением";
        КонецЕсли;
        Источник.НачатьТранзакцию();
        СвояТранзакция = Истина;
        Проверка.Получить(0).Количество = 99;
        Проверка.Записать(Истина);
        Источник.ОтменитьТранзакцию();
        СвояТранзакция = Ложь;
        Проверка = СчитатьСвойНабор85(Источник, Метка);
        Если Проверка.Количество() <> 2 Или Проверка.Итог("Количество") <> 5 Тогда
            ВызватьИсключение "Откат учебного изменения не подтвержден";
        КонецЕсли;
        Источник.НачатьТранзакцию();
        СвояТранзакция = Истина;
        Проверка.Очистить();
        Проверка.Записать(Истина);
        Если СчитатьСвойНабор85(Источник, Метка).Количество() <> 0 Тогда
            ВызватьИсключение "Удаление только собственного UUID не подтверждено";
        КонецЕсли;
        Источник.ЗафиксироватьТранзакцию();
        СвояТранзакция = Ложь;
        Если СчитатьСвойНабор85(Источник, Метка).Количество() <> 0 Тогда
            ВызватьИсключение "После фиксации остались собственные строки";
        КонецЕсли;
    Исключение
        СбойЗавершения = Ложь;
        Если СвояТранзакция И Источник.ТранзакцияАктивна() Тогда
            Попытка
                Источник.ОтменитьТранзакцию();
            Исключение
                СбойЗавершения = Истина;
            КонецПопытки;
        КонецЕсли;
        Попытка
            Источник.РазорватьСоединение();
        Исключение
            СбойЗавершения = Истина;
        КонецПопытки;
        Если СбойЗавершения Тогда
            Сообщить("Собственный откат или закрытие тоже не подтверждены");
        КонецЕсли;
        ВызватьИсключение "Опыт не завершен. Сверьте только сохраненный собственный UUID; автоматического повторения и чужой очистки нет";
    КонецПопытки;
    Источник.РазорватьСоединение();
    Если Источник.ПолучитьСостояние() <> СостояниеВнешнегоИсточникаДанных.Отключен Тогда
        ВызватьИсключение "Закрытие собственного соединения не подтверждено";
    КонецЕсли;
    Сообщить("Две строки: фиксация, откат и собственное удаление проверены чтением; источник закрыт");
КонецПроцедуры
SQL Server: создание собственной новой базы и двух таблиц

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

Вручную в SSMS на отдельном own 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;
Модуль набора записей Строки85

УчебныйSQL85 → Таблицы → Строки85 → Модуль набора записей; точные native event-сигнатуры.

УчебныйSQL85 → Таблицы → Строки85 → Модуль набора записей; точные native event-сигнатуры.

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

Процедура ОбработкаПроверкиЗаполнения(Отказ, ПроверяемыеРеквизиты)
    Для Каждого Запись Из ЭтотОбъект Цикл
        Если Запись.Метка <> Отбор.Метка.Значение Или (Запись.Номер <> 1 И Запись.Номер <> 2)
            Или Запись.Название = "" Или Запись.Количество < 0 Тогда
            Отказ = Истина;
        КонецЕсли;
    КонецЦикла;
КонецПроцедуры

Процедура ПередЗаписью(Отказ)
    Если Не Отбор.Метка.Использование Или ТипЗнч(Отбор.Метка.Значение) <> Тип("Строка") Или СтрДлина(Отбор.Метка.Значение) <> 36 Тогда
        Отказ = Истина;
        Возврат;
    КонецЕсли;
    Для Каждого Запись Из ЭтотОбъект Цикл
        Если Запись.Метка <> Отбор.Метка.Значение Или (Запись.Номер <> 1 И Запись.Номер <> 2)
            Или Запись.Название = "" Или Запись.Количество < 0 Тогда
            Отказ = Истина;
        КонецЕсли;
    КонецЦикла;
КонецПроцедуры

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

  1. Проверка версии, имени новой CF, пустой остальной бизнес-метадаты, единственного собственного источника/пользователя и отсутствия расширений/чужой транзакции предшествует соединению. Уже подключенный источник не закрывается и не переиспользуется.

  2. Получаем три самостоятельных объекта параметров: общий, пользовательский и сеансовый. Указываем одинаковый собственный DSN и Windows-аутентификацию, вызываем все три setter, затем читаем строки назад. Эти административные настройки сохраняются в своей базе, не являются временным getter-примером или восстановлением прежних секретов.

  3. Connect подтверждается состоянием Подключен и фактическим SELECT DB_NAME через собственную функцию МеткаСтенда85. Ни один SQL/BSL запрос не строится конкатенацией пользовательского текста. Получение Кубы проверяет тип локального менеджера при пустом дереве кубов; OLAP отсутствует.

  4. Новый UUID печатается до записи. СоздатьНаборЗаписей дает пустой набор; отбор устанавливается равенством Метка. Прочитать читает только этот диапазон. Отбор readonly как свойство, но его элементы настраиваемы; свойству Отбор другой объект не назначается.

  5. Заполнить запускает полный приведенный event-модуль; он не создает чужих строк. Добавить и Вставить создают Книга3/Ручка2, Сдвинуть меняет порядок в памяти. Индекс/Получить проверяют обе позиции, Итог вычисляет 5. Порядок SQL чтения после записи не обещан.

  6. ВыгрузитьКолонки создает только пустую структуру из четырех колонок. Выгрузить дает данные, ВыгрузитьКолонку/ЗагрузитьКолонку показывают отдельный массив количеств. Удалить удаляет одну строку только из памяти, Очистить очищает память, Загрузить заново воспроизводит обе строки. Ни один из этих вызовов сам по себе не удаляет SQL-строки.

  7. После проверок заполнения/метадаты/модифицированности начинается своя внешняя транзакция. Записать(Ложь) именно добавляет собственные две строки; двойная запись не повторяется. Readback выполняется до и после ЗафиксироватьТранзакцию.

  8. Вторая внешняя транзакция меняет количество на99 и Записать(Истина) замещает только равенство UUID. Затем ОтменитьТранзакцию и новый набор должны снова дать две строки/сумму5. Транзакция внешней СУБД не подменяется глобальной транзакцией базы1С.

  9. Третья транзакция явно удаляет исключительно подтвержденный диапазон ownUUID: уже прочитанный/проверенный набор очищается и записывается с Истина, фильтр остается. Пустой набор без отбора никогда не записывается. Ноль проверяется до и после фиксации.

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

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

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

  1. Первый положительный опыт: в памяти две строки, суммы5 и количество2; после первой фиксации повторное чтение равно2/5; после отката99 снова2/5; после собственного удаления и фиксации0.

  2. В собственной VM SQL SELECT * FROM dbo.guide_lines WHERE run_id = <ровно сохраненный UUID> должен дать ноль после завершения. Параметризуйте запрос средствами SSMS/драйвера, не вводите чужой UUID. Никакой общий DELETE не нужен.

  3. В новой CF предварительно откройте соединение из иного собственного опыта: урок должен отказаться до setter/закрытия. Неправильный пользователь/версия/расширение/DSN также должны дать отказ.

  4. До записи временно измените Метка одной строки на другой UUID: обработчик ПередЗаписью должен отказать; не изменяйте данные рабочей базы для этого теста.

  5. SQL CHECK откажет отрицательному количеству, но BSL ПроверитьЗаполнение/ПередЗаписью должны отказать раньше. Пустое Название также отказывается. Это разные слои контроля, а не гарантия одной общей транзакции нескольких СУБД.

  6. Оборвите только собственный локальный опыт после фиксации: не считайте сообщение об исключении доказанным откатом уже завершенной транзакции. Сверьте сохраненный UUID; код никогда не удаляет неопознанный диапазон.

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

Собственный UUID прошел реальную последовательность SQL добавление→подтверждение→изменение→откат→удаление→подтверждение. Остальные строки не выбирались и не замещались; ошибка оставляет честный неизвестный исход для ручной проверки.

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

  1. Это авторский код и статические проверки, не запуск1С/SQL/ODBC. runtimeVerifiedScenarios=0. Windows DSN и служебная учетная запись сервера имеют отдельные настройки; в уроке именно локальный толстый/тонкий управляемый клиент и собственная файловая база, а не чужой серверный DSN.

  2. Записать по умолчанию замещает! Поэтому Ложь при добавлении и Истина только после точного UUID отбора написаны явно. Равенство UUID не является механизмом авторизации: настоящую изоляцию дает новая VM/SQL-база/права/единственный пользователь; нельзя переносить урок в production.

  3. GetState относится к соединению, Выбран к считыванию набора, Модифицированность к собственной памяти. Ни один не доказывает отсутствия изменений другими процессами. UUID и последовательный сеанс не заменяют SQL PK/транзакции.

  4. Обычная транзакция1С и транзакция внешнего источника различны; распределенной атомарности урок не обещает. При сетевом разрыве в момент commit итог неизвестен: без readback нет успеха и нет автоматического повторения.

  5. Отбор, ЭтотОбъект, ДополнительныеСвойства — readonly ссылки. Меняется содержащаяся структура/элемент отбора, не само readonly свойство. Поддерживающий event не отключает safe mode вручную; native замечания о safe mode не являются разрешением запустить код в рабочей базе.

  6. Свой DSN настраивается человеком только на localhost изолированной VM. Проверка DB_NAME после открытия подтверждает выбранную SQL-базу, но сама не является проверкой сетевого адреса/сертификата или доверия администратору DSN.

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

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

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

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

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