Регистрация определяемых пользователем типов в SQL Server

Область применения:SQL Server

Чтобы использовать определяемый пользователем тип (UDT) в SQL Server, необходимо зарегистрировать его. Регистрация определяемого пользователем типа включает регистрацию сборки и создание типа в базе данных, в которой его нужно использовать. Определяемые пользователем объекты относятся к одной базе данных и не могут использоваться в нескольких базах данных, если в каждой базе данных не зарегистрирована идентичная сборка и определяемый пользователем тип. После регистрации сборки UDT и создания типа можно использовать UDT в Transact-SQL и в клиентском коде. Дополнительные сведения см. в определяемых пользователем типов CLR.

Развертывание определяемых пользователей с помощью Visual Studio

Самый простой способ развертывания пользовательского интерфейса — использовать Visual Studio. Однако для более сложных сценариев развертывания и максимальной гибкости используйте Transact-SQL, как описано далее в этой статье.

Для создания и развертывания определяемых пользователем типов с помощью среды Visual Studio выполните следующие шаги.

  1. Создайте проект базы данных на узлах языка Visual Basic или Visual C# .

  2. Добавьте ссылку на базу данных SQL Server, которая будет содержать определяемый пользователем тип.

  3. Добавьте класс определяемого пользователем типа .

  4. Напишите код для реализации определяемого пользователем типа.

  5. В меню "Сборка " выберите "Развернуть". Это регистрирует сборку и создает тип в базе данных SQL Server.

Использование Transact-SQL для развертывания определяемых пользователем пользователей

Синтаксис Transact-SQL CREATE ASSEMBLY используется для регистрации сборки в базе данных, в которой вы хотите использовать UDT. Он хранится внутри системных таблиц базы данных, а не во внешней файловой системе. Если определяемый пользователем тип зависит от внешних сборок, их тоже необходимо загрузить в базу данных. Инструкция CREATE TYPE используется для создания определяемого пользователем объекта в базе данных, в которой она будет использоваться. Дополнительные сведения см. в разделе CREATE ASSEMBLY и CREATE TYPE.

Использование сборки создания

Синтаксис CREATE ASSEMBLY регистрирует сборку в базе данных, в которой вы хотите использовать определяемый пользователем тип. После регистрации сборки она не имеет зависимостей.

Создание нескольких версий одной сборки в данной базе данных запрещено. Однако можно создать несколько версий одной сборки на основе языка и региональных параметров в данной базе данных. SQL Server различает несколько версий языка и региональных параметров сборки по разным именам, зарегистрированным в экземпляре SQL Server. Дополнительные сведения см. в статье Создание и использование сборок с строгим именем.

При выполнении CREATE ASSEMBLY с наборами разрешений SAFE или EXTERNAL_ACCESS сборка проверяется, чтобы убедиться, что она является проверяемой и типобезопасной. Если не указать набор разрешений, SAFE предполагается. Код с набором разрешений UNSAFE не проверяется. Дополнительные сведения о наборах разрешений сборки см. в сборках конструктора.

Пример

Следующая инструкция Transact-SQL регистрирует сборку Point в SQL Server в базе данных AdventureWorks2025 с набором разрешений SAFE. Если предложение WITH PERMISSION_SET опущено, сборка регистрируется в наборе разрешений SAFE.

USE AdventureWorks2022;

CREATE ASSEMBLY Point
    FROM '\\ShareName\Projects\Point\bin\Point.dll'
    WITH PERMISSION_SET = SAFE;

Следующая инструкция Transact-SQL регистрирует сборку с помощью аргумента <assembly_bits> в предложении FROM. Это значение varbinary представляет файл в виде потока байтов.

USE AdventureWorks2022;
CREATE ASSEMBLY Point
FROM 0xfeac4 ... 21ac78

Использование типа создания

После загрузки сборки в базу данных можно создать тип с помощью инструкции Transact-SQL CREATE TYPE. Она добавляет тип в список доступных типов для этой базы данных. Тип имеет область базы данных и может использоваться только в той базе данных, в которой он был создан. Если UDT уже существует в базе данных, инструкция CREATE TYPE завершается ошибкой.

Примечание.

Синтаксис CREATE TYPE также используется для создания собственных типов данных псевдонимов SQL Server и предназначен для замены sp_addtype в качестве средства создания типов данных псевдонима. Некоторые необязательные аргументы в синтаксисе CREATE TYPE относятся к созданию определяемых пользователем типов и не применимы к созданию типов данных псевдонима (например, базового типа).

Дополнительные сведения см. в разделе CREATE TYPE.

Пример

Следующая инструкция Transact-SQL создает тип Point. EXTERNAL NAME указывается с помощью синтаксиса именования двух частей <assembly_name>.<udt_name>.

CREATE TYPE dbo.Point
EXTERNAL NAME Point.[Point];

Удаление определяемого пользователем набора данных из базы данных

Инструкция DROP TYPE удаляет UDT из текущей базы данных. После удаления определяемого пользователем объекта можно использовать инструкцию DROP ASSEMBLY для удаления сборки из базы данных.

Оператор DROP TYPE не выполняется в следующих ситуациях:

  • Таблицы в базе данных, которые содержат столбцы, определенные с помощью определяемого пользователем типа.

  • Функции, хранимые процедуры или триггеры, использующие переменные или параметры определяемого пользователем типа, созданные в базе данных с предложением WITH SCHEMABINDING.

Пример

Следующий код Transact-SQL должен выполняться в следующем порядке. Сначала таблица, ссылающаяся на Point определяемого пользователем типа, должна быть удалена, а затем тип и, наконец, сборка.

DROP TABLE dbo.Points;
DROP TYPE dbo.Point;
DROP ASSEMBLY Point;

Поиск зависимостей UDT

Если существуют зависимые объекты, такие как таблицы с определениями столбцов UDT, оператор DROP TYPE завершается ошибкой. Он также завершается ошибкой, если существуют функции, хранимые процедуры или триггеры, созданные в базе данных с помощью предложения WITH SCHEMABINDING, если эти подпрограммы используют переменные или параметры определяемого пользователем типа. Сначала необходимо удалить все зависимые объекты, а затем выполнить инструкцию DROP TYPE.

Следующий запрос Transact-SQL находит все столбцы и параметры, использующие UDT в базе данных AdventureWorks2025.

USE AdventureWorks2022;

SELECT o.name AS major_name,
       o.type_desc AS major_type_desc,
       c.name AS minor_name,
       c.type_desc AS minor_type_desc,
       at.assembly_class
FROM (SELECT object_id,
             name,
             user_type_id,
             'SQL_COLUMN' AS type_desc
      FROM sys.columns
      UNION ALL
      SELECT object_id,
             name,
             user_type_id,
             'SQL_PROCEDURE_PARAMETER'
      FROM sys.parameters) AS c
     INNER JOIN sys.objects AS o
         ON o.object_id = c.object_id
     INNER JOIN sys.assembly_types AS at
         ON at.user_type_id = c.user_type_id;

Обслуживание определяемых пользователем пользователей

Вы не можете изменить определяемый пользователем тип после его создания в базе данных SQL Server, хотя можно изменить сборку, на которой основан тип. В большинстве случаев необходимо удалить UDT из базы данных с помощью инструкции Transact-SQL DROP TYPE, внести изменения в базовую сборку и перезагрузить ее с помощью инструкции ALTER ASSEMBLY. Затем необходимо повторно создать определяемый пользователем тип и зависимые объекты.

Пример

Оператор ALTER ASSEMBLY используется после внесения изменений в исходный код в сборке UDT и перекомпилировал его. Она копирует DLL-файл на сервер и выполняет повторную привязку к новой сборке. Полный синтаксис см. в разделе ALTER ASSEMBLY.

Следующая инструкция Transact-SQL ALTER ASSEMBLY перезагрузит сборку Point.dll из указанного расположения на диске.

ALTER ASSEMBLY Point
    FROM '\\Projects\Point\bin\Point.dll';

Использование alter assembly для добавления исходного кода

Предложение ADD FILE в синтаксисе ALTER ASSEMBLY отсутствует в CREATE ASSEMBLY. Оно обеспечивает возможность добавления исходного кода или любых других файлов, связанных со сборкой. Файлы копируются из исходных расположений и сохраняются в системных таблицах базы данных. Это обеспечивает постоянную доступность исходного кода или других файлов на тот случай, если возникнет необходимость повторного создания или документирования текущей версии определяемого пользователем типа.

Следующая инструкция Transact-SQL ALTER ASSEMBLY добавляет исходный код класса Point.cs для Point определяемого пользователем кода. Это копирует текст, содержащийся в файле Point.cs, и сохраняет его в базе данных под именем PointSource.

ALTER ASSEMBLY Point
ADD FILE FROM '\\Projects\Point\Point.cs' AS PointSource;

Сведения о сборке хранятся в таблице sys.assembly_files в базе данных, где установлена сборка. Таблица sys.assembly_files содержит следующие столбцы.

Столбец Описание
assembly_id Идентификатор, определенный для сборки. Это число назначается всем объектам, относящимся к одной сборке.
name Имя объекта.
file_id Число, определяющее каждый объект, с первым объектом, связанным с заданным assembly_id, присваивается значение 1. При наличии нескольких объектов, связанных с одной assembly_id, каждый последующий file_id увеличивается по 1.
content Шестнадцатеричное представление сборки или файла.

Функцию CAST или CONVERT можно использовать для преобразования содержимого столбца content в доступный для чтения текст. Следующий запрос преобразует содержимое файла Point.cs в доступный для чтения текст, используя имя в предложении WHERE, чтобы ограничить результирующий набор одной строкой.

SELECT CAST (content AS VARCHAR (8000))
FROM sys.assembly_files
WHERE name = 'PointSource';

Если вы копируете и вставляете результаты в текстовый редактор, вы увидите, что разрывы строк и пробелы, существующие в исходном коде, сохраняются.

Управление пользовательскими пользователями и сборками

При планировании реализации определяемых пользователем типов обдумайте, какие методы нужны в самой сборке определяемого пользователем типа, а какие нужно создать в отдельных сборках и реализовать в виде определяемых пользователем функций или хранимых процедур. Разделение методов на отдельные сборки позволяет обновлять код без влияния на данные, которые могут храниться в столбце UDT в таблице. Сборки UDT можно изменять без удаления столбцов UDT и других зависимых объектов, только если новое определение может считывать бывшие значения и подпись типа не изменяется.

Разделение процедурного кода, который может измениться от кода, необходимого для реализации определяемого пользователем кода, значительно упрощает обслуживание. Включение только кода, необходимого для функции определяемого пользователем кода, и обеспечение максимально простого определения определяемого пользователем кода снижает риск удаления определяемого пользователем объекта из базы данных для исправлений кода или исправлений ошибок.

Функция преобразования валюты и валюты

В примере базы данных Currency UDT в примере AdventureWorks2025 представлен полезный пример рекомендуемого способа структурирования определяемого пользователем объекта и связанных с ним функций. Currency UDT используется для обработки денег на основе денежной системы определенной культуры и позволяет хранить различные типы валют, такие как доллары, евро и т. д. Класс UDT предоставляет имя языка и региональных параметров в виде строки и сумму денег в виде десятичного типа данных. Все необходимые методы сериализации содержатся внутри сборки, определяющей класс. Функция, реализующая преобразование валют из одного языка и региональных параметров в другую, реализуется как внешняя функция с именем ConvertCurrency, и эта функция находится в отдельной сборке. Функция ConvertCurrency выполняет свою работу, извлекая скорость преобразования из таблицы в базе данных AdventureWorks2025. Если источник скорости преобразования должен изменяться или если в существующем коде должны быть какие-либо другие изменения, сборка может быть легко изменена, не влияя на Currency определяемого пользователем типа.

Список кода для функций UDT Currency и ConvertCurrency можно найти, установив примеры среды CLR.

Использование определяемых пользователем типов в разных базах данных

Определяемые пользователем типы по определению находятся в одной базе данных. Таким образом, определяемый пользователем в одной базе данных, нельзя использовать в определении столбца в другой базе данных. Чтобы использовать определяемые пользователем объекты в нескольких базах данных, необходимо выполнить инструкции CREATE ASSEMBLY и CREATE TYPE в каждой базе данных на идентичных сборках. Сборки считаются одинаковыми, если имеют одинаковое имя, строгое имя, культуру, версию, набор разрешений и двоичное содержимое.

После того как определяемый пользователем тип зарегистрирован и доступен в обеих базах данных, можно преобразовать значение данного типа из одной базы данных для использования в другой. Одинаковые определяемые пользователем типы могут использоваться в нескольких базах данных в следующих сценариях.

  • Вызываемые хранимые процедуры определены в различных базах данных.

  • Запрашиваемые таблицы определены в различных базах данных.

  • Выбор данных определяемого пользователем типа из столбца одной базы данных и вставка в столбец такого же типа другой базы данных.

В этих ситуациях любое преобразование, требуемое сервером, происходит автоматически. Вы не можете явно выполнять преобразования с помощью функций Transact-SQL CAST или CONVERT.

При создании рабочих таблиц ядра СУБД SQL Server в системной базе данных tempdb не требуется никаких действий. Это включает обработку курсоров, табличных переменных и определяемых пользователем табличных функций, включающих определяемые пользователем функции, а также прозрачное использование tempdb. Однако если вы явно создаете временную таблицу в tempdb, которая определяет столбец UDT, то UDT необходимо зарегистрировать в tempdb так же, как для пользовательской базы данных.