Новые возможности решают проблемы разработчиков

Еще задолго до появления Visual Studio 2005 и SQL Server 2005 можно было наблюдать целый поток технических статей и маркетинговых материалов, превозносивших достоинства ADO.NET 2.0, новой версии ADO.NET, и тех инструментальных средств создания приложений, которые на нее ссылались. Во многих статьях просто приводился длинный список новых привлекательных возможностей ADO.NET 2.0. Но я думаю, что разработчиков больше интересует, как эти возможности помогут им в решении конкретных задач. Поэтому я собираюсь представить ADO.NET 2.0, перечислив некоторые важные проблемы и показав, насколько быстрее и эффективнее их решает новая версия.

Лучше управляет соединениями

Одна из самых досадных проблем в ADO.NET была связана с тем, как провайдеры данных обрабатывали (а скорее, не обрабатывали) пул соединений. К примеру, когда в ADO.NET 1.1 «умирало» соединение, механизм организации пула сохранял его экземпляр до тех пор, пока какое-нибудь ничего не подозревающее приложение не пыталось им повторно воспользоваться. И только тогда механизм организации пула «избавлялся от трупа». Однако при этом он оставлял другие отказавшие соединения, чтобы последующим вызовам Open было где поплутать. В ADO.NET 2.0 реализован новый подход: как только обнаруживается нарушение соединения, происходит немедленное вычищение из пула и его, и всех остальных неисправных соединений, что существенно облегчает задачу обработчиков исключений. Можно даже добавить код, стимулирующий очищение пула (или всех пулов). В ADO.NET 2.0 также заменены счетчики показателей пропускной способности соединения. Новые счетчики, кажется, работают (в отличие от старых), так что можно с большей точностью проводить мониторинг состояния пула соединений.

При работе с оболочкой Visual Studio в ходе создания нового соединения в Visual Studio 2003 предоставлялся выбор провайдеров OLE DB, но не провайдеров данных .NET Data. Для решения этой проблемы в ADO.NET 2.0 введен новый класс DbConnection StringBuilder, призванный помочь разработчикам строить настоящие строки соединения для провайдера данных в среде .NET, .NET Data Provider. Учитывая возможность использования новых интерфейсов приложений .NET Framework API для формирования списка провайдеров и серверов, создавать инструментальные средства построения диалоговых окон со строкой соединения ConnectionString станет заметно легче.

Некоторые приложения, особенно основанные на архитектуре JET, пытаются воспользоваться одним соединением для отправки обновлений в не до конца заполненные наборы строк и терпят неудачу. К примеру, разработчики могут, используя DataReader, выполнить предложение SELECT и при прохождении по строкам попытаться исполнить предложение UPDATE через то же самое соединение. Теперь ADO.NET 2.0 и SQL Server 2005 поддерживают множественные активные результирующие наборы — Multiple Active Result Sets (MARS). Хотя мне еще только предстоит разобраться в этой возможности, видимо, специалисты Microsoft гордятся ею. MARS позволяет выполнять дополнительные операции по одному соединению (при принятии соответствующих мер предосторожности). Мне думается, что разумнее просто открыть дополнительное соединение, однако по умолчанию возможности MARS отключены, так что разработчикам предстоит самим решать, применять их или нет.

Быстрее обрабатывает данные

Справедливости ради замечу, что некоторым разработчикам действительно требуется предоставлять клиенту по 100 тыс. строк и возможность манипулировать ими в DataTable. Для таких задач специалисты Microsoft переделали способ конструирования, хранения и индексирования объектов DataTable и DataSet в ADO.NET. Если в DataTable находится менее 10 тыс. строк, то разница в производительности будет не очень заметна. Но разработчики, строящие гигантские таблицы DataTable, почувствуют весьма существенное увеличение производительности — в 80 раз (так мне сказали в Microsoft). Подобное усовершенствование не должно побуждать вас загружать в оперативную память весь список абонентов МГТС. Существуют более быстрые и удобные способы обработки огромных объемов данных, такие как применение нового класса BulkCopy для импорта строк в таблицы на сервере и их обработки с помощью хранимой процедуры или даже новой процедуры на базе CLR.

Многие разработчики применяют DataReader для выборки данных, но впоследствии пользуются собственным кодом для загрузки данных в DataTable или DataSet. Сейчас в ADO.NET 2.0 классы DataTable и DataSet предоставляют метод загрузки Load, позволяющий разработчикам напрямую загружать данные в DataTable из DataReader. Можно также выделить поток Data-Reader из существующих DataSet или DataTable с помощью метода CreateReader. А это означает, что DataReader может возвращать множественные наборы строк посредством метода NextResult.

Однако предположим, что у вас спрашивают, как заставить быстрее работать приложение, предоставляющее клиенту 10 тыс. и более строк. Спрашивается, зачем? Так часто бывает, когда заказчик хочет выполнить массированную операцию, но не сознает этого. Как правило, запросы таких клиенты принимают одну из двух форм.

  1. Заказчик просит произвести выборку миллиона строк, внести изменения и отправить строки обратно. Разумеется, заказчики могут не знать о существовании хранимых процедур, способных выполнить все изменения прямо на сервере за минимальное время. Таким клиентам я рекомендую почитать учебник по созданию корректных операций обновления UPDATE на сервере. Но ведь люди применяют те средства, с которыми им удобно работать.
  2. Заказчик просит выбрать миллион строк из другой базы данных и переместить их в SQL Server. Иногда заказчики собираются произвести по ходу перемещения логическую обработку данных, но обычно они просто хотят импортировать множество строк из мэйнфрейма в свой офис. В прошлом я советовал в таких случаях воспользоваться DTS или программой копирования массивов (BCP). В ADO.NET 2.0 можно легко импортировать данные из любого источника с помощью класса SqlBulkCopy. Можно массированно копировать для дальнейшей обработки в SQL Server данные, демонстрируемые любым провайдером данных среды .NET: SqlClient, OLE DB, ODBC или провайдерами независимых фирм. Как только данные окажутся на сервере, клиенту стоит изменить или отфильтровать их на месте. То, что отнимало часы и даже дни с прежними версиями ADO, теперь занимает секунды или минуты с ADO.NET 2.0.

Чтобы проиллюстрировать последнее утверждение, я недавно написал приложение, применяющее MSDN Index CD, для поиска DVD в своей коллекции Universal. К сожалению, базирующемуся на Microsoft Internet Explorer (IE) поисковому механизму, который сопровождает Index CD, требуется несколько минут на самый простой поиск. Я загрузил данные MSDN Index с помощью класса ADO.NET 2.0 SqlBulkCopy, чтобы файлы .rs, неизменно базирующиеся на классическом варианте Advanced Data TableGram (ADTG), из Index CD попали в SQL Server. После того как данные были загружены, я создал подходящие индексы и смог снизить время обработки запроса с нескольких минут до менее чем пяти секунд. Операция BCP переместила около 450 тыс. строк менее чем за 30 секунд. Я также попробовал импортировать данные XML с CD, но результаты оказались неудовлетворительными — все происходило намного дольше. Похоже, XML представляет собой один из самых неэффективных (но зато самых гибких) механизмов хранения данных.

Еще одна возможность, которую никак нельзя упустить в ADO.NET 2.0, это адаптер таблиц TableAdapter. Лучше всего генерировать этот класс с помощью механизма перетаскивания интерфейса Visual Studio 2005. Класс TableAdapter спроектирован для показа новых функциональных возможностей объекта DataTable, который реализует многие методы DataSet. DataTable позволяет преобразовать в последовательную форму индивидуальный объект DataTable, применяя либо двоичный метод, либо метод XML. Добавим к этому новые механизмы связывания и элементы управления навигацией по наборам строк, и получим более мощный инструмент построения интерактивных приложений. ASP.NET также получает поддержку от ADO.NET. К примеру, теперь можно автоматически обновлять наборы данных, которые строятся и связываются с применением новой «полностью дуплексной» технологии управления данными.

ADO.NET 2.0 может вести многозадачную обработку?

Поскольку я предвидел, что моему поисковому приложению MSDN Index иногда может требоваться много времени для выполнения сложного поиска, мне захотелось опробовать возможности нового асинхронного DataReader в ADO.NET 2.0 для вывода индикатора, показывающего прогресс при выполнении поиска. Хотя сделать это было несложно, предотвратить возникновение тупиковых ситуаций в ходе выполнения длительных запросов не удавалось. Ведь исполнение запроса и возврат набора строк образуют двухфазный процесс. При использовании в SqlClient.SqlCommand команды BeginExecuteReader для начала исполнения поискового запроса управление немедленно возвращается приложению. В этой точке можно показывать индикатор прогресса выполнения или делать что угодно для развлечения пользователей, чтобы они от скуки не нажали CTRL-ALT-DEL. Как только будет достигнуто состояние завершения IsCompleted, можно получить доступ к потоку DataReader, но ожидание на этом не заканчивается. Требуется еще возвратить найденные строки, на что может уйти значительное время. ADO.NET не предоставляет асинхронные методы загрузки Load и заполнения Fill (что было бы прекрасно), так что придется прибегнуть к потокам BackgroundWorker. Хотя разобраться в этих потоках нетрудно, сам факт, что были опущены асинхронные Fill и Load, представляется мне досадной оплошностью. Кстати, эта новая возможность почти догоняет базирующуюся на СОМ версию ADO, которая также поддерживает асинхронный метод Connection Open.

Как ADO.NET 2.0 проводит обновления

В базирующемся на COM «классическом» ADO пакетные обновления были реализованы уже давно, и наконец-то в ADO.NET 2.0 тоже появилась такая возможность. Это означает, что можно будет вносить в DataTable десятки (или тысячи) изменений и при этом ADO.NET реализует эти изменения за гораздо меньшее число походов на сервер и обратно. Для поддержания этой возможности ADO.NET демонстрирует новый набор событий, которые обеспечивают высокую степень детализации при управлении операциями и возможными исключениями.

Если только от данной возможности не откажутся (а сейчас это под вопросом), ADO.NET 2.0 сможет улучшить метод, которым CommandBuilder строит исполняемые команды для выполнения параллельной обработки. Ввод нового свойства для обработки конфликтов ConflictOption в ADO.NET 2.0 позволяет выбирать между следующими вариантами: сравнением всех пригодных для поиска значений CompareAllSearchableValues (это текущая установка в ADO.NET 1.1), сравнением версий строк CompareRowVersion (эта установка проверяет версию строки и штамп времени для тестирования распараллеливания) и перезаписью изменений OverwriteChanges (она форсирует внесение изменений путем исключения оператора WHERE из предложения UPDATE). Такая дополнительная гибкость означает, что класс CommandBuilder может лучше соответствовать разным подходам управления распараллеливанием. Но трудно сказать, чем применение CommandBuilder лучше при работе со сложным синтаксисом SelectCommand.

Взаимодействие ADO.NET 2.0 и SQL Server

SQL Server 2005 Express представляет собой предложенную Microsoft замену версии MSDE. Одна из наиболее интересных возможностей ADO.NET — его способность открывать базы данных SQL Server (специально ориентированная на экземпляры SQL Server Express) простым указанием на файл .mdf базы данных SQL Server. Хотя доступ к базе данных через файлы .mdf поддерживался еще в версии ADO.NET 1.0, версия ADO.NET 2.0 теперь дает возможность в строку соединения ConnectionString помещать относительный путь к файлу .MDF, что позволяет применять эту строку вместе с настройками приложения. Кроме того, при использовании параметра User Instance=True SQL Server копирует базы данных master, model и tempdb, а также базу данных пользовательского приложения в частную область данных текущего пользователя. Подобное перемещение заметно упрощает доступ к базе данных и предотвращает повреждение совместно используемой базы данных master и других системных баз данных.

Хотя ADO.NET 2.0 все еще не поддерживает курсоры на стороне сервера, в нем реализована технология, которая гораздо лучше подошла бы многим приложениям. Представьте себе, что SQL Server инициирует возникновение события в приложении при изменении какой-либо строки в заданном наборе строк. Именно это и происходит в новом классе SqlNotificationRequest при работе со службами извещения SQL Server Notification Services. Такое мгновенное извещение позволит разработчикам обновлять данные в локальных кэшах при изменении данных на сервере. Эта технология может работать как с Windows Forms, так и с приложениями ASP.NET.

ADO.NET также поддерживает все новые типы данных SQL Server, включая двоичные данные переменной длины varbinary(max), типы BLOB и CLOB, а также определенные на Common Language Runtime (CLR) пользовательские типы данных (UDT). Появился даже новый клиентский интерфейс SqlClient для применения в основанных на CLR хранимых процедурах, функциях, агрегатах и триггерах.

ADO.NET 2.0 больше не требуется стек MDAC

В прошлом разработчики и архитекторы делали глубокий вдох и надеялись на лучшее, когда объявляли о выходе новой версии стека MDAC. Они знали, что с большой вероятностью это могло разрушить некоторые из уже развернутых ими приложений. С ADO.NET 2.0 больше не придется так беспокоиться о возможной поломке существующего кода, потому что стек MDAC (который содержит ADO на базе COM и избранные библиотеки netlib) для развертывания приложений ADO.NET не требуется. При построении приложений для среды .NET Framework исполняемые модули могут размещаться в одном каталоге, на который не оказывает влияния новый код, установленный после развертывания. Можно даже отметить избранные DLL, которые должны быть установлены и зарегистрированы в общих областях целевой системы или в кэше глобальной сборки Global Assembly Cache (GAC).

Очевидно, что специалисты Microsoft потратили немало времени на разработку новых возможностей ADO.NET 2.0 и на их интеграцию в Visual Studio и SQL Server 2005. Понятно также, что в Microsoft с особым вниманием относятся к сильно типизированным данным, связыванию данных и формированию отчетов. Эти новые возможности призваны помочь разработчикам реализовывать более эффективные, безопасные и быстродействующие проекты с меньшим объемом кода.

Вильям Воэн - Президент компании Beta V Corporation. Имеет звание Microsoft MVP. Работает в компьютерной индустрии с 1972 года. billva@betav.com


Отладка T-SQL в Visual Studio 2005

Для тех, кто занимается разработкой SQL Server, возможность работать с хранимыми процедурами дает заметный выигрыш в производительности. В предшествовавших версиям 2005 года выпусках Visual Basic и Visual Studio разработчикам приходилось быть весьма изобретательными, чтобы вообще заставить работать средства отладки T-SQL. Больше такое не повторится, ситуация исправлена. Отладчик не просто стал работать — специалисты Microsoft добавили превосходные возможности, которые облегчат отладку и настройку даже самых сложных хранимых процедур. В Visual Studio 2005 можно установить точки прерывания, которые будут срабатывать:

  • на n-й раз. В этом случае можно выбрать разные варианты возникновения прерывания: когда показания счетчика будут равны, больше или равны и даже кратны заданному значению. Это значит, что можно вводить прерывания, когда известно, что за хранимой процедурой надо понаблюдать после того, как она вызывалась n раз.
  • когда выполнены условия фильтра. Можно ограничить срабатывание точки прерывания только теми случаями, когда хранимую процедуру инициируют указанные процессы или потоки. Можно указывать название компьютера MachineName, идентификатор процесса ProcessID, название процесса ProcessName, идентификатор потока ThreadID, имя потока ThreadName, объединяя их в выражение операторами AND (&), OR (||) или NOT (!). К примеру, если SQL Server работает на группе серверов, то можно отлаживать хранимую процедуру, когда она запускается на определенном сервере из этой группы.

По-видимому, SQL Server 2005 не поддерживает условные точки прерывания SQL Server, так что выбрать эту возможность нельзя. Другая возможность позволяет указать, что сообщение должно появиться в отладочном окне при срабатывании точки прерывания, как показано на экране A.

Включение отладчика T-SQL также проще осуществить в Visual Studio 2005, чем в предыдущих версиях. Однако эта возможность не включена в Standard Edition, и, чтобы ею воспользоваться, понадобится Professional Edition или Team System Edition.

При отладке конкретной хранимой процедуры нужно задействовать Server Explorer, чтобы открыть эту хранимую процедуру и прийти к той ее строке, где надо прервать выполнение, точно так же, как это делается в Visual Studio 2003. Чтобы установить точку прерывания, следует щелкнуть правой кнопкой мыши на границе, как это делается для обычного кода в редакторе кода хранимой процедуры. Затем нужно открыть окно свойств приложения Application Properties (новинка Visual Studio 2005), открыть закладку Debug и выбрать режим включения отладчика Enable SQL Server debugging. Чтобы Visual Studio прервал исполнение, не надо подсоединяться к процессу, как это было в бета-версиях. При тестировании приложения Visual Studio показывает окно интерактивного редактора T-SQL, после того как хранимая процедура запущена и выполнены условия точки прерывания.


Возвращение возможностей Visual Studio 2003

Microsoft заняла неожиданную позицию в отношении некоторых новых возможностей доступа к данным в Visual Studio 2005. По каким-то причинам разработчики Microsoft Visual Studio решили скрыть отдельные возможности Visual Studio, которыми многие привыкли пользоваться еще с первого выпуска Visual Studio. К примеру, в каждой книге, статье или учебном курсе по ADO.NET объясняется, как создать обновляемый набор данных DataSet с помощью мастера конфигурации адаптера данных DataAdapter Configuration Wizard (DACW). Но, запустив Visual Studio 2005, вы не найдете значка этого мастера на панели инструментов Toolbox, по крайней мере в предназначенной для просмотра членами сообщества июльской версии Community Technology Preview (CTP). Исчезли и значки мастеров команд Command и соединений Connection для каждого из провайдеров. Эти возможности в продукте по-прежнему имеются, но разработчики Microsoft скрыли их. Однако многие, как и я, по-прежнему находят применение этим средствам повышения производительности, особенно при обучении работе с ADO.NET. К счастью, их нетрудно вновь показать. Для этого нужно сделать следующее:

  1. Запустить Visual Studio и создать проект Windows Forms. Проект можно создать на любом языке.
  2. Зафиксировать закладку инструментария Toolbox, потому что мы собираемся создать новую закладку.
  3. Щелкнуть правой кнопкой мыши ниже пунктов инструментария Toolbox и выбрать из выпадающего меню добавление закладки Add Tab. Затем нужно присвоить новой закладке какое-нибудь содержательное имя, например "Отверженные компоненты, которые Microsoft не дает мне применять".
  4. Щелкнуть правой кнопкой мыши на новой закладке, выбрать Choose Items, чтобы показать диалоговое окно выбора инструментов Choose Toolbox Items. Придется подождать, пока происходит ее инициализация.
  5. Пролистать сведения в диалоговом окне до раздела провайдера доступа к данным. Для SQL Server необходимо добавить пункты из списка компонентов SqlClient. Если набрать S, указатель передвинется к первому S. Можно также ввести SqlClient в диалоговом окне фильтра Filter, чтобы найти все нужные компоненты, как показано на рис. Б. Надо просто проверить те компоненты, которые предполагается добавить в заказное меню.
  6. Повторить этот процесс для компонентов ODBC и OLE DB, которые желательно показывать в инструментарии Toolbar.

Когда вы закончите, у вас должна появиться новая закладка Toolbox с компонентами ADO.NET, использованными в последних трех версиях, как показано на рис. С.

К сожалению, не все средства повышения продуктивности работы, к которым мы привыкли в Visual Studio 2003, остались в Visual Studio 2005. К примеру, когда надо было сделать быстрый вызов хранимой процедуры для построения коллекции параметров, Visual Studio 2003 позволял перетащить хранимую процедуру из Server Explorer в форму, а Visual Studio заботился об остальном. Этот метод в Visual Studio 2005 не работает. Но, как я понимаю, одно из новых добавлений может построить коллекцию параметров Parameters из хранимой процедуры, так что еще не все потеряно.

Поделитесь материалом с коллегами и друзьями