MS SQL Server 9 “Yukon”. Интеграция с .NET
Антон Злыгостев (Sinclair)
ЮКОН
— река в Канаде и США (Аляска). Длина 3700 км, площадь бассейна 855 тыс.кв.км. Истоки — в горах, ограничивающих с юго-востока плоскогорье Юкон; главный исток — река Льюис, берущая начало в Кордильерах. Впадает в залив Нортон Берингова моря, образуя дельту.
Большая Советская Энциклопедия
Не так давно в руки некоторых представителей RSDN Team попал предварительный релиз следующей версии MS SQL Server. Это даже не бета-версия, (что неудивительно – ведь до ожидаемого поступления финального варианта в продажу остался целый год), но мы не могли устоять перед искушением заглянуть в будущее.
Со всей ответственностью заявляю – маркетинговые материалы, публикуемые по данному продукту, не отражают и малой доли новых возможностей. Из одного перечисления нововведений можно было бы сделать журнальную статью, поэтому исследователи разделили обязанности между собой. В данной статье рассматривается технология интеграции .NET и MS SQL Server.
Современные коммерческие РСУБД не могут позволить себе ограничиться ролью пассивного хранилища данных, поддерживая только SQL. Необходима поддержка возможностей процедурного программирования. До недавнего времени типичным решением этой проблемы было специфичное для производителя расширение стандартного SQL для написания триггеров и хранимых процедур (PL/SQL, T-SQL). На тот не столь уж редкий случай, когда этого расширения не хватало для удовлетворения потребностей разработчиков, предлагались не менее специфичные способы использовать «внешний» по отношению к серверу код (пользовательские функции в Interbase, расширенные хранимые процедуры в MS SQL и т.д.).
Основным недостатком первого решения является откровенная узость SQL, хотя бы и расширенного. «Дотянуть» SQL до полноценного языка программирования общего назначения – нереально. К тому же, он по необходимости является интерпретируемым языком, что ограничивает его быстродействие при выходе за пределы табличных операций. Например, написать хранимую процедуру для шифрования PGP вполне можно и на T-SQL (благо там не нужно ничего, кроме арифметики). Но скорость ее работы будет, мягко говоря, недостаточной.
При использовании внешнего кода возникает другая проблема – в большинстве случаев ему трудно получить доступ к контексту РСУБД, использующей его. Как правило, все взаимодействие происходит через «замочную скважину» точки входа в DLL. Да, для вычисления хеша MD5 такая технология вполне подходит, но возможности взаимодействия подобного кода с ядром СУБД слишком ограничены.
Несколько лет назад Oracle предложил использовать Java в качестве языка программирования для своей РСУБД. Эта практика не прошла незамеченной в Редмонде, и вот теперь Microsoft готовит ответный удар.
Следующие объекты MS SQL Server могут быть созданы с использованием .NET:
Хранимые процедуры.
Триггеры.
Функции (скалярные и табличные).
Агрегирующие функции.
Пользовательские типы данных.
Для написания кода этих объектов потребуется .NET Framework версии 1.2 или выше.
В отличие от расширенных хранимых процедур, код которых находится во внешних динамических библиотеках, код .NET хранится внутри соответствующей базы данных. Это обеспечивает дополнительное удобство при администрировании – восстановление базы из резервной копии или перенос на другой сервер (detach/attach) не нарушит целостности приложения.
Есть два основных способа выполнить загрузку сборки в базу данных:
вручную, при помощи операторов T-SQL и любого клиентского приложения (пойдет даже старый Query Analyzer. Он хоть и не так красив в строю, как новый MS SQL Server Workbench, зато у него нет привычки падать и отжиматься в самые неподходящие моменты).
При помощи средств автоматического развертывания, встроенных в MS Visual Studio .NET codename Whidbey.
Как только сборка загружена в базу данных, ее код можно использовать для создания различных объектов. Особенности этих двух способов описаны в следующих двух подразделах.
Загрузка кода при помощи T-SQL
Загрузка кода производится при помощи оператора CREATE ASSEMBLY:
CREATE ASSEMBLY assembly_name [ AUTHORIZATION owner_name ] FROM { < client_assembly_specifier > | < assembly_bits > [,...n] } [ WITH PERMISSION_SET = { SAFE | EXTERNAL_ACCESS | UNSAFE } ] < client_assembly_specifier > :: = '[\machine_name\]share_name\[path\]manifest_file_name' < assembly_bits > :: = { varbinary_literal | varbinary_expression } |
Код будет загружен в текущую базу данных соединения. Чтобы сменить базу, предварительно выполните команду USE database_name.
Имя параметра | Описание |
assembly_name | Имя сборки .NET (assembly). Оно должно быть уникальным в пределах текущей базы данных, удовлетворять требованиям MS SQL Server, предъявляемых к идентификаторам, и при этом совпадать с именем файла сборки. |
AUTHORIZATION owner_name | Указывает имя роли, которая будет считаться владельцем данной сборки. Можно указывать только те роли, в которые входит текущий пользователь, или те, на которые у него есть права IMPERSONATE. По умолчанию владельцем станет сам текущий пользователь. |
<client_assembly_specifier> | Строковое выражение, которое указывает локальный или сетевой путь к файлу сборки. Можно загружать только однофайловые сборки. Все сборки, от которых зависит указанная, также будут автоматически загружены в базу данных. Если они уже присутствуют в базе, то у выполняющего операцию пользователя должны быть права REFERENCES для них. Если сборки не найдены ни в базе, ни в том же каталоге, где и основная, или на них нет соответстующих прав, оператор не будет выполнен. |
assembly_bits | Бинарное представление сборки. Если сборок несколько, то первой должна идти главная из них, а потом те, от которых она зависит. Такая технология позволяет миновать фазу записи на диск при динамической генерации кода и избежать проблем с доступом к файловой системе. Именно таким образом происходит развертывание сборок из-под MS Visual Studio 8.0 (Whidbey). |
PERMISSION_SET {SAFE | EXTERNAL_ACCESS | UNSAFE } | Уровень прав, которые MS SQL Server предоставит коду сборки при его исполнении. По умолчанию используется SAFE.SAFE – самый ограниченный уровень. Код в такой сборке не может получить доступ к внешнему миру (файловой системе, сети, переменным окружения или реестру).EXTERNAL_ACCESS позволяет выходить за пределы MS SQL Server, но с определенными ограничениями. Полный список ограничений на данный момент недоступен, но по крайней мере исполнение не-менеджед кода запрещено.UNSAFE предоставляет неограниченный доступ к ресурсам, как внешним, так и внутренним. Такие сборки могут загрузить в базу данных только члены группы sysadmin.В большинстве случаев должно хватать уровня SAFE. При этом есть гарантия, что злонамеренный разработчик не предоставит бинарный код, делающий какие-либо гадости от имени сервиса SQL Server или текущего пользователя. Все примеры в этой статье работают с уровнем SAFE. |
Таблица 1. Параметры оператора CREATE ASSEMBLY.
Загрузка при помощи Visual Studio
Загружать код вручную не очень-то удобно. Особенно это сказывается во время разработки приложения, когда отлаживаемый код то и дело необходимо исправлять. Новая версия Visual Studio позволяет существенно облегчить этот процесс. Достаточно создать в студии проект типа SQL Server Project (не путать с Database Project!), и в меню Build появятся команды Deploy, которые (помимо компиляции исходного кода) сделают всю необходимую работу по размещению ваших сборок в базе данных. При открытии проекта Visual Studio попросит указать сервер и базу данных, в которую будет выполняться развертывание.
Естественно, «внутри» Visual Studio использует те же самые команды T-SQL. Как правило, параметры этих команд определяются автоматически. Для управления процессом развертывания используются (конечно же!) атрибуты. Классы этих атрибутов реализованы в сборке Microsoft.VisualStudio.DataTools.SqlAttributes.
СОВЕТ Если у вас возникнет желание разработать свои средства автоматического развертывания проектов SQL Server, обратите внимание на эти атрибуты. Поддержка их поможет использовать код, написанный другими разработчиками, без дополнительных усилий |
На уровне сборки для управления процессом развертывания определен один класс атрибута System.Data.Sql.SqlAssemblyAttribute. При создании проекта SQL Server Project в файл AssemblyInfo.cs автоматически будет добавлен этот атрибут. Его использование выглядит вот так:
[assembly: SqlAssembly(<name>, Authorization = <authorization>)] |
Строковый параметр name соответствует параметру assembly_name оператора CREATE ASSEMBLY, параметр Authorization – параметру owner_name (см. предыдущий раздел).
Для того, чтобы Visual Studio могла корректно зарегистрировать ваши типы, процедуры, функции или триггеры, их код тоже надо будет снабдить соответствующими атрибутами. Подробности приведены далее.
Говорят, что идеальные программисты с первого раза пишут безошибочный код. Если вы один из них, то можете пропустить этот раздел и переходить прямо к написанию кода.
Однако если вы, как и я, периодически испытываете взрыв эмоций при виде сообщения об ошибке, которое обрезано ровно перед тем местом, где должен быть номер строки и имя файла, то вас несомненно обрадует тот факт, что код .NET, хранящийся в базе данных, можно отлаживать с удобством и комфортом. Лично я пользовался для отладки все той же Visual Studio Whidbey, и выглядело это примерно так:
Прежде всего, нужно выполнить развертывание проекта (меню Build->Deploy). Настоятельно рекомендую выбирать отладочную конфигурацию проекта.
Теперь выясните идентификатор процесса (PID) MS SQL Server. Процесс называется “sqlservr.exe”. Те, у кого запущен только один экземпляр SQL Server, могут сразу переходить к пункту 3. У меня Yukon стоит рядом с MSDE, поэтому таких процессов нашлось два. Чтобы избежать неоднозначности, можно просто остановить лишние серверы, а можно подключиться к нужному и выполнить команду SELECT ServerProperty('ProcessID')