SQL.RU
 client/server technologies
 Главная | Документация | Статьи | Книги | Форум | Блоги | Опросы | Гостевая | Рассылка | Работа | Поиск | FAQ |
   
#284<<  #285  >>#286

СОДЕРЖАНИЕ

1.

СТАТЬИ

1.1.

Технология ADO

2.

ССЫЛКИ НА СТАТЬИ

2.1.

Статьи на русском языке

2.2.

Англоязычные статьи

3.

ФОРУМ SQL.RU

3.1.

Самые популярные темы недели

3.2.

Вопросы остались без ответа


Москва, 7-8 декабря 2005 года

СТАТЬИ

Технология ADO

Глава из книги Кэнту М. (Marco Cantu): Delphi 7. Для профессионалов
Авторы рассылки благодарят издательский дом ПИТЕР за предоставленные к публикации материалы.

Аннотация издательства

Издание: 1-е, 2004 год, ISBN: 5-94723-593-5, Формат: 17x24 см, Объем: 1104 стр., Переплет: твердая обложка, Срок выхода: в продаже.

Среда Delphi была и до сих пор является наилучшим сочетанием объектно-ориентированного и визуального программирования не только для Windows, но теперь уже и для Linux и в ближайшем будущем — и для .NET. В этой книге автор попытался практически полностью исключить справочный материал, сконцентрировавшись на технологиях эффективного использования Delphi. В книге приведено более 300 примеров. Как сказал один из подписчиков групп новостей, «книги Кэнту — это по сути „delphi.filtered“, только больше и лучше». Книга предназначена для программистов, разработчиков и всех, серьезно интересующихся программированием в среде Delphi.

[В начало]

Технология ADO (глава 15)

С середины 1980-х годов программисты RDBMS пытаются найти «волшебный ключик» от двери, которая ведет в страну независимости от конкретной базы данных. Проблема состоит в том, что данные могут поступать из самых разных источников, каждый из которых обладает своей спецификой. Однако разработка приложений существенно упростилась бы, если бы удалось создать унифицированный механизм взаимодействия с самыми разными источниками данных. Это мог бы быть универсальный программный интерфейс API, который позволил бы программистам разрабатывать приложения, одинаковым образом взаимодействующие с различными источниками данных. Такие приложения можно было бы использовать для взаимодействия с самими разными системами RDBMS, а также с другими источниками данных. За истекшее время различными компаниями было предложено множество решений в этой области. Наиболее значительными являются Microsoft ODBC (Open Database Connectivity) и Borland IDAPI (Integrated Database Application Programming Interface). Технология Borland IDAPI больше известна под именем BDE (Borland Database Engine).
В середине 1990-х годов, с развитием и распространением технологии COM (Component Object Model), компания Microsoft объявила о постепенном переходе от ODBC к использованию новой технологии OLE DB. Однако OLE DB, по мнению самой компании Microsoft, является интерфейсом системного уровня, этот интерфейс должен использоваться системными программистами. Технология OLE DB является тяжеловесной, сложной и очень чувствительной к ошибкам. Она требует от программиста слишком многого. Работать с OLE DB слишком сложно. Чтобы облегчить работу с OLE DB, был создан дополнительный прикладной уровень, который получил название ADO (ActiveX Data Objects). Работать с ADO существенно проще, чем с OLE DB. Технология ADO предназначена для прикладных программистов.
В главе 14 уже говорилось о том, что компания Borland также решила заменить технологию BDE новой технологией под названием dbExpress. Следует отметить, что ADO по своим возможностям и идеологии в большей степени напоминает BDE. Как BDE, так и ADO поддерживают навигацию, манипулирование наборами данных, обработку транзакций, кэшируемые обновления (в ADO они называются batch updates (пакетные обновления)). Иными словами,концептуально и идеологически ADO и BDE являются похожими технологиями.

ПРИМЕЧАНИЕ

Я хотел бы поблагодарить Гая Смита Ферриера (Guy Smith Ferrier) за то, что он написал данную главу для книги Mastering Delphi 6 (Русское издание: Delphi 6. Для профессионалов. — СПб.: Питер, 2002. — Примеч. перев.). Гай — программист, автор книг и статей, кроме того, он выступает на конференциях. Он является автором нескольких коммерческих программных продуктов и многочисленных внутренних систем как для небольших, так и для крупных компаний. Он написал множество статей для журнала The Delphi Magazine, а также для других изданий. Кроме того, он неоднократно выступал на различных конференциях в Северной Америке и в Европе. Гай живет в Англии вместе с женой, сыном и кошкой.

В данной главе мы рассмотрим работу с ADO. Мы также рассмотрим dbGo — набор компонентов Delphi, который изначально назывался ADOExpress, однако в Delphi 6 был переименован, так как компания Microsoft противится использованию обозначения ADO в продуктах, разработанных сторонними производителями. В среде Delphi вы можете работать с ADO без помощи dbGo. Вы можете импортировать библиотеку типов ADO и получить прямой доступ к интерфейсам ADO. Именно так приходилось работать с ADO в Delphi до появления версии Delphi 5. Однако такой подход не позволяет вам воспользоваться преимуществами встроенной в Delphi инфраструктуры взаимодействия с базами данных. В частности, вы не сможете воспользоваться элементами управления, специально предназначенными для работы с данными, кроме того, для вас будет недоступной технология DataSnap. Во всех примерах данной главы для взаимодействия с ADO используется dbGo. Во-первых, dbGo входит в стандартный комплект поставки Delphi, во-вторых, dbGo является очень удобной технологией. Вне зависимости от того, будете ли вы использовать dbGo или откажетесь от использования этой технологии, материал данной главы будет для вас полезным.

ПРИМЕЧАНИЕ

Помимо dbGo вы можете использовать для взаимодействия с ADO множество других продуктов, разработанных сторонними производителями, например Adonis, AdoSlutio, Diamond ADO и Kamiak.

В данной главе рассматриваются следующие вопросы:

  • Microsoft Data Access Components (MDAC);

  • Delphi dbGo;

  • файлы связи с данными (Data link files);

  • получение информации о схеме;

  • использование механизма Jet;

  • обработка транзакций;

  • отключенные и хранимые на диске наборы записей;

  • модель портфеля и установка MDAC.

[В начало]

MDAC (Microsoft Data Access Components)

На самом деле ADO является частью более крупномасштабной технологии под названием Microsoft Data Access Components (MDAC). Термин MDAC является общим обозначением для всех разработанных компанией Microsoft технологий, связанных с БД. К этому набору относятся ADO, OLE DB, ODBC и RDS (Remote Data Services). Часто приходится слышать, что люди используют термины MDAC и ADO как синонимы, однако это неправильно. На самом деле ADO является лишь одной из частей MDAC. Когда мы говорим о версиях ADO, мы имеем в виду версии MDAC. К основным версиям MDAC относятся версии 1.5, 2.0, 2.1, 2.5 и 2.6. Компания Microsoft распространяет MDAC в виде отдельного продукта. Этот продукт может быть загружен с веб-узла Microsoft бесплатно. Мало того, фактически его можно бесплатно включать в состав ваших собственных продуктов (существуют определенные ограничения, однако большинство разработчиков Delphi без каких-либо проблем удовлетворяют всем этим требованиям). Кроме того, MDAC входит в комплект поставки большинства продуктов Microsoft, имеющих отношение к базам данных. В состав Delphi 7 входит версия MDAC 2.6.
Необходимо принять во внимание два важных обстоятельства. Во-первых, с большой долей уверенности можно сказать, что технология MDAC уже установлена на клиентских компьютерах ваших пользователей. Во-вторых, вне зависимости от версии MDAC, которая была установлена на клиентских компьютерах ваших пользователей, можно с уверенностью сказать, что эта версия рано или поздно будет обновлена до самой свежей (текущей) версии MDAC. Обновление может быть выполнено вами, вашими пользователями или одним из устанавливаемых в системе приложений Microsoft. Подобное обновление фактически невозможно предотвратить, так как MDAC устанавливается в составе такого широко распространенного приложения, как Internet Explorer. К этому следует добавить, что компания Microsoft поддерживает лишь самую последнюю версию MDAC, а также версию, предшествующую самой последней. Исходя из всего этого, можно прийти к выводу: ваше приложение должно работать с самым свежим выпуском MDAC или с предшествующей ему версией.
Как разработчик ADO, вы должны регулярно просматривать страницы веб-узла Microsoft, посвященные MDAC. Для этого следует обратиться по адресу www. microsoft.com/data. Здесь вы сможете бесплатно загрузить самую свежую версию MDAC. Также рекомендуется загрузить MDAC SDK (13 Мбайт), если у вас еще нет этого пакета. На самом деле MDAC SDK входит в состав Platform SDK, так что, если у вас есть Platform SDK, значит, вы уже обладаете MDAC SDK. Пусть пакет MDAC SDK станет вашей библией. Вы должны загрузить его и регулярно обращаться к нему для получения необходимых сведений и ответов на любые вопросы, связанные с ADO. Если вы нуждаетесь в информации, связанной с MDAC, прежде всего вы должны обратиться к MDAC SDK.

[В начало]

Провайдеры OLE DB

Провайдеры OLE DB обеспечивают доступ к источникам данных. В dbExpress для этой цели используются драйверы, а в BDE — связи SQL Links. В процессе установки MDAC в системе автоматически устанавливаются провайдеры OLE DB, перечисленные в табл. 15.1.

Таблица 15.1. Провайдеры OLE DB, входящие в состав MDAC

Драйвер

Провайдер

Описание

MSDASQL

ODBC Drivers

Драйверы ODBC (по умолчанию)

Microsoft.Jet.OLEDB.3.5

Jet 3.5

Только базы данных MS Access 97

Microsoft.Jet.OLEDB.4.0

Jet 4.0

Базы данных MS Access и другие БД

SQLOLEDB

SQL Server

Базы данных MS SQL Server

MSDAORA

Oracle

Базы данных Oracle

MSOLAP

OLAP Services

Online Analytical Processing

SampProv

Sample provider

Пример провайдера OLE DB для файлов CSV

MSDAOSP

Simple provider

Для создания ваших собственных провайдеров для простых текстовых данных

[В начало]

Вот перечень этих провайдеров.

  • ODBC OLE DB используется для обратной совместимости с ODBC. Подробнее ознакомившись с работой ADO, вы узнаете об ограничениях, присущих этому провайдеру.

  • Jet OLE DB — поддержка MS Access и других локальных баз данных. Мы вернемся к рассмотрению этих провайдеров далее.

  • SQL Server обеспечивает взаимодействие с SQL Server 7, SQL Server 2000 и Microsoft Database Engine (MSDE). MSDE — это упрощенная версия SQL Server, в которой отсутствует большинство инструментов, а кроме того, добавлен специальный код, который намеренно снижает производительность в случае, если к базе данных одновременно подключаются более пяти пользователей. К преимуществам MSDE следует отнести то, что этот механизм распространяется бесплатно и полностью совместим с SQL Server.

  • OLE DB для OLAP может использоваться напрямую, однако чаще обращение к нему осуществляется через ADO Multi-Dimentional (ADOMD). ADOMD — это дополнительная технология ADO, специально разработанная для Online Analytical Processing (OLAP). Если ранее вы работали с Delphi Decision Cube, Excel Pivot Tables или Access Cross Tabs, значит, вы работали с одной из форм OLAP. Помимо уже перечисленных здесь провайдеров, компания Microsoft осуществляет поддержку некоторых других провайдеров OLE DB, которые входят в состав других продуктов или в состав SDK.

  • Active Directory Services OLE DB входит в состав ADSI SDK; AS/400 OLE DB и VSAM OLE DB входят в состав SNA Server; Exchange OLE DB входит в состав Microsoft Exchange 2000.

  • Indexing Service OLE DB входит в состав Microsoft Indexing Service — внутренний механизм Windows, ускоряющий поиск информации в файлах при помощи построения каталога с файловой информацией. Служба индексирования Indexing Service интегрирована в IIS и часто используется для индексирования веб-узлов.

  • Internet Publishing OLE DB позволяет разработчикам манипулировать каталогами и файлами с использованием HTTP.

  • Существует также категория провайдеров OLE DB, которые называются провайдерами обслуживания (service providers). Как следует из имени, эти провайдеры обеспечивают обслуживание других провайдеров OLE DB и зачастую активизируются автоматически без участия программиста. Например, служба Cursor Service активизируется в случае, если вы создаете курсор на стороне клиента, а провайдер Persistent Recordset активизируется в случае, если вы собираетесь сохранить данные на локальном диске.

Помимо перечисленных, существует также огромное количество других провайдеров OLE DB для MDAC. Провайдеры OLE DB можно получить как от Microsoft, так и от независимых производителей. Список провайдеров OLE DB очень большой и постоянно меняется, поэтому его невозможно воспроизвести в данной книге. Кроме независимых производителей поставку и поддержку провайдеров OLE DB осуществляют многие производители систем RDBMS. Например, компания Oracle поддерживает собственный провайдер OLE DB под названием ORAOLEDB.

СОВЕТ

Вы уже, наверное, обратили внимание на то, что в списке отсутствует провайдер OLE DB для InterBase. Во-первых, вы можете воспользоваться драйвером ODBC, во-вторых, вы можете использовать провайдер IBProvider, разработанный Дмитрием Коваленко (www.lipetsk.ru/prog/eng/index.html). Наконец, вы можете попробовать разработать провайдер самостоятельно. Для этого удобно использовать комплект OLE DB Provider Development Toolkit, разработанный Бинхом Ли (Binh Ly) и доступный по адресу http://www.techvanguards.com/products/optk/install.htm.

[В начало]

Использование компонентов dbGo

Программисты, уже знакомые с BDE, dbExpess или IBExpress, без труда узнают компоненты, входящие в состав dbGo (табл. 15.2).

Таблица 15.2. Компоненты dbGo

Компонент dbGo

Описание

Эквивалент из комплекта BDE

ADOConnection

Подключение к базе данных

База данных

ADOCommand

Исполняет команду SQL

Нет эквивалента

ADODataSet

Многоцелевой наследник TDataSet

Нет эквивалента

ADOTable

Инкапсулирует таблицу

Table

ADOQuery

Инкапсулирует SQL SELECT

Query

ADOStoredProc

Инкапсулирует сохраненную процедуру (stored procedure)

StoredProc

RDSConnection

Подключение Remote Data Services

Нет эквивалента

Четыре компонента наборов данных (ADODataSet, ADOTable, ADOQuery и ADOStoredProc) фактически полностью реализованы общим для них базовым классом TCustomADODataSet. Этот компонент несет ответственность за выполнение большинства функций, присущих набору данных. Производные компоненты являются тонкими оболочками, которые делают доступными для внешнего мира те или иные возможности базового компонента. Таким образом, компоненты обладают множеством общих черт. Компоненты ADOTable, ADOQuery и ADOStoredProc предназначены для упрощения адаптации кода, ориентированного на BDE. Однако следует иметь в виду, что эти компоненты нельзя считать полностью идентичными эквивалентами аналогичных компонентов BDE. Различия обязательно проявят себя при разработке фактически любого приложения за исключением, может быть, самых тривиальных. В качестве основного компонента при разработке новых программ следует считать компонент ADODataSet, так как, во-первых, этот компонент является достаточно удобным, а во-вторых, его интерфейс сходен с интерфейсом ADO Recordset. В данной главе я продемонстрирую использование каждого из упомянутых компонентов.

[В начало]

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

Хватит теории, давайте перейдем к делу. Разместим на форме компонент ADOTable. Для индикации базы данных, к которой следует подключиться, в рамках ADO используются строки подключения (connection strings). Если вы знаете, что делаете, вы можете набрать строку подключения вручную. Однако в общем случае для создания строки подключения рекомендуется использовать специальный редактор (редактор свойства ConnectionString), рабочее окно которого показано на рис. 15.1.

Щелкните на Build (Сформировать), чтобы запустить разработанный компанией Microsoft редактор строк подключения. Его рабочее окно показано на рис. 15.2. Давайте рассмотрим этот инструмент подробнее, так как он является важным средством при работе с ADO. На первой вкладке показаны провайдеры OLE DB и провайдеры обслуживания, установленные на вашем компьютере. Перечень провайдеров может быть разным для разных версий MDAC, кроме того, новые провайдеры могут появиться в списке в результате установки на компьютере новых прикладных программ. Вернемся к нашему примеру. Выберите провайдер Jet 4.0 OLE DB — для этого сделайте двойной щелчок на надписи Jet 4.0 OLE DB Provider, на экране появится вкладка Connection (Подключение). Внешний вид этой страницы для разных провайдеров может быть разным. Для провайдера Jet редактор предложит вам ввести имя базы данных и аутентификационные данные. Вы можете выбрать MDB-файл базы данных Access, входящий в комплект поставки Delphi (например, C:\Program Files\Common Files\Borland Shared\Data\dbdemos.mdb). Щелкните на кнопке Test Connection (Протестировать соединение) для того, чтобы убедиться в правильности вашего выбора.
На вкладке Advanced (Дополнительно) вы можете контролировать режим доступа к базе данных. Здесь вы можете настроить эксклюзивный доступ или доступ только для чтения. На вкладке All (Все) перечисляются все параметры строки подключения. Этот список может быть разным для разных провайдеров OLE DB. Хорошо запомните эту страницу, так как с ее помощью можно решить множество разнообразных проблем. Закрыв редактор Microsoft, вы вернетесь к редуктору строк подключения Borland. В рабочем окне этого редактора будет показана строка, которая будет присвоена ConnectionString (здесь я разделил ее на несколько строчек, чтобы удобнее было читать):

Provider=Microsoft.Jet.OLEDB.4.0; Data Source=C:\Program Files\Common Files\Borland Shared\Data\dbdemos.mdb; Persist Security Info=False


Строка подключения — это обычная строка символов, в которой через точку с запятой перечисляются параметры и их значения. Такую строку можно редактировать вручную. Параметры и их значения можно перенастраивать в процессе выполнения программы, для этого вы должны написать собственный набор подпрограмм для выполнения поиска параметра в списке и внесения изменения в его значение. Существует также более простой способ: вы можете скопировать строку в список строк Delphi и воспользоваться механизмом обработки пар «имя—значение ». Этот прием будет продемонстрирован в примере JetText, о котором будет рассказано далее в разделе «Доступ к текстовым файлам через Jet».
После того как вы сформировали строку подключения, вы можете выбрать таблицу. Раскройте список таблиц при помощи свойства TableName в окне Object Inspector. Выберите таблицу Customer. Добавьте компонент DataSource и элемент управления DBGrid, а затем соедините их вместе. В результате получилась реальная, хотя и примитивная программа, использующая ADO (полный исходный код оформлен в виде примера FirstAdoExample). Чтобы увидеть данные, занесите в свойство Active набора данных значение True или откройте набор данных внутри обработчика события FormCreate (как это сделано в примере). Второй способ позволяет избежать проблем, если на этапе проектирования база данных недоступна.

СОВЕТ

Если вы планируете использовать dbGo в качестве основной технологии доступа к БД, вам наверняка захочется переместить компонент DataSource на страницу ADO палитры компонентов, чтобы не перескакивать постоянно со страницы на страницу. Если вы используете ADO в комбинации с другой технологией, вы можете имитировать установку DataSource на нескольких страницах. Для этого необходимо создать шаблон (Component Template) компонента DataSource и поместить его на страницу ADO.

[В начало]

Компонент ADOConnection

Когда вы используете компонент ADOTable, он создает свой собственный компонент соединения с БД у вас за спиной. Однако вы вовсе не обязаны использовать именно это соединение. В общем случае вы должны создать свое собственное соединение при помощи компонента ADOConnection, который по сути является эквивалентом компонента SQLConnection из библиотеки dbExpress и компонента Database из библиотеки BDE. Компонент ADOConnection позволяет вам должным образом настроить процедуру аутентификации, контролировать транзакции, напрямую выполнять команды, адресованные БД, кроме того, он позволяет сократить количество подключений, существующих в рамках приложения.
Использовать ADOConnection достаточно просто. Разместите этот компонент на форме и настройте его свойство ConnectionString таким же образом, как вы делали это для компонента ADOTable. Кроме того, вы можете сделать двойной щелчок на компоненте ADOConnection (или выбрать пункт Component Editor в контекстном меню) для того, чтобы напрямую обратиться к редактору строки подключения. Если строка подключения (ConnectionString) указывает на необходимую вам базу данных, вы можете отключить диалоговое окно подключения к БД, для этого необходимо присвоить свойству LoginPrompt значение False. Чтобы в предыдущем примере воспользоваться новым соединением, присвойте значение ADOConnection1 свойству Connection компонента ADOTable1. Вы увидите, что значение свойства ConnectionString станет пустым, так как свойства Connection и ConnectionString исключают друг друга. Преимущество использования ADOConnection состоит в том, что строка подключения теперь хранится в одном месте, вместо того чтобы храниться в нескольких разных компонентах. Еще одно более важное преимущество заключается в том, что несколько разных компонентов могут использовать одно и то же соединение с сервером базы данных. Если вы не добавите в программу вручную сделанный вами компонент ADOConnection, каждый компонент ADO будет обладать собственным соединением с сервером.

[В начало]

Файлы связи с данными (Data Link Files)

Итак, компонент ADOConnection позволяет вам централизовать определение строки подключения в рамках формы или модуля данных. Однако у описанного подхода по-прежнему имеется один существенный недостаток: если вы идентифицируете базу данных при помощи некоторого имени файла, путь к этой базе будет жестко закодирован внутри исполняемого файла приложения. В результате возможности приложения будут существенно ограничены. Чтобы решить проблему, в ADO используются так называемые файлы связи с данными (Data Link Files). Файл связи с данными — это строка подключения, оформленная в виде INIфайла. Например, в рамках Delphi устанавливается файл dbdems.udl, в котором содержится следующий текст:

[oledb] ; Все, что расположено ниже данной строки, является строкой инициализации OLE DB Provider=Microsoft.Jet.OLEDB.4.0; Data Source=C:\Program Files\Common Files\Borland Shared\Data\dbdemos.mdb

Файл связи с данными может обладать любым расширением, однако рекомендуется использовать расширение .UDL. Вы можете создать такой файл при помощи любого текстового редактора. Кроме того, чтобы создать такой файл, вы можете открыть окно проводника Windows, правой кнопкой мыши щелкнуть в одной из папок диска, выбрать New > Text Document (Создать > Текстовый документ), сменить расширение файла на .UDL (я предполагаю, что в вашей системе проводник отображает расширения файлов), затем сделать двойной щелчок на файле — в результате будет запущен редактор строки подключения Microsoft.
Если в редакторе свойства ConnectionString вы выберете Use Data Link File (Использовать файл связи с данными), в этом свойстве будет автоматически размещена строка 'FILE NAME =', за которой будет указано имя файла связи с данными. Такой прием продемонстрирован в примере DataLinkFile. Файлы связи с данными можно разместить в любом месте диска, однако ADO использует для хранения таких файлов некоторый стандартный каталог. Узнать имя этого каталога можно при помощи функции DataLinkDir, которая определяется в модуле ADODB. Если конфигурация — по умолчанию используемая в MDAC, значит, эта функция вернет следующее:

C:\Program Files\Common Files\System\OLE DB\Data Links

[В начало]

Динамические свойства

Представьте, что вы занимаетесь разработкой среднего звена, расположенного между клиентами и несколькими базами данных. С одной стороны, вы должны сформировать единый унифицированный программный интерфейс для доступа к нескольким разным базам данных, с другой стороны, этот интерфейс должен обеспечивать доступ к специфическим возможностям каждой из баз данных. Чтобы решить обе эти задачи, вы можете разработать тяжеловесный интерфейс, который будет представлять собой сумму возможностей всех баз данных, для взаимодействия с которыми он предназначен. Каждый класс такого интерфейса должен включать в себя все возможные свойства и методы, однако для работы с конкретной БД можно будет использовать лишь подмножество свойств и методов класса. Надеюсь, не стоит доказывать вам, что это решение не является самым лучшим. Для решения проблемы в ADO используются динамические свойства (dynamic properties). Фактически все интерфейсы ADO, равно как и соответствующие им компоненты dbGo, обладают свойством под названием Properties. Это свойство является коллекцией свойств, специфичных для текущей базы данных. К этим свойствам можно обратиться, указав их порядковый номер, например:

ShowMessage(ADOTable1.Properties[1].Value);

Однако в большинстве случаев удобнее использовать имя: ShowMessage(ADOConnection1.Properties['DBMS Name'].Value); Набор динамических свойств определяется типом объекта и провайдером OLE DB. Чтобы вы получили представление о важности динамических свойств, я замечу, что такие компоненты, как ADOConnection или Recordset, поддерживают приблизительно 100 динамических свойств. Как будет показано в данной главе, динамические свойства активно используются в ADO для решения множества разнообразных задач.

СОВЕТ

Важным событием, имеющим отношение к использованию динамических свойств, является событие OnRecordsetCreate. Впервые это событие появилось в Delphi 6. Событие OnRecordsetCreate генерируется сразу же после создания Recordset, но перед тем как этот компонент будет открыт. Это событие полезно использовать для настройки тех динамических свойств, которые могут быть настроены только тогда, когда набор записей (Recordset) находится в закрытом состоянии.

[В начало]

Получение информации о схеме

В ADO для получения информации о схеме используется метод OpenSchema компонента ADOConnection. Этот метод принимает четыре параметра:

  • Тип данных, которые будут возвращаться методом OpenSchema. Это значение типа TSchemaInfo: набор из 40 значений, включая перечни таблиц, индексов, столбцов, представлений и сохраненных процедур.

  • Фильтр, который необходимо применить в отношении к данным, прежде чем они будут возвращены. Пример этого параметра будет продемонстрирован чуть позже.

  • GUID для запроса, специфичного для провайдера. Этот параметр используется, только если первый параметр равен значению siProviderSpecific.

  • Компонент ADODataSet, в составе которого будут возвращены данные. Этот параметр иллюстрирует распространенную в рамках ADO тему: если метод возвращает некоторое количество данных, он заносит эти данные в Recordset или, в терминологии Delphi, — в компонент ADODataSet.

Чтобы воспользоваться методом OpenSchema, вы должны открыть ADOConnection. Следующий код, который является частью примера OpenSchema, извлекает список первичных ключей для каждой таблицы и заносит их в компонент ADODataSet:

ADOConnection1.OpenSchema(siPrimaryKeys, EmptyParam, EmptyParam, ADODataSet1);

Каждому полю в составе первичного ключа соответствует одна строка в результирующем наборе данных. Таким образом, если таблица обладает первичным ключом, состоящим из двух полей, в результирующем наборе данных такой таблице будут соответствовать две строки. Значение EmptyParam указывает на то, что параметру присваивается пустое значение, значит, параметр игнорируется. Результат работы кода показан на рис. 15.3.

Если в качестве второго параметра вы передаете значение EmptyParam, в состав результирующего набора данных включается вся информация указанного типа для всей базы данных. Очень часто для удобства вы хотите выполнить фильтрацию информации. Конечно же, для этой цели можно применить к результирующему набору данных традиционный фильтр Delphi (для этого можно использовать свойства Filter и Filtered или событие OnFilterRecord). Однако в этом случае фильтрация будет выполняться на стороне клиента. Второй параметр позволяет выполнить фильтрацию более эффективно на стороне источника информации о схеме. Фильтр определяется как массив значений. Каждый элемент массива обладает специальным смыслом, имеющим отношение к типу возвращаемых данных. Например, массив фильтров для первичных ключей включает в себя три элемента: каталог (то есть базу данных), схему и имя таблицы. Этот пример возвращает перечень первичных ключей в таблице Customer:

var Filter: OLEVAriant; begin Filter := VarArrayCreate([0, 2], varVariant); Filter[2] := 'CUSTOMER'; ADOConnection1.OpenSchema( siPrimaryKeys, Filter, EmptyParam, ADODataSet1); end;

ПРИМЕЧАНИЕ

Ту же информацию можно получить при помощи ADOX. ADOX — это дополнительная технология ADO, которая позволяет вам получать и изменять информацию о схеме. В SQL эквивалентом ADOX является язык DDL (Data Definition Language), то есть выражения CREATE, ALTER, DROP и DCL (Data Control Language), то есть выражения GRANT, REVOKE. В рамках dbGo технология ADOX напрямую не поддерживается, однако вы можете импортировать библиотеку типов ADOX и использовать ее в приложениях Delphi. В отличие от метода OpenSchema, реализация ADOX в Delphi не универсальна, поэтому использовать ее не всегда удобно. Если вы хотите просто получить информацию о схеме, но не изменять ее, для этой цели, как правило, удобнее использовать метод OpenSchema.

[В начало]

Использование механизма Jet

Теперь, когда вы получили базовое представление об MDAC и ADO, мы можем перейти к рассмотрению механизма Jet. Для одних этот механизм представляет интерес, другим он совершенно не нужен. Если вы имеете дело с Access, Paradox, dBase, Excel, Lotus 1-2-3, HTML или данными, хранящимися в текстовых файлах, значит, рассматриваемый здесь материал будет для вас полезным. Если вы не заинтересованы в перечисленных здесь форматах, вы можете пропустить весь этот раздел.
Как правило, механизм Jet ассоциируется с базами данных Microsoft Access. Действительно, Access является основной системой, с которой взаимодействует Jet. Однако помимо Access механизм Jet позволяет работать с множеством других локальных источников данных. Многие не подозревают об этом, однако именно в этом заключается одно из основных преимуществ Jet. Взаимодействие с Access через Jet в стандартном режиме работы этого механизма выполняется относительно просто, поэтому здесь мы не будем рассматривать этот режим использования Jet. Вместо этого мы подробно рассмотрим взаимодействие Jet с другими форматами.

ПРИМЕЧАНИЕ

Механизм Jet входит в состав некоторых (но не всех) версий MDAC. В частности, он отсутствует в версии 2.6. В свое время было много споров относительно того, могут ли программисты, использующие средства разработки, не принадлежащие Microsoft, включать в комплект поставки своих программных продуктов механизм Jet. Официально считается, что такое возможно. Механизм Jet можно загрузить бесплатно с веб-узла компании Microsoft, кроме того, этот механизм входит в комплект поставки многих продуктов компании Microsoft.

Существует два провайдера OLE DB для механизма Jet: Jet 3.51 OLE DB и Jet 4.0 OLE DB. Провайдер Jet 3.51 OLE DB использует Jet 3.51 и поддерживает работу только с Access 97. Если вы будете применять только Access 97 и не собираетесь переходить на Access 2000, то Jet 3.51 в большинстве случаев даст более высокую производительность по сравнению с провайдером Jet 4.0 OLE DB.
Провайдер Jet 4.0 OLE DB поддерживает работу с Access 97, Access 2000 и с драйверами IISAM (Installable Indexed Sequential Access Method). Устанавливаемые драйверы ISAM специально написаны для механизма Jet и обеспечивают доступ к таким форматам, как Paradox, dBase и текстовые файлы. Именно возможность использования этих драйверов делает Jet полезным и удобным инструментом. Полный список драйверов ISAM, установленных на вашем компьютере, определяется набором установленного в системе программного обеспечения. Этот список располагается в реестре по адресу:

HKEY_LOCAL_MACHINE\Software\Microsoft\Jet\4.0\ISAM Formats

В состав комплекта поставки Jet входят драйверы для Paradox, dBase, Excel, текстовых файлов и HTML.

[В начало]

Импорт и экспорт

Механизм Jet удобно использовать для импорта и экспорта данных. Процесс экспортирования данных одинаков для каждого экспортированного формата и состоит из исполнения выражения SELECT в специальном формате. Рассмотрим пример экспортирования данных из базы данных Access в примере DBDemos в таблицу Paradox. Для этого добавим в программу JetImportExport активное соединение ADOConnection с названием ADOConnection1. Это соединение использует механизм Jet для того, чтобы открыть базу данных. Следующий код экспортирует таблицу Customer в файл Customer.db формата Paradox:

SELECT * INTO Customer IN "C:\tmp" "Paradox 7.x;" FROM CUSTOMER

Рассмотрим составные части этого SQL-выражения. После ключевого слова INTO указывается новая таблица, которая будет создана в результате выполнения оператора SELECT. До выполнения этого кода таблица с этим именем должна отсутствовать в базе. После ключевого слова IN указывается база данных, в которую добавляется новая таблица. В Paradox это должен быть каталог, который уже существует на диске. Сразу же после имени базы данных указывается имя драйвера IISAM, который будет использоваться для экспорта данных. В конце имени драйвера обязательно нужно добавить символ точки с запятой (;). Ключевое слово FROM является стандартным компонентом любого выражения SELECT. В рассматриваемом примере эта операция выполняется при помощи компонента ADOConnection1, вместо фиксированного имени каталога используется текущий каталог программы:

ADOConnection1.Execute (''SELECT * INTO Customer IN "' + CurrentFolder + '" "Paradox 7.x;" FROM CUSTOMER');

Точно такой же формат используется в любых операциях экспорта, однако в зависимости от используемого драйвера IISAM имя базы данных интерпретируется по-разному. Вот аналогичное выражение, которое экспортирует данные в таблицу Excel:

ADOConnection1.Execute ('SELECT * INTO Customer IN "' + CurrentFolder + 'dbdemos.xls" "Excel 8.0;" FROM CUSTOMER’);

Новый файл Excel с именем dbdemos.xls создается в текущем каталоге программы. В этот документ Excel добавляется рабочая книга с именем Customer, в которую заносятся все данные из таблицы Customer базы данных Access с именем dbdemo. mdb.
Вот еще одно выражение, которое экспортирует те же самые данные в HTMLфайл:

ADOConnection1.Execute ('SELECT * INTO [customer.htm] IN "' + CurrentFolder + '" "HTML Export;" FROM CUSTOMER');

В данном случае база данных — это каталог (как и в Paradox). Имя таблицы включает в себя расширение .htm, поэтому имя таблицы необходимо заключить в квадратные скобки. Обратите внимание, что драйвер IISAM называется не просто HTML, а HTML Export. Как следует из названия, драйвер позволяет только экспортировать данные, но не позволяет импортировать их.
Наконец, давайте рассмотрим входящий в состав Jet драйвер HTML Import, который является полезным дополнением к HTML Export. Добавьте на форму компонент ADOTable. Настройте строку подключения ConnectionString на использование провайдера Jet 4.0 OLE DB. Присвойте параметру Extended Properties строки подключения значение HTML Import. В качестве имени базы данных укажите имя HTML-файла, который был создан в результате экспорта (чуть ранее), точнее говоря, Customer.htm. Теперь присвойте свойству TableName значение Customer. Откройте таблицу — вы только что импортировали данные из HTML-файла. Имейте в виду, что если вы попытаетесь обновить данные, система выдаст ошибку, так как драйвер предназначен только для импорта. Если вы создали собственный HTMLфайл, в котором содержатся таблицы, и хотите открыть эти таблицы с использованием данного драйвера, вы должны помнить, что имя таблицы — это значение тега caption в HTML-разделе table.

[В начало]

Работа с курсорами

У каждого из наборов данных ADO есть два свойства, которые неразрывно связаны друг с другом и оказывают значительное влияние на ваше приложение. Это свойства CursorLocation и CursorType. Если вы хотите понять принцип функционирования набора данных ADO, вы должны изучить эти два свойства.

[В начало]

Положение курсора (свойство CursorLocation)

Свойство CursorLocation определяет, каким образом осуществляется извлечение и модификация данных. Этому свойству можно присвоить одно из двух значений: clUseClient (курсор на стороне клиента) или clUseServer (курсор на стороне сервера). Выбор значения в большой степени влияет на функциональность, производительность и масштабируемость базы данных.
Клиентский курсор обслуживается механизмом ADO Cursor Engine. Этот механизм является превосходным примером провайдера обслуживания OLE DB: он обеспечивает обслуживание для других провайдеров OLDE DB. Механизм ADO Cursor Engine управляет обработкой данных на стороне клиента. При открытии набора данных все данные результирующего набора перекачиваются с сервера на клиентский компьютер. После этого данные хранятся в памяти, их обновление и обработка осуществляется с использованием ADO Cursor Engine. Этот подход напоминает использование ClientDataSet в приложениях dbExpress. Преимущество состоит в том, что после передачи данных на сторону клиента любые манипуляции с этими данными выполняются значительно быстрее. Кроме того, так как манипуляции выполняются в памяти, механизм ADO Cursor Engine обладает более широкими возможностями, чем любой из курсоров, работающих на стороне сервера. Далее я подробнее рассмотрю эти преимущества, а также другие технологии, основанные на клиентских курсорах (в частности, отключенные и постоянные наборы записей). Курсор на стороне сервера управляется самой системой RDBMS. В клиент-серверной архитектуре, основанной на таких продуктах, как SQL Server, Oracle или InterBase, это означает, что управление курсором осуществляется на удаленном серверном компьютере. Если речь идет о настольной базе данных, такой как Access или Paradox, серверный курсор управляется программным продуктом, обслуживающим базу данных. То есть логически курсор расположен на «сервере», однако физически база данных вместе с курсором располагается на клиентском компьютере. Как правило, серверные курсоры загружаются быстрее, чем клиентские курсоры, так как при открытии набора данных с серверным курсором нет необходимости перемещать все данные на сторону клиента. Благодаря этому серверные курсоры лучше подходят для обслуживания больших наборов данных, то есть тогда, когда клиентский компьютер не обладает объемом памяти, достаточным для хранения всего набора данных. Чтобы понять возможности курсоров обоих типов, лучше всего посмотреть, как они функционируют в той или иной ситуации. Например, можно взять ситуацию блокирования записей. Чуть позднее я более подробно расскажу о блокировании. (Если вы хотите заблокировать запись, вам потребуется серверный курсор, так как система RDBMS должна знать о том, что запись заблокирована.)
Еще одной характеристикой, на которую следует обратить внимание при выборе местоположения курсора, является масштабируемость. Серверные курсоры располагаются на стороне сервера. Чем больше пользователей подключается к базе, тем больше курсоров создается на сервере. С каждым новым курсором нагрузка на сервер возрастает. Таким образом, при увеличении количества пользователей общая производительность системы может существенно понизиться. Используя курсоры на стороне клиента, вы можете существенно повысить масштабируемость вашего приложения. Открытие клиентского курсора обойдется вам дороже, так как в процессе открытия все данные передаются на сторону клиента, однако обслуживание клиентского курсора менее обременительно для сервера, ведь основная связанная с этим нагрузка возлагается на клиентский компьютер.

[В начало]

Тип курсора (свойство CursorType)

Тип курсора во многом определяется местом расположения курсора. Существует пять типов курсоров, один из которых не используется. Неиспользуемый тип называется unspecified (неуказанный). В ADO существует много значений, которые соответствуют неуказанному значению. В Delphi эти значения фактически никогда не используются. Эти значения присутствуют в Delphi только потому, что они присутствуют в ADO. Дело в том, что технология ADO изначально разрабатывалась для таких языков, как Visual Basic и C. В этих языках вы работаете с объектами напрямую, без поддержки вспомогательных механизмов, таких как dbGo. В результате вы можете создать открытый набор записей (в терминологии ADO — recordset), не указывая при этом значения для каждого из свойств. Таким образом, значения некоторых свойств будут не определены. В этом случае свойству присваивается значение unspecified (не указано). Однако в рамках dbGo вы имеете дело с компонентами. Компоненты обладают конструкторами. Конструктор — это функция, которая в обязательном порядке инициализирует каждое из свойств компонента. Когда вы создаете компонент dbGo, каждое из его свойств обладает определенным значением. В итоге отпадает надобность в использовании значения unspecified (не указано).
Тип курсора влияет на то, каким образом происходит чтение и обновление данных. Можно использовать один из четырех типов курсора: Forward-Only (только вперед), Static (статический), Keyset (набор ключей) и Dynamic (динамический). Прежде чем переходить к обсуждению разнообразных комбинаций типов и местоположения курсора, отмечу одно важное обстоятельство: для курсоров, работающих на стороне клиента, можно использовать только один тип: статический курсор. Все остальные типы курсоров могут использоваться только на стороне сервера. Давайте подробнее рассмотрим типы курсоров в порядке возрастания затрат, связанных с их обслуживанием.

  • Forward-only (только вперед). Курсоры этого типа обходятся дешевле всего в смысле затрат. Иными словами, такие курсоры обеспечивают самую высокую производительность. Как следует из имени, курсор Forward-only (только вперед) позволяет вам перемещаться по набору данных в направлении от начала к концу. Курсор читает с сервера количество записей, указанное в свойстве CacheSize (по умолчанию 1), каждый раз, как только он покидает последнюю запись в локальном кэше, он читает с сервера следующую порцию записей. Любая попытка переместиться по направлению к началу набора записей за пределы локального кэша приводит к возникновению ошибки. Это поведение напоминает поведение набора данных в библиотеке dbExpress. Курсор Forwardonly (только вперед) плохо подходит для формирования пользовательского интерфейса, в котором пользователь обладает возможностью контролировать направление перемещения. Вместе с тем, такой курсор вполне подходит для выполнения пакетных операций, формирования отчетов, при построении вебприложений, не сохраняющих информацию о состоянии, — в любой из этих ситуаций вы начинаете с начала набора данных и перемещаетесь по направлению к концу набора данных. По достижении конца набор данных закрывается.

  • Static (статический). При использовании статического курсора набор данных полностью перемещается на сторону клиента, обращение к нему осуществляется при помощи окна размером CacheSize. В результате пользователь получает возможность перемещаться по набору данных в обоих направлениях. Недостаток заключается в том, что данные являются статическими — обновления, добавления и удаления записей, выполняемые другими пользователями, не видны для статического курсора, так как данные курсора уже прочитаны.

  • Keyset (набор ключей). Чтобы понять принцип функционирования этого курсора, разделите слово Keyset на две части: key и set. Key — это ключ, то есть в данном контексте — идентификатор записи. Зачастую имеется в виду первичный ключ. Set — это множество или набор. Получается «набор ключей». При открытии набора данных с сервера читается полный список всех ключей. Например, если набор данных формируется при помощи выражения SELECT * FROM CUSTOMER, значит, список ключей можно сформировать при помощи выражения SELECT CUSTID FROM CUSTOMER. Набор ключей хранится на стороне клиента до закрытия курсора. Когда приложение нуждается в данных, провайдер OLE DB читает строки таблицы, используя для этой цели имеющийся у него набор ключей. В результате клиент всегда имеет дело с обновленными данными. Однако набор ключей является статическим в том смысле, что после открытия курсора в этот набор нельзя добавить новые ключи, также ключи нельзя удалить из набора. Иными словами, если другой пользователь добавляет в таблицу новые записи, эти изменения не будут видны для клиента. Удаленные записи становятся недоступными, а любые изменения в первичных ключах (как правило, пользователям запрещается менять первичные ключи) также становятся недоступными.

  • Dynamic (динамический). Это наиболее дорогостоящий курсор. Динамический курсор функционирует приблизительно так же, как курсор набора ключей. Разница заключается в том, что набор ключей заново читается с сервера каждый раз, когда приложение нуждается в данных, отсутствующих в кэше. Так как значение свойства ADODataSet.CacheSize по умолчанию равно 1, запросы на чтение данных возникают достаточно часто. Можно себе представить дополнительную нагрузку, которую данный курсор создает на сервер DBMS и на сеть. Однако при использовании этого курсора клиент знает не только об изменениях данных, но и о добавлениях и удалениях, выполняемых другими клиентами.

[В начало]

Вы не всегда получаете то, о чем просите

Теперь, когда вы знаете о типах и местоположении курсора, я должен предупредить вас о том, что допускается использование далеко не всех комбинаций типов и местоположений курсора. Как правило, это ограничение связано с типом RDBMS и/или провайдером OLE DB. Например, если курсор располагается на стороне клиента, тип курсора может быть только статическим. Вы можете понаблюдать подобное поведение самостоятельно. Добавьте на форму компонент ADODataSet, настройте свойство ConnectionString для подключения к любой базе данных, после этого присвойте свойству ClientLocation значение clUseCursor, а свойству CursorType — значение ctDynamic. Теперь измените значение свойства Active на True и понаблюдайте за свойством CursorType. Значение этого свойства немедленно изменится на ctStatic. Следует сделать важный вывод: вы далеко не всегда получаете именно то, о чем просите. Открыв набор данных, всегда проверяйте значения свойств — некоторые из них могут самопроизвольно изменить свои значения. Для различных провайдеров OLE DB характерны разные изменения свойств. Приведу лишь несколько примеров:

  • провайдер Jet 4.0 OLE DB изменяет большинство типов курсоров на Keyset (набор ключей);

  • провайдер SQL Server OLE DB часто меняет Keyset (набор ключей) и Static (статический) на Dynamic (динамический);

  • провайдер Oracle OLE DB меняет все типы курсоров на Forward-only (только вперед);

  • провайдер ODBC OLE DB может выполнить самые разные изменения типа курсора в зависимости от используемого драйвера ODBC.

[В начало]

Отсутствие счетчика

Когда вы пытаетесь прочитать свойство RecordCount какого-либо набора данных ADO, иногда вы обнаруживаете, что это свойство равно –1. Курсор типа Forwardonly не знает, какое количество записей входит в состав набора данных, пока он не достигнет конца набора. По этой причине свойство RecordCount равно значению – 1. Статический курсор всегда знает, какое количество записей входит в набор данных, так как статический курсор читает все данные набора в момент открытия. Курсор типа Keyset (набор ключей) тоже знает количество записей в наборе, так как в момент открытия набора данных он извлекает из базы данных фиксированный набор ключевых значений. Таким образом, для курсоров Static и Keyset вы можете обратиться к свойству RecordCount и получить точное количество записей в наборе. Динамический курсор не может достоверно знать количество записей, так как каждый раз при чтении данных он заново читает набор ключей, поэтому свойство RecordCount для этого курсора всегда равно –1. Вы можете вообще отказаться от использования свойства RecordCount и вместо этого использовать выражение SELECT COUNT(*) FROM имя_таблицы. Однако в результате вы получите неточное значение количества записей в таблице базы данных — это значение далеко не всегда совпадает с количеством записей в наборе данных.

[В начало]

Клиентские индексы

Одним из преимуществ курсоров, работающих на стороне клиента, является возможность создания локальных, или клиентских, индексов. Представьте, что у вас есть набор данных ADO с клиентским курсором и что этот набор соединен с таблицей Customer из примера DBDemos. Представьте, что к этому набору подключена сетка DBGrid. Присвойте свойству IndexFieldNames значение CompanyName. Сетка немедленно отобразит записи, упорядочив их в соответствии со значением поля CompanyName. Важно отметить, что для формирования индекса ADO не читает заново данные из источника. Индекс формируется на основе данных, хранящихся в памяти. Благодаря этому, во-первых, индекс формируется достаточно быстро, во-вторых, не создается никакой дополнительной нагрузки на сеть и DBMS. В противном случае одни и те же данные пришлось бы раз за разом передавать через сеть в различном порядке сортировки.
Свойство IndexFieldNames обладает еще кое-какими интересными возможностями. Например, присвойте этому свойству значение Country;CompanyName — вы увидите, что записи сначала отсортированы в соответствии с именем страны, а затем — в соответствии с именем компании. Теперь присвойте свойству IndexField- Names значение CompanyName DESC (ключевое слово DESC должно быть написано заглавными буквами, но не desc или Desc). В результате записи будут отсортированы в порядке убывания значений.
Эта простая, но весьма мощная возможность позволяет вам решить одну из наиболее актуальных проблем, связанных с программированием БД. Пользователи любят задавать неизбежный и неприятный для программистов, но совершенно оправданный вопрос: «Могу ли я щелкнуть на заголовке столбца сетки для того, чтобы отсортировать мои данные?» Существует несколько способов решения этой проблемы. Например, вы можете воспользоваться стандартным (не поддерживающим работу с данными) элементом управления, таким как ListView, который поддерживает встроенный механизм сортировки. Кроме того, вы можете выполнить обработку события OnTitleClick компонента DBGrid и в рамках обработчика заново исполнять SQL-выражение SELECT, добавляя к нему подходящую команду ORDER BY. Однако любое из этих решений нельзя назвать в полной мере удовлетворительным. Если данные кэшируются на стороне клиента (мы уже обсуждали этот подход, когда говорили о компоненте ClientDataSet), вы можете воспользоваться индексом, сформированным в памяти клиентского компьютера. Добавьте следующий обработчик события OnTitleClick для сетки (полный исходный код входит в состав примера ClientIndexes):

procedure Tfrom1.DBGrid1TitleClick(Column: Tcolumn); begin if ADODataSet1.IndexFieldNames = Column.Field.FieldName then ADODataSet1.IndexFieldNames := Column.Field.FieldName + ' DESC' else ADODataSet1.IndexFieldNames := Column.Field.FieldName end;

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

ПРИМЕЧАНИЕ

Все то же самое можно реализовать с использованием компонента ClientDataSet, однако этот компонент не поддерживает ключевого слова DESC, поэтому для сортировки в порядке уменьшения значений вам потребуется написать дополнительный код. Более того, при смене порядка сортировки компонент ClientDataSet будет заново формировать индекс — это ненужная и, возможно, медленная операция.

[В начало]

Клонирование

Технология ADO поддерживает множество интересных возможностей. Вы можете пожаловаться, что обилие возможностей приводит к увеличению размера исполняемого кода, который приходится устанавливать на клиентском компьютере. Однако благодаря обилию возможностей ADO вы можете формировать мощные и надежные приложения. Одной из удобных возможностей ADO является возможность клонирования. Клонированный набор записей — это новый набор записей, который обладает точно таким же набором свойств, как и изначальный. Вначале я объясню, как происходит клонирование, затем расскажу о том, зачем это надо.

ПРИМЕЧАНИЕ

Компонент ClientDataSet также поддерживает клонирование, однако я не упомянул об этой возможности в главе 13.

Для клонирования набора данных (в ADO — набора записей) используется метод Clone. Клонировать можно любой набор данных ADO, однако в данном примере мы будет использовать компонент ADOTable. В программе DataClone (рис. 15.6) присутствуют два компонента ADOTable — один из них подключен к данным, а второй пуст. Оба набора данных подключены к источнику данных DataSource и сетке. Когда пользователь щелкает на кнопке Clone Dataset (клонировать набор данных), выполняется всего одна строка кода, которая клонирует набор данных:

ADOTable2.Clone(ADOTable1);


Эта строка клонирует набор данных ADOTable1 и размещает полученный клон в наборе данных ADOTable2. Благодаря этому вы получаете два представления одних и тех же данных. Каждый набор обладает собственным указателем на текущую запись и собственной копией информации о состоянии, благодаря этому клон никак не влияет на изначальную копию данных. Подобное поведение делает клоны отличным инструментом работы с набором данных, не влияя при этом на изначальные данные. Еще одна интересная возможность: вы можете создать несколько разных активных записей — у разных клонов активные записи могут быть разными. Подобную функциональность нельзя реализовать в Delphi, используя лишь один набор данных.

СОВЕТ

Набор данных можно клонировать только в случае, если он поддерживает закладки (bookmarks). По этой причине курсоры типа «только вперед» и динамические курсоры не могут быть клонированы. Чтобы определить, поддерживает ли набор записей закладки, вы можете воспользоваться методом Supports (например, ADOTable1.Supports([coBookMark])). Побочный эффект клонирования заключается в том, что закладки, созданные одним из клонов, могут использоваться всеми остальными клонами.

[В начало]

Обработка транзакций

В разделе «Использование транзакций» главы 14 мы с вами говорили о том, что механизм транзакций позволяет разработчикам группировать отдельные операции в отношении БД в единую логически неразрывную процедуру.
Обработка транзакций в ADO осуществляется при помощи компонента ADOConnection, для этого используются методы BeginTrans, CommitTrans и RollbackTrans. Действие этих методов сходно с аналогичными методами dbExpress и BDE. Для изучения механизма транзакций, встроенного в ADO, воспользуемся программой TransProcessing. В состав программы входит компонент ADOConnection, строка подключения которого (свойство ConnectionString) настроена на использование провайдера Jet 4.0 OLE DB и на обращение к файлу dbdemos.mdb. В программе присутствует компонент ADOTable, подключенный к таблице Customer и связанный с компонентами DataSource и DBGrid для отображения данных. Наконец, в программе присутствуют три кнопки, предназначенные для выполнения следующих команд:

ADOConnection1.BeginTrans; ADOConnection1.CommitTrans; ADOConnection1.RollbackTrans;


Используя эту программу, вы можете вносить в базу данных изменения, а затем выполнять откат транзакции, то есть отмену этих изменений. В результате база данных будет восстановлена в состояние, в котором она находилась до начала транзакции. Следует отметить, что обработка транзакций выполняется по-разному в зависимости от базы данных и провайдера OLE DB. Например, если вы подключитесь к Paradox с использованием провайдера ODBC OLE DB, вы получите сообщение об ошибке, указывающее на то, что база данных или провайдер OLE DB не могут начать транзакцию. Чтобы определить уровень поддержки транзакций, можно воспользоваться динамическим свойством Transaction DDL соединения:

if ADOConnection1.Properties['Transaction DDL'].Value > DBPROPVAL_TC_NONE then ADOConnection1.BeginTrans;


Если вы попытаетесь обратиться к этой же базе данных Paradox при помощи провайдера Jet 4.0 OLE DB, никакой ошибки не возникнет, однако из-за ограничений провайдера вы не сможете выполнить откат транзакции.
Еще одно странное отличие проявляет себя при работе с Access: если вы используете провайдер ODBC OLE DB, вы сможете использовать транзакции, однако не сможете использовать вложенные транзакции. Попытка открыть новую транзакцию параллельно с уже существующей активной транзакцией приведет к возникновению ошибки. Однако при использовании механизма Jet вы сможете без проблем использовать вложенные транзакции.

[В начало]

Вложенные транзакции

Используя программу TransProcessing, попробуйте выполнить следующий тест.

  1. Активизируйте транзакцию.

  2. Измените значение поля ContactName записи Around The Horn: вместо Thomas Hardy поставьте Dick Solomon.

  3. Активизируйте еще одну, вложенную транзакцию.

  4. Измените значение поля ContactName записи Bottom-Dollar Markets: вместо Elizabeth Lincoln поставьте Sally Solomon.

  5. Выполните откат внутренней транзакции.

  6. Подтвердите внешнюю транзакцию.

В результате модификации должны быть внесены только в запись Around The Horn. Если же внутренняя транзакция будет подтверждена, а в отношении внешней транзакции вы выполните откат, в результате в базу данных вообще не будет внесено ни одного изменения (даже изменения, сделанные в рамках внутренней транзакции). Именно так работают вложенные транзакции. Существует ограничение: Access поддерживает только пять уровней вложения транзакций.
ODBC не поддерживает вложенных транзакций, а провайдер Jet OLE DB поддерживает до пяти уровней вложения. Провайдер SQL Server OLE DB вообще не поддерживает вложения транзакций. Вы должны иметь в виду, что вложение транзакций может обрабатываться по-разному в зависимости от версии SQL-сервера или драйвера. Необходимую информацию можно получить в документации и при помощи экспериментов. Судя по всему, в большинстве случаев внешняя транзакция определяет, будут ли внесены в базу данных изменения, сделанные в рамках внутренней транзакции.

ПРОДОЛЖЕНИЕ СЛЕДУЕТ

[В начало]

ССЫЛКИ НА СТАТЬИ

Статьи на русском языке

Windows Error Reporting - надежда на лучшее
Карен Форстер
Надежда... Я вспоминаю это слово, когда просматриваю письма наших читателей и отвечаю на вопросы относительно использования функции отчета об ошибках - Microsoft Office and Windows Error Reporting (WER, преемник утилиты Dr. Watson, который был написан в свое время командой разработчиков Office, а теперь адаптирован другими подразделениями Microsoft). Так, например, один IT-специалист сказал: "Я надеюсь, что Microsoft действительно обрабатывает эти отчеты и затем пытается решить описанные в них проблемы". Опрос наших читателей показал, что большинство профессионалов ИТ не получают ответа на свои Web-запросы при возникновении сбоев в работе программ Microsoft и не поощряют пользователей посылать в Microsoft подобные запросы. Профессионалы ИТ ничего не знают о дальнейшей с...

Business Process Modeling Notation
Михаил Козлов
CASE: В одном из блогов попалось упоминание о демонстрации прототипа системы Microsoft Business Modeler, которая может быть будет выпущена Microsoft как надстройка над Windows Workflow Faundation. Вроде бы заявляется о планах по поддержке BPEL и Business Process Modeling Notation (BPMN...

Microsoft Solution Accelerator for Business Desktop Deployment
Михаил Козлов
CASE: Многие пользователи хотят использовать последние версии Microsoft Office 2003, т.к. благодаря его новым по сравнению с Office XP возможностям видят значительный прирост эффектиности своей работы...

Обзор корпоративных решений Microsoft на клубе 4CIO.Ru
Михаил Козлов
Кроме выступления на Аксиоме Успеха про технологии Microsoft для бизнес-анализа, вчера вечером я рассказывал любезно пригласившим меня ИТ-директорам - членам клуба 4CIO.Ru - про корпоративные решения Microsoft...

Урок bat-аники
Алексей Александров
Мы все любим писать серьезные вещи на серьезных языках. Шаблоны, C++, Reflection, Perl и многое другое - вот то, что мы любим, то, чему посвящаем длинные сообщения в форумах, то, что снится нам по ночам. Однако в нашей повседневной деятельности встречаются и вещи, которые не так интересны и интеллектуальны. Мы не очень любим говорить об этом, делаем вид, что Это - грязно, нечистоплотно и недостойно нашего внимания. Однако, приходит день, приходит час и перст Судьбы находит нас - нам надо написать еще один батничек: Иногда это запускалка для построения проекта, которая должна при ошибке компиляции скопировать логи на сетевой диск, иногда - запуск обновления исходных текстов из SVN. Иногда - что-нибудь еще. К чему я это все? А к тому, что поговорим мы о полезных хитростях...

Сиквел режут по живому:
Ivan's Blog
MSSQLServer: To resolve this issue, remove the ONLINE index option from the Transact-SQL statement. In SQL Server Management Studio, clear the Allow online processing of DML statements while creating the index box from the Options page of the New Index dialog. Надо заметить что это коснется только операции создания уникального не кластерного индекса, все остальные операции, равно как и операции перестроения (rebuild) любых индексов, по прежнему можно выполнять online....

Журналирование изменений структуры БД и данных
Наталья Кривонос
MSSQLServer: Задачи журналирования различных событий, происходящих в базе данных, рано или поздно встают практически перед каждым, кто имеет отношение к процессу разработки, сопровождения, администрирования, документирования и распространения программных систем, связанных с использованием БД...

Подробное знакомство с RAID-массивами
Александр Радаев
На свете существует много интересного компьютерного железа. И не всегда получается понять, какой от него прок. А ведь именно любопытство в паре с ленью являются главными двигателями прогресса. Главное - это направить свой поток интереса в правильное русло...

Эволюция + революция, или Пути развития современных процессоров
Андрей Бондаренко
Недавнее появление двухъядерных процессоров революционно уже хотя бы потому, что кардинально новые модели процессоров оказались дешевле сравнимых с ними по производительности предшественников...

Как нужно выбирать информационные системы
Федор Петренко
CASE: Удивительный способ выбора информационной системы попался мне в прошлом номере журнала CIO-World, издаваемом ИД Компьютерра....

Программа, печатающая свой текст, T-SQL [Кен Хендерсон]
Олег Михайлик
MSSQLServer: Традиционная задача курса информатики. Нетрадиционный язык....

Англоязычные статьи

Faking arrays in T-SQL stored procedures
bizdatasolutions.com
It is a very common requirement among the SQL Server developer community, how to pass multi-value strings to a stored procedure. As we all know multi-values are totally against the basic foundation of relational model and hence in T-SQL there are certain tricks you can apply to get them done. Note that some of the methods described here may not suit your requirements as it is and may use non-relational and proprietory methods. Also there may be some undocumented methods and the relevant caveats apply. Basic recommendations like use proper datatype conversion techniques, not using SELECT *, not ordering columns by positional numbers etc must be considered for stable production code.

Creating a Number (Sequentially incrementing values) table in T-SQL
bizdatasolutions.com
There are many methods to create a Number/Sequencing table. With these methods, you will end up with a table of sequentially incrementing integer values that can be used for many SQL shortcuts & tricks. You can create one in many ways:

Concatenating row values in the single column
bizdatasolutions.com
Many a time, T-SQL developers are faced with a requirement to generate report-like resultsets right off of a SQL query. It could be a direct data retrieval operation or it could be concatenating the data in a column and updating another table. Sometimes, the developer is even advised that such operations violate First Normal Form. (Talking about 1NF violations in a language like SQL which lacks sufficient domain support, allows NULLs and supports duplicates is somewhat ironic)

SSIS: how to migrate Data Transformation Task of a DTS
Marco Russo
As you already know, the DTS migration wizard of SSIS 2005 doesn't migrate Data Transformation Task in a Data Flow component, but instead it uses to encapsulate each Transformation Task into a legacy embedded DTS2000 package.

Find all customers likely to buy beer
DMTeam
This article shows you how to use DMX concepts from prior tips to tackle a common mining scenario.

ADO.Net 2.0: Relative paths in ConnectionString
Sushil Chordia
In SqlClient Managed Provider, there has always existed (right from ADO.Net 1.0 days) a keyword in the connection string called AttachDbFileName. The user could have the location of the database file assigned to this keyword in the connection string and when opening a connection, this file gets attached as a database on the server. Here is an example:

On-Line Analytical Processing (OLAP)
Buck Woody
In the last article in this series on Business Intelligence, I described the star schema, which lays out data in a different way than the relational database I've explained in other tutorials. The star schema is linked closely with a form of reporting called On Line Analytical Processing, or OLAP.

What to do with IdentifyingAttributes and DefaultDetailAttributes?
Bob Meyers
SQL 2005 report models will ship with a curious and admittedly incomplete solution for handling "the information users typically want to see about an instance of entity X". The problem is that there are many scenarios for which the answer to that question differs:

Migrating DSO code to AMO
Darren Gosbell
I had a question today about how I was going to migrate my DSO code to AMO. (I would have replied directly, but you did not leave a return email address)

More about self-reproducing T-SQL
Ken Henderson
In yesterday's entry, I talked about self-replicating programs and how educational it can be to construct them. Commonly known in hacking parlance as quines, these self-reproducing programs force us to think about how our language works and are a good way to pass the time when your employer thinks you should be working.

How can SQL Server 2005 OnLine Piecemeal Restore improve availability?
Tom Davidson
Question 1: How can SQL Server 2005 OnLine Piecemeal Restore improve availability? Question 2: Can I recover a single object such as a table or specific partition(s) from a partitioned table?

Troubleshoot Connectivity Issue in SQL Server 2005 - Part II
Ming Lu
Please visit http://blogs.msdn.com/sql_protocols/archive/2005/10/22/483684.aspx for troubleshooting connection problems when SNAC(SQL Native Client) connect to SQL Server 2005.

Creation of SOAP(HTTP) SSL endpoint fails with error 0x80070494
Anuradha Rawal
Say you want to create an SSL endpoint for SOAP such as the following

TDSSNIClient initialization failed with error 0xd, status code 0x36.
Vaughn
I've seen this problem posted a couple times on the MSDN forums so I'm including the problem and the solution here. The MSDN SQL Server Data Access Forum is available at:

Back in Redmond and Object Dependencies
Randy Dyess
This week finds me in Seattle setting through a alpha review of one of the new SQL Server exams. I can’t tell you much about this week as it is all under NDA, but I will tell you that it is very interesting setting here surrounded by some very knowledgeable SQL Server folks and listening to their take on things. No matter how much you think you know, another person with the same level of experience will come along and describe their way of using something and it gets you to thinking of my you never thought of that. This is going to be a very informative week.

SSIS: Problems calling SSIS packages from Visual Studio
Jamie Thomson
Over the past couple of days myself and a colleague, Tim Haines, have been grappling with what seemed like an surmountable problem at times. I say we...its been more Tim - he's done a great job in uncovering some inherent problem in Visual Studio (seemingly).

Choosing a Database for High Availability: An Analysis of SQL Server and Oracle
Microsoft
SQL Server 2005 provides enterprise-class high-availability features at a lower cost than Oracle 10g. This white paper compares the high-availability features of SQL Server 2005 and Oracle 10g that address planned and unplanned downtime. Additionally, this paper presents steps to overcoming the primary barriers to high availability.

Microsoft Research Tech Transfers: Better Decisions Faster
Microsoft
Microsoft SQL Server 2005, Visual Studio 2005 and BizTalk Server 2006 are poised for launch, and key components of the products stem from technology transfers by Microsoft Research.

AS 2005: From Release to Launch
Mosha Pasumansky
It is official now - SQL Server 2005 is finally released. I am still trying to comprehend it, so far I am overwhelmed with all kinds of feelings. I kind of started to beleive that it is going to happen only at the beginning of September, when we pretty much stopped doing almost anything about Yukon and switched to SP1 work. Now our product begins its own life, outside of our labs. It is a little bit scary, but I do have full confidence, that it is going to succeed, and succeed in a big way. Starting November 7 there is going to be a wave of launch events all over the world. I felt honoured to be invited to so many of them - the most tempting ones were from Microsoft Russia to attend the launch event in Moscow (followed by Kiev). Since I left USSR 15 years ago - I haven't been back there, and I really wanted to go. Unfortunatelly, for personal reasons, I couldn't go (but two of my collegues and good friends - Sasha Berger and Irina Gorbach will be there). I am going to be in the San Francisco launch event though on November 7, so if you will be there - stop by Analysis Services booth and say hello to me and Rob Zare. Of course, we will answer any questions you might have at that time too. It also will be pretty interesting to compare that launch event to the one in Las Vegas in 1998 when we launched OLAP Services 7.0. Nobody knew what we were about, and the questions were at the level of "So what is that OLAP thing ?". I bet it is going to be very different this time !

Know your enemy
Ken Henderson
In The Art of War, Sun Tzu said, "If you know your enemy and know yourself, you need not fear the result of a hundred battles." But, he went on to warn, "If you know yourself but not the enemy, for every victory gained you will also suffer a defeat."

SSIS: Indirect configurations gotcha
Jamie Thomson
Any developer knows that building solutions in a lab environment is all well and good but its not till you get out into the real world that the foibles and idiosyncrasies of what you're doing really start to scupper your well designed and thoroughly architected solution. Well tonight I faced just such a situation. I'll tell you about it in a bit but first, here's a little demo I'd like you to try. You can do this on Win XP.

SQL Server 2005 Indexes: How many and how big?
Davide Mauri
This little snip of code allows you to list how many indexes are present on a table, their type and how big (kb and mb) they are:

SQL Service Broker Management Studio 2005
Saravana Kumar
I been spending last few months in this project for the connected systems developer competition. After looking at some of the features of SQL server 2005, the one things that attracted me a lot as an Integration person is SERVICE BROKER, which helps your to build scalable, reliable, asynchronous messaging style communication between two SQL Servers (whether its local or situated remotely). Cool thing is SERVICE BROKER is included in the free version of the product SQL EXPRESS as well (there are few limitations, but for basic use its more than enough).

Siebel 7.7 Benchmarks on SQL Server 2005
anuchaw
At Siebel Customer World 2005 held in Boston last week, two new record breaking Siebel Platform Sizing and Performance Benchmarks (PSPP) were announced. The world record for Siebel Scalability is now the 30,000 Siebel Concurrent User Benchmark on SQL Server 2005. This is an amazing performance benchmark with real world Siebel workloads that is done on a 16 X HP Integrirty 8620 machine with 64 GB of RAM. SQL Server 2005 Non Uniform Memory Access (NUMA) and connection affinity features maximised the performance and scalability of the HP Integrity rx8630 database server. Read the full bencmhark results and get information on how it was done

Maintenance checks for SQL Server
Kevin Kline and Baya Pavliashvili
SQL Server has become more self-maintaining with each new release, but the principle "better safe than sorry" still stands: Solid database administration involves performing regular maintenance on system and user databases so that you fix problems before your users find them.

Top 10 new features in SQL Server 2005
Jeremy Kadlec
In the business world, everything is about being "better, faster and cheaper" than the competition -- and SQL Server 2005 offers many new features to save energy, time and money. From programming to administrative capabilities, this version of SQL Server tops all others and it enhances many existing SQL Server 2000 features. Here I'll outline the 10 most significant new features in order of importance:

Planning your SQL Server backup
Greg Robidoux
Planning is the most critical stage, but it's the one that is often done on the fly. When facing a new situation, the choices below are often evaluated very quickly and then a decision is made. Although that approach addresses the issue at hand, it leads to inconsistencies in your overall process.

Configuring the Pivot Component
ashvinis
Sometimes coincidences happen that make you sit back and say Hmm. Couple of days back Ovidiu, one of our senior developers, came by and asked me to blog about the Pivot transform. Then earlier today someone doing a high end POC down south need the same information. Hmm.

The Steps to monitoring greatness
Markus Hain
SQL Server Profiler can correlate Microsoft Windows System Monitor (Performance Monitor in Windows NT 4.0) counters with SQL Server or SQL Server 2005 Analysis Services (SSAS) events. Windows System Monitor logs system activity for specified counters in performance logs. The first thing to remember is in order to have correlating information you need to obviously be in sync - in other words you must start the perfmon trace and profiler trace at the same time or else they won't match up.

The Best Kept Secret About SQL Query Analyzer
Yakov Shlafman
It has been nearly 5 years since SQL Server 2000 was released and almost seven since Query Analyzer was introduced in SQL Server 7. Surely every trick, tip, technique, or secret has been published by now? Perhaps, but this might be a new one from Yakov Shlafman. Check out what he thinks is the best kept secret.

Accurate Numeric Identifiers: Using Verhoeff's Method for Check Digits
Lynn Fields
Check digits–not to be confused with checksums–are often added to numeric identifiers such as customer and product numbers to reduce the chance of incorrect entries. Sequences of numbers are notoriously easy to mistype, and constraints alone generally won't do the job. In this excellent article, Lynn Fields shows you how to implement the "Cadillac" of check digit methods–the Verhoeff Dihedral Group.

Simplify the Creation of XML from SQL Server Data
Hugh Lynch
SQL Server 2000 had extensions built in to allow you to work with XML data, however, most installations did not work with it. XML has proven that it is a very powerful way of transmitting and working with data, but creating it from relational data has proven to be difficult. New author Hugh Lynch, CTO of Restricted Stock Systems, Inc. brin gs us a method for easily creating XML from your SQL Servers.

SQL Server 2005 Secures Your Data Like Never Before
Don Kiely
If you care about your data, you must upgrade to SQL Server 2005 the day it is released. There simply is no other option.

SQL Server 2005: Better Than Ever for Software Developers
Alan Zeichick
Some key improvements in SQL Server 2005 make this developer-friendly database even better than before. Get the details today and get ready for the upcoming release.

Help! My Database is Marked Suspect
Brian Knight
If your database is marked suspect, this will show you a step-by-step guide in how to fix the problem

Microsoft SQL Server Cluster Vs Standby Server
Bilal Ahmed
Building a highly available system is hard. This short white paper from Sonasoft shows some of the differences between a cluster and their standby server product.

Calling COM From T-SQL
Dinesh Asanka
One of the lesser used features of SQL Server is the ability to access the functionality in various DLLs using a COM interface. Dinesh Asanka brings us a basic article with a few examples in how you can work with COM components from inside SQL Server 2000

Dynamic Management Views
graz
The dynamic management views (DMVs) in SQL Server 2005 are designed to give you a window into what's going on inside SQL Server. They can provide information on what's currently happening inside the server as well as the objects it's storing. They are designed to be used instead of system tables and the various functions provided in SQL Server 2000. This article provides an introduction to DMVs and covers a few of the basic views and functions

Compress SQL Server backups using WinZip – Part II
Muthusamy Anantha Kumar
Part I of this article illustrated how to use reasonably priced WinZip to do a full backup and transaction log backup. Part II of this article is going to illustrate how to delete the original backup file after zipping the backup file using WinZip and how to uncompress the compressed backup files using the WinZip command line wzunzip.exe

Backing up and Restoring Databases in SQL 2000
Steven Warren
If you are a Database Administrator (DBA), I have no doubt in my mind that you have been called away from home, dinner, or just plain in the middle of the night to answer a page on a disaster with your database(s). In this field, it is the nature of the beast to get called away at the most inappropriate time. Aren't you glad you backed up your database(s)? Or, did you? In this article, we will introduce you to the different types of backup strategies available in SQL Server 2000

Setting DTS Package Properties at Runtime
Gregory A. Larsen
Wouldn't it be nice if you could change DTS package properties at runtime? If you could then you could have a generic package that processed different files, loaded different database tables and/or connected to different servers, plus a slew of other things. In this article, I will be discussing how to use the dynamic property task to set DTS package properties at runtime

[В начало]

ФОРУМ SQL.RU

Самые популярные темы недели

Ваше мнение об упражнениях SELECT на http://sql.ipps.ru
Новые упражнения на http://sql.ipps.ru
"Мифы сиквела"
SELECT TOP 1, а если наоборот?
Не могу сохранить хранимую процедуру
Линк к гадскому ORACLE... Выполнение "его" процедур?!?
Как выдернуть запросом данные с Oracle
Incorrect syntax near '-'.
Сложный расчет разницы двух нарастающих итогов (расчет просрочки по платежам)
Запрос в text
Шифрование функции
SQL and INSERT into ##TMPTABLE
INSERT INTO... двух связанных таблиц
Триггер: имена изменяемых полей
Нужен ли WITH RECOMPILE в ХП с большим кол-вом параметров
Использование SQL2000 EE больше 2гб памяти
бесконечная обработка директории
Динамически вызвать функцию и....
Удаление записей из связанных таблиц
Проблема с Linked Server

[В начало]

Вопросы остались без ответа

Ошибка при выполнении JOB
Как запустить дебагер VS.NET
Узнать имя DTS из JOB
Что то не могу найти ..
New Survey: Why Upgrade MS SQL Server?
Резервирование базы SQLserver с помощью DataProtector
Простой вопрос
SQL Server Upgrade Wizard
Зеркальный сервер

[В начало]

#284<<  #285  >>#286
Rambler's Top100 Рейтинг@Mail.ru      Хостинг от компании Parking.ru  Administrator: admin@sql.ru 
Copyright: SQL.Ru 2000-2010