WWW.DISSERS.RU

БЕСПЛАТНАЯ ЭЛЕКТРОННАЯ БИБЛИОТЕКА

   Добро пожаловать!

Pages:     | 1 |   ...   | 8 | 9 || 11 |

«David Sceppa Microsoft' ADO.NET Microsoft Press Дэвид Сеппа Microsoft ADO.NET ...»

-- [ Страница 10 ] --

Visual Basic.NET If ViewState("LastVisit") Is Nothing Then IblLastVisit.Text = "This is your first visit! Welcome!" ViewStateC'LastVisit") = Now.ToString Else IblLastVisit.Text = "Welcome back. Your last visit was: " & _ ViewStateC'LastVisit") ViewStateC'LastVisit") = Now.ToString End If Visual C# -NET if

ViewState["LastVisit"] = DateTime.Now.ToStringO;

i else { IblLastVisit.Text = "Welcome back. Your last visit was: " + ViewState["LastVisit"];

ViewState["LastVisit"] = DateTime.Now.ToStringO;

at a naine="'3Ei4ERAT.JR ' cent e-rt -'Micrcsc-t visual studio.NET 7. 0 " conteim-"http: //schemes. 4i1crD5oft.com/1meni sense/ body MS^PQSITIONING-"Gr1dLayOUl:"> •driput 1 type-"Mdden" name-11 VIEMSTATE" alue. db*tMTU30DAzNTQ4MDtOP«sPGk8MT47Pjt5pHqeo;

w8aTwxP]s+o;

«8dDi"PHABQDxu2xhOOZ47bDx>ZVix1b;

ni helghT-.27ps;

w(dth:419px;

7-TNDEX: 101;

LEFT: 22p«;

POSITION: absolute;

TOP: 24px">wel aaek. Your lasi visit was: 3/22/2002 1:59: !РИ | Рис. 14-1. Свойство ViewState страницы ГЛАВА 14 Создание эффективных Web-приложений На рис. 14-1 показан исходный код страницы, которая с помощью показаного фрагмента кода отслеживает в свойстве ViewState время и дату последнего посе щения страницы пользователем. Внимательно изучив HTML-код страницы, вы таи дите, что свойство ViewState хранится в скрытом поле. Поскольку независимо от конфигурации все браузеры поддерживают скрытые поля, свойство ViewState го дится для хранения данных в различных ситуациях, когда задействовать файлы cookie проблематично.

Преимущества Как и в случае с файлами cookie, хранение данных с использованием свойства ViewState страницы позволяет ASP.NET-коду не поддерживать сведений о состоя нии и повышает масштабируемость этого кода. Поскольку свойство ViewState ре ализовано в виде скрытого поля, получать и записывать в него данные можно независимо от параметров безопасности браузера. Кроме того, в отличие от фай лов cookie, свойство ViewState позволяет работать с гораздо большим объемом данных.

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

Свойство ViewState не рассчитано на хранение любых данных, а только тех, которые ASP.NET может сериализовать. Разрешается записывать значения с про стым типом данных, например строки и целые числа, а вот значения с универ сальным типом данных Object записать нельзя, поскольку ASP.NET не умеет сохра нять и создавать экземпляры таких объектов. В свойство ViewState можно запи сывать классы, поддерживающие интерфейс ISerializable, например объекты DataSet и DataTable.

Хранение сведений о состоянии на стороне Web-сервера ASP.NET также предоставляет различные параметры хранения сведений о состоя нии на стороне Web-сервера.

Свойство Session У класса Page есть свойство Session, возвращающее экземпляр класса HttpSessionState.

Как и в случае со свойством ViewState. в свойстве Session страницы разрешается хранить данные. Однако они хранятся на стороне сервера, а не передаются бра узеру вместе с HTML-кодом страницы.

ASP.NET поддерживает параметры, хранящиеся в свойстве Session, до заверше ния пользовательского сеанса. Кроме того, эти параметры хранятся отдельно от аналогичных параметров других сеансов. Таким образом, информация в свойстве Session страницы уникальна для конкретного сеанса.

Создание эффективных приложений с использованием ADO.NET 542 Часть IV Преимущества Поскольку хранение данных осуществляется Web-сервером, а не браузером, га рантируется защита этих данных. Пользователю не удастся средствами браузера просмотреть или изменить содержимое объекта Session. Кроме того, поскольку данные хранятся на сервере, объект Session можно использовать независимо от параметров клиента.

Недостатки Хранение сведений о состоянии с использованием свойства Session снижает мас штабируемость кода на ASP.NET, поскольку при этом для каждого сеанса прило жения требуются определенные ресурсы.

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

50? 500? Теперь умножьте этот объем на число клиентов, использующих данную возможность вашего Web-приложения. J 0 клиентов? 100? 1000? Еще больше? Оце ните общий объем ресурсов сервера, который понадобится вам при хранении све дений о состоянии с использованием свойства Session.

Объект Application Объект Application аналогичен объекте Session за исключением того, что данные, доступные через свойство Application страницы, совместно используются всеми сеансами. Таким образом, данные объекта Application доступны всем клиентам.

Преимущества Как и объект Session, объект Application обеспечивает высокий уровень защиты хранимых в нем данных. Это связано с тем, что данные находятся на сервере и объект Application можно использовать независимо от параметров браузера.

Поскольку данные в объект Application глобальны для всех сеансов приложе ния, этот объект идеально подходит для хранения неизменяемых данных, задей ствованных во всех сеансах, например списка категорий товаров.

Недостатки Данные в объекте Application используют ресурсы сервера, и увеличение их объе ма может отрицательно сказаться на производительности вашего приложения.

Объект Cache Объект Page предоставляет свойство Cache, возвращающее экземпляр объекта Cache.

Объект Cache похож на объект Application с повышенной надежностью. Данные объекта Cache доступны всем сеансам приложения. Просматривают и изменяют содержимое объекта Cache, как и содержимое объекта Application, однако когда вы добавляете в объект Cache элемент данных с помощью метода Add или Insert, он предоставляет следующую функциональность:

• разрешается указать время удаления элемента из кэша, задав конкретное (Date Time) или относительное (TimeSpan) значение;

ГЛАВА 14 Создание эффективных Web-приложений • можно задать значение свойства CacbeDependancy, чтобы при изменении за висимого элемента добавленный вами элемент данных удалялся из кэша. Или же определить значение свойства CacbeDependancy, чтобы элемент удалялся из кэша при редактировании содержимого конкретного XML-файла;

• допустимо указать функцию обратного вызова, к которой обратится ASP.NET при удалении элемента из кэша;

• объект Cache обладает теми же преимуществами и недостатками, что и объект Application, за исключением того, что предоставляет дополнительные возмож ности удаления данных из кэша.

Кэширование вывода Представьте, что в левой части всех страниц вашего Web-приложения отобража ется список разделов узла. Например, список категорий товаров или просто спи сок страниц. Предположим, что данные для построения этого списка хранятся где то в БД и редко изменяются.

Эти данные можно выбрать в объекте DataSet и поместить его в объект Appli cation. Таким образом, ASP.NET-коду не придется каждый раз выбирать эти дан ные при выводе новой страницы. Вероятно, это значительно снизит объем сете вого трафика, однако при выводе новой страницы вы будете по-прежнему пре образовывать содержимое DataSet в HTML-код.

ASP.NET предлагает изящное решение данной проблемы: кэширование выво да. Можно кэшировлть вывод, представляющий страницу или ее часть. Или же полностью или частично кэшировать вывод с кодом страницы на основе пара метров. Если вам нужно кэшировать HTML-данные с кодом странице, не преми ните воспользоваться этой мощной функцией ASP.NET.

Преимущества Если необходимо многократно генерировать один и тот же HTML-код на основе содержимого объекта DataSet, кэширование вывода окажется очень эффективным, поскольку требует меньше ресурсов сервера. Как и в случае с объектом Cache, при кэшировании вывода можно управлять сроком хранения данных.

Недостатки Как и все серверные функции кэширования, кэширование вывода требует ресур сов сервера.

Хранение сведений о состоянии в БД Никто не говорит, что обязательно хранить сведения о состоянии на Web-серве ре. Есть специальные серверы БД, предназначенные для хранения и работы с дан ными. В БД допустимо хранить глобальные и уникальные для сеансов данные ва шего Web-приложения, например содержимое корзины отдельных пользователей.

Представьте, что вашему приложению нужно выполнить настолько сложный или длительный по времени запрос, что вы предпочли бы сохранить результаты этого запроса в отдельной таблице, а не выполнять его каждый раз, когда пользо ватель обращается к следующей странице результатов. Например, пользователь может выполнить в БД поиск приводов CD-RW со скоростью записи не менее 2 Ох, 544 Часть IV Создание эффективных приложений с использованием ADO.NET которые поддерживают интерфейсы USB и FireWire и продаются в магазинах, расположенных не далее, чем в 30 милях от дома пользователя. Вот образец та кого запроса:

SELECT ProductID, ProductName, Description, UnitPrice,... FROM Products WHERE UnitPrice < 200 AND Description LIKE 'ШВГ AND Description LIKE 'XFireWire*' AND...

Представьте, что запрос возвращает 50 записей, на каждой странице отобра жается 10 товаров. Можно выполнять данный запрос каждый раз, когда пользова тель открывает новую страницу результатов, а можно поместить результаты это го запроса в одну из таблиц БД. Воспользовавшись запросом INSERT INTO и иден тификатором сеанса пользователя, чтобы отслеживать принадлежность результатов к определенному сеансу, следует создать вторую таблицу, где будут храниться результаты запросов к первой таблице:

INSERT INTO ProductsQueryCache SELECT ? AS SessionID, ProductID, ProductName, Description, UnitPrice,...

FROM Products WHERE UnitPrice < 200 AND Description LIKE 'MSB*' AND Description LIKE 'XFireWireX 1 AND...

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

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

Примечание Решив воспользоваться описанной техникой, не забудьте удалить кэшированные записи из БД в событии End объекта Session или когда это потребуется.

Преимущества Хранение информации в БД позволяет ASP.NET-коду не поддерживать сведений о состоянии. Данные, хранящиеся в БД, надежны. Если Web-сервер по какой-то при чине откажет, после его восстановления данные из БД снова станут доступны.

Данные из БД имеют высокую степень защиты, поскольку доступны пользовате лю только через ASP.NET-код. БД предназначены для работы с большими набора ми результатов. Если вам действительно требуется поддерживать большие набо ры результатов между обращениями к страницам, лучше всего хранить эти резуль таты в БД.

Недостатки Хранить сведения о состоянии в БД сложнее, чем просто хранить данные в про стых объектах и наборах типа Session, Application, Cache, ViewState или в файле cookie, ГЛАВА 14 Создание эффективных Web-приложений Рекомендации по хранению сведений о состоянии То, как и где вы храните сведения о состоянии, может значительно влиять на производительность, масштабируемость и безопасность ваших Web-приложений.

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

Хранение данных в объектах ViewState Применяйте объекты ViewState, когда имеете дело с небольшими наборами резуль татов и допускаете просмотр этих результатов пользователем. Если же необходи мо обеспечить защиту данных и исключить возможность изменения информации пользователем, храните данные в объекте Session или в БД. Помните: при обра щении к ним данные из объекта ViewSession каждый раз передаются от клиента к серверу и обратно. Чем больше размер содержимого объекта ViewSession, тем боль ше времени уйдет на передачу его по сети.

Хранение данных в объекте Application В объекте Application рекомендуется хранить небольшой объем данных, глобаль ных для всех сеансов вашего приложения. Помните: чем больше данных содер жит объект Application, тем сильнее снижается производительность.

Хранение данных в объекте Session Объект Session рассчитан на хранение небольшого объема данных, критичных для конкретного сеанса, а также предназначен для случаев, когда хранение данных в объекте ViewState неприемлемо.по соображениям безопасности. Помните: чем больше данных в объекте Session, тем сильнее и в несколько раз быстрее по срав нению с объектом Application падает производительность. Казалось бы, всего 100 кбайт данных в объекте Session. Но умножьте это значение на число сеансов, поддерживаемых ASP.NET в конкретный момент времени! Рекомендую вам хранить большой объем данных, уникальных для отдельного сеанса, в БД, Хранение данных в БД Храните большой объем данных, уникальных для отдельного сеанса, в БД, Понятно, что обращаться к таким данным, находящимся в памяти, быстрее, чем получать их из БД. Но если вам требуется хранить большие объемы данных, специфичных для отдельных сеансов, разместив эти данные в БД, вы уменьшите объем памяти сервера, используемый вашим приложением в данный конкретный момент вре мени.

Кэширование вывода Если вам требуется многократно генерировать одинаковый HTML-код, используйте средства кэширования вывода ASP.NET, а не кэшируйте данные, необходимые для генерирования этого HTML-кода.

Часть IV Создание эффективных приложений с использованием ADO.NET Постраничная разбивка информации Компаний, каталог товаров которых может уместиться на одной Web-странице.

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

ASP.NET и ADO.NET предоставляют средства постраничного представления результатов запросов, которые мы сейчас и рассмотрим.

Средства постраничного представления информации, предоставляемые Web-элементом управления DataGrid Web-элемент управления DataGrid включает средства, значительно упрощающие постраничный вывод результатов запроса. Свойства AllowPaging и PagerStyle это го элемента позволяют программно управлять тем, где и как будут выводиться данные, с которыми связан DataGrid. На рис. 14-2 показана Web-страница, созданная с использованием связанного с данными элемента управления DataGrid и его средств постраничного представления информации.

Рис. 14-2. Web-страница, использующая средства постраничного представления информации, предоставляемые элементом управления DataGrid Разработчикам, создающим Web-приложения при помощи Visual Studio.NET, проще всего задать эти свойства средствами диалогового окна Property Builder элемента управления DataGrid. Чтобы запустить его, щелкните на Web-форме эле Создание эффективных Web-приложений ГЛАВА мент управления DataGrid правой кнопкой и выберите в контекстном меню ко манду Property Builder. Затем щелкните в правой панели открывшегося окна ссылку Paging. Откроется диалоговое окно, аналогичное показанному на рис. 14-3.

Рис. 14-3- Задание параметров постраничного представления информации для элемента управления DataGrid при помощи диалогового окна Property Builder Свойство AltowPaging Задавая свойству Allou'Paging значение True, вы указываете элементу управления DataGrid создать ссылки для перемещения между страницами набора результатов, Если значение свойства AllowPagmg — True, сразу после связывания с источником данных элемент управления DataGrid автоматически создает вместе со страницами результатов ссылки для перемещения между этими страницами. Можно указать нужный вид ссылок — кнопки Next (предыдущая страница) и Previous (следую щая страница) или номера, позволяющие перейти к конкретным страницам.

Когда пользователь переходит к новой странице, наступает событие Pagelndex Changed элемента управления DataGrid. Оно позволяет определить, к какой именно странице результатов перешел пользователь, и задать соответствующее значение свойству CurrentPagelndex DataGrid.

Свойства AHowCustomPaging и VirtualltemCount Допустим, вы знаете, как получить содержимое только нужной страницы, и хоти те при помощи средств постраничного представления информации DataGrid со здать ссылки на другие страницы результатов. Задав свойству AllowCustomPaging элемента управления DataGrid значение True, можно задать свойству VirtualttemCount DataGrid значение, представляющее общее число записей в наборе результатов.

При этом DataGrid создает ссылки на страницы, основываясь на значении свой ства VirtualltemCount, а не на числе записей в источнике данных.

Следующий фрагмент кода помещает в объект DataReader только первые 10 записей набора результатов и задает соответствующим свойствам элемента уп Часть IV Создание эффективных приложений с использованием ADO.NET равления DataGrid нужные значения для создания ссылок на другие страницы на бора результатов.

Visual Basic.NET gridResults.Allow/Paging = True gridResults.AllowCustomPaging = True gridResults.CurrentPagelndex = gridResults.PageSize = gridResults.PagerStyle.Mode = PagerMode.NumericPages gridResults.PagerStyle.Position = PagerPosition.TopAndBottom Dim strConn, strSQL As String strConn = "Provider=SQLOLEDB;

Data Source=(local)\NetSDK;

" & _ "Initial Catalog=Northwind;

Trusted_Connection=Yes;

" Dim cnNorthwind As New OleDbConnection(strConn) StrSQL = "SELECT COUNT(CustomerlD) FROM Customers" Dim cmdFetchRowCount As New 01eDbCommand(strSQL, cnNorthwind) strSQL = "SELECT TOP 10 CustomerlD, CompanyName, ContactName, Country " & _ "FROM Customers" Dim cmdFetchOnePage As New 01eDbCommand(strSQL, cnNorthwind) cnNorthwind.Open() grldResults.VirtualltemCount = cmdFetchRowCount.ExecuteScalarQ Dim rdrOnePage As OleDbDataReader = cmdFetchOnePage.ExecuteReader() gridResults.DataSource = rdrOnePage gridResults.DataBind() rdrOnePage.CloseO cnNorthwtnd.CloseO Visual C#.NET gridResults.AllowPaging = true;

gridResults.AllowCustomPaging = true;

gridResults.CurrentPagelndex = 0;

gridResults.PageSize = 10;

gridResults.PagerStyle.Mode = PagerMode.NumericPages;

gridResults.PagerStyle.Position = PagerPosition.TopAndBottom;

string strConn, strSQL;

strConn = "Provider=SQLOLEDB;

Data Source=(local)\\NetSDK;

" + "Initial Catalog=Northwind;

Trusted_Connection=Yes;

";

OleDbConnection cnNorthwind = new OleDbConnection(strConn);

strSQL = "SELECT COUNT(CustomerlD) FROM Customers";

OleDbCommand cmdFetchRowCount = new 01eDbCommand(strSQL, cnNorthwind);

strSQL = "SELECT TOP 10 CustomerlD, CompanyName, ContactName, Country " + "FROM Customers";

OleDbCommand cmdFetchOnePage = new 01eDbCommand{strSQL, cnNorthwind);

cnNorthwind.OpenO;

gridResults.VirtualltemCount = Convert.ToInt32(cmdFetchRowCount.ExecuteScalarQ);

ГЛАВА 14 Создание эффективных Web-приложений OleDbOataReader rdrOnePage = cmdFetchOnePage.ExecuteReader();

gridfiesults.DataSource = rdrOnePage;

gridResults.OataBindO;

rdrOnePage. CloseO;

cnNorthwind.CloseO;

Использованный в данном примере запрос очень прост — он с помощью раз дела ТОР выбирает только первые 10 записей, возвращаемых запросом. Такой синтаксис удобен, когда требуется получить лишь первую страницу данных. Но как же получить содержимое других страниц набора результатов?

Средства постраничного представления информации, предоставляемые методом Fill объекта DataAdapter Как вы помните из главы 5, метод Fill объекта DataAdapter перегружен и одна из его сигнатур позволяет получить часть набора результатов, возвращаемого объектом DataAdapter. Второй параметр этой сигнатуры определяет число записей, пропус каемых перед началом выборки данных, а третий параметр — максимальное число выбираемых записей.

Скажем, вам требуется выводить 10 записей на странице. Тогда для вывода за писей пятой страницы нужно пропустить первые 40 записей и выбрать следую щие 10. Приведенный ниже фрагмент кода помещает в объект DataSet только за писи пятой страницы:

Visual Basic.NET Dim strConn, strSQL As String strConn = "Provider=SQLOLEDB;

Data Source=(local)\NetSDK;

" & "Initial Catalog=Northwtnd;

Trusted_Connection=Yes;

" strSQL = "SELECT CustomerlD, CompanyName, ContactName, Country " & _ "FROM Customers" Dim da As New 01eDbDataAdapter(strSQL, strConn) Dim ds As New DataSetO da.Fill(ds, 40, 10, "Customers") Visual C#.NET string strConn, strSQL;

strConn = "Provider=SQLOLEDB;

Data Source=(local)\\NetSDK;

" * "Initial Catalog=Northwlnd;

Trusted_Connection=Yes;

";

strSQL = "SELECT CustomerlD, CompanyName, ContactName, Country " + "FROM Customers";

OleDbDataAdapter da = new 01eDbDataAdapter(strSQL, strConn};

DataSet ds = new DataSetO;

da.Fill(ds, 40, 10, "Customers");

Этот фрагмент очень прост, но сам подход к решению проблемы имеет зна чительный недостаток. В этом примере БД все равно возвращает данные всех записей таблицы. По-прежнему имеется объективное падение производительно сти, связанное с выборкой 40 записей, которые объект DataAdapter просто отбра сывает и не помещает в объект DataSet.

Создание эффективных приложений с использованием ADO.NET 550 Часть IV Создание запросов, возвращающих страницу данных БД SQL Server и Access позволяют использовать в запросах раздел ТОР, с помощью которого удается возвращать только первые п записей. Так, следующий запрос возвращает первые 10 записей таблицы Customers, упорядочивая их по столбцам Country и CustomerlD:

SELECT TOP 10 CustomerlD, CompanyName, ContactName, Country FROM Customers ORDER BY Country, CustomerlD Если необходимо разбить результаты запроса на страницы, стоит воспользо ваться этим синтаксисом и вернуть только записи для конкретной страницы.

Например, для вывода пятой страницы результатов нужно получить 41—50 запи си таблицы Customers.

SELECT TOP 10 CustomerlD, CompanyName, ContactName, Country FROM Customers WHERE CustomerlD NOT IN (SELECT TOP 40 CustomerlD FROM Customers ORDER BY Country, CustomerlD) ORDER BY Country, CustomerlD Здесь используется подзапрос, выбирающий первые 40 записей и упорядочи вающий их по столбцам Country и CustomerlD. Затем родительский запрос выби рает первые 10 записей, не входящие в набор результатов подзапроса, и опять же упорядочивает их по столбцам Country и CustomerlD. Вот более универсальный синтаксис таких запросов:

SELECT TOP РаэмерСтраницы Поле1, Поле2,... FROM Таблица WHERE ПолеКлюча NOT IN (SELECT TOP ЧислоПропускаеныхЗаписей ПолеКлюча FROM Таблица ORDER BY ПорядокСортировки) ORDER BY ПорядокСортировки И БД SQL Server, и Access поддерживают разделы ТОР и NOT IN. Тем не менее указанные разделы поддерживаются далеко не всеми БД, и следовательно, их нельзя считать универсальным решением. Например, БД Oracle не поддерживают раздел ТОР.

БД Oracle предоставляют функцию, аналогичную по возможностям разделу ТОР — rownum. Oracle нумерует возвращаемые запросом записи, поэтому с по мощью функции rownum вы получите только первые п записей набора результа тов. Тем не менее Oracle генерирует номера записей до сортировки результатов запроса, а значит, чтобы вернуть с помощью функции rownum часть записей за проса, в котором определен порядок сортировки, нужно прибегнуть к маленькой хитрости. Немного обмана и пара подзапросов — и с помощью функции rownum вы вернете нужную часть записей запроса, использующего порядок сортировки, Так, следующий Oracle-запрос возвращает 41 — 50 записи таблицы Customers:

SELECT CustomerlD, CompanyName, ContactName, Country FROM (SELECT CustomerlD, CompanyName, ContactName, Country, rownum AS Row_Num FROM (SELECT CustomerlD, CompanyName, ContactName, Country FROM Customers ORDER BY Country, CustomerlD) Создание эффективных Web-приложений ГЛАВА WHERE rownum <= 10) WHERE ROW_NUM > Примечание Я не считаю себя знатоком СУБД Oracle. Возможно, есть более простой способ создавать такие запросы для БД Oracle.

Приложение PagingOptions На прилагаемом к книге компакт-диске записано Web-приложение PagingOptions.

В нем применяются различные средства, позволяющие пользователю постранич но перемещаться по результатам запроса. В каждом случае данные и ссылки на страницы выводятся средствами элемента управления DataGrid. На одной из стра ниц постраничная разбивка данных осуществляется средствами DataGrid. Другие страницы кэшируют данные в объекты ViewState, Session, а также в БД. Есть стра ница, получающая с помощью подзапросов нужные данные из БД, страница, за писывающая в БД результаты оригинального запроса, а также страница, получа ющая эти записанные результаты.

Редактирование данных на Web-странице Мы обсудили простой способ вывода данных на Web-странице. А как создать Web страницу, позволяющую редактировать представленные на ней данные?

Редактировать данные на Web-странице гораздо сложнее, чем на Windows форме. Помните: элементы управления Web-страницы, связанные с данными, ге нерируют HTML-код на основе источника данных. Если вы выводите данные при помощи связанного элемента управления TextBox и пользователь изменяет его содержимое, это не отразится автоматически на содержимом источника данных.

Для создания Web-страницы, допускающей редактирование данных, нужно выве сти данные, предоставить пользователю возможность изменить их и затем заста вить ASP.NET-код отреагировать на эти изменения и предпринять соответствую щие действия.

Природа Web-приложений, исключающая хранение сведений о состоянии, еще больше усложняет создание Web-страниц, позволяющих пользователю редакти ровать данные. Скажем, вы выводите содержимое записи данных с помощью не скольких элементов управления TextBox. Как, после того как пользователь изме нит содержимое записи и щелкнет кнопку Update, найти нужную запись и внести в нее соответствующие изменения? Кэшировали ли вы при помощи объекта DataSel где-нибудь данные, скажем, в объекте ViewState или Session? Требуется ли вам об ратиться к БД, чтобы повторно выбрать нужную запись данных? Как определить, изменились ли данные с момента первого обращения к ним пользователя?

Упрощение редактирования данных при помощи элемента управления DataGrid Не будем рвать с места в карьер. Для начала посмотрим, как с помощью элемента управления DataGrid реализовать на Web-странице функции, позволяющие выби 552 Часть IV Создание эффективных приложений с использованием ADO.NET рать и редактировать данные. Наша цель — создать Web-страницу, аналогичную показанной на рис. 14-4.

2 SbapptiiBCanlfiDaletwse Mfctoieft КИнпнй Isplnrar a /floealhostphoppineC jrt/stcro&itinuiubsH. во» Kumbtr of Items. Total Cost af Order: $82 00 | Submit Onler ] CoirtnU» Shopp.f Laughing ' Lumberjack Рис. 14-4. Пример Web-страницы, позволяющей редактировать данные Рис. 14-5- Задание параметров редактирования данных в диалоговом окне Property Builder элемента управления DataGrid Точно так же, как DataGrid упрощает создание пользовательского интерфейса для постраничного представления информации, этот элемент управления упро щает разработку' пользовательского интерфейса, позволяющего выбирать и редак тировать записи. Щелкните элемент управления DataGrid в среде Visual Studio.NET правой кнопкой и выберите в контекстном меню команду Property Builder. Откро ГЛАВА 14 Создание эффективных Web-приложений ется диалоговое окно (рис. 14-5), в котором можно отобрать нужные столбцы данных и указать, имеет ли пользователь право редактировать их содержимое.

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

Обработка событий, связанных с редактированием содержимого DataGrid Как бы то ни было, задание свойств элемента управления DataGrid при помощи диалогового окна Property Builder в действительности не предоставляет пользо вателю возможности редактировать данные, с которыми связан DataGrid.

У элемента управления DataGrid на рис. 14-5 есть столбец Edit, Update, Cancel и столбец Delete. Если связать этот элемент управления с источником данных, Web страница выглядит аналогично показанной на рис, 14-6, Total Cost of Order Ш 00 SubmitOKfer Conlinue Shopping Рис. 14-6. Web-страница, использующая средства редактирования данных, предоставляемые элементом управления DataGrid Предположим, пользователь щелкает кнопку Edit первого товара в корзине.

DataGrid не позволяет пользователю редактировать содержимое записи напрямую.

Вместо этого страница обращается к серверу, где наступает событие EditCommand элемента управления DataGrid. В это событие вам следует вручную добавить код, который задавал бы свойству Editltemlndex (порядковый номер редактируемого элемента) DataGrid соответствующее значение.

Затем, когда вы вызовете метод DataBind элемента управления DataGrid, DataGrid добавит в HTML-таблицу элементы управления TextBox, которые позволят пользо вателю изменить содержимое записи. Кроме того, DataGrid добавит для редакти руемой записи кнопки Update и Cancel.

19- 554 Часть IV Создание эффективных приложений с использованием ADO.NET Передача изменений в БД После того как пользователь внесет нужные изменения и щелкнет кнопку 1 Jpdate, наступит событие UpdateCommand элемента управления DataGrid. Его аргументы позволяют определить, какую запись изменил пользователь, а также получить ее текущее содержимое. Тем не менее добавить логику для передачи измененного содержимого записи в БД вам придется вручную.

Внесение изменений в объект DataSet Чтобы внести изменения в объект DataSet найдите с помощью аргументов собы тия UpdateCommand соответствующий объект DataRow, внесите изменения и за тем передайте их с помощью объекта DataAdapter. Следующий фрагмент кода средствами аргументов события UpdateCommand получает название и новое ко личество товара, сведения о котором в корзине изменил пользователь. Затем код передает новые данные в БД с помощью объекта DataAdapter.

Visual Basic.NET Private Sub gridCart_UpdateCommand(ByVal source As Object, _ ByVal e As DataGridCommandEventArgs) Dim daCart As New OleDbDataAdapterQ Dim tblCart As New DataTableQ Dim vueCart As New DataView(tblCart) vueCart.Sort = "ProductName" Dim strNewQuantity As String strNewQuantity = CType(e.Item.Cells(2).Controls(0), TextBox).Text Dim intlndexToEdit As Integer intlndexToEdit = vueCart.Find(e.Item. Cells(1). Text) vueCart(intIndexToEdit)("QuantLty") = Clnt(strNewQuantity) daCart.Update(tblCart) End Sub Visual C#.NET private void gridCart_UpdateCominand{ object source, DataGridCommandEventArgs e) I OleDbDataAdapter daCart = new OleDbDataAdapterf);

DataTable tblCart = new DataTableO;

DataView vueCart = new DataView(tblCart);

vueCart.Sort = "ProductName";

string strNewQuantity;

strNewQuantity = ((TextBox) e.Item.Cells[2].Controls[0]).Text;

int intlndexToEdit;

intlndexToEdit = vueCart.Find(e.Item.Cells(1).Text);

vueCart[irvtIndexToEdit][ "Quantity"] = Convert,Tolnt32{strNewQuantity);

daCart.Update(tblCart);

I Создание эффективных Web-приложений ГЛАВА Создание собственных запросов UPDATE Показанный в предыдущем разделе фрагмент кода с помощью аргументов собы тия UpdateCommand получает название и новое количество товара, сведения о котором Б корзине изменил пользователь. Вместо того чтобы менять содержимое DataSet на основе этих данных и передавать коррективы в БД с помощью объек та DataAdapter, стоит воспользоваться этой же информацией и создать собствен ный запрос UPDATE, например:

UPDATE ShoppingCarts SET Quantity = WHERE ProductName = AND ShoppingCartID = Приложение ShoppingCart Ня прилагаемом к книге компакт-диске записано Web-приложение под названи ем ShoppingCart, позволяющее перемещаться по каталогу БД Northwind и добав лять товары из него в корзину. Кроме того, пользователь может изменять содер жимое корзины, добавляя товары или изменяя их количество. Приложение также позволяет разместить заказ и помещает его в таблицу Order Details БД Northwind.

Web-приложение включает две дополнительных Web-страницы, StoreCartln Database и StoreCartlnViewState, предоставляющих одинаковую функциональность.

Единственное отличие этих страниц в том, где они хранят содержимое корзины пользователя. Как следует из названий, страница StoreCartlnDatabase хранит со держимое корзины пользователя в БД, а страница StoreCartlnViewState — в объекте ViewState.

При создании системы приема заказов через Интернет я бы стал хранить со держимое корзин в БД, но мне подумалось, что полезно показать здесь и реше ние на основе объекта ViewState.

Вопросы, которые стоит задавать почаще Вопрос. Как, прежде чем я свяжу объект DataReader с элементом управления, определить, вернул ли запрос данные?

Ответ. Это — один из распространенных вопросов Web-разработчиков, не име ющий, к сожалению, простого решения. Если с помощью метода DataReader Read определить, вернул ли запрос записи, и затем связать с объектом DataReader элементы управления, первая запись набора результатов запроса в них не отображается.

Если вы просто связываете объект DataReader с элементом упраапения DataGrid, с помощью свойства Count набора Items DataGrid удастся определить, сколько записей вернул запрос. Тем не менее иногда нужно узнать число возвращенных записей до того, как связать элементы управления с объектом DataReader.

Предположим, вы средствами следующего запроса выбираете заказы конкрет ного клиента:

SELECT OrderlD, Customer-ID, OrderDate FROM Orders WHERE CustomerlD = ?

При работе с БД, поддерживающей пакетные запросы, можно выполнить па кетный запрос, который сначала вернет число записей, удовлетворяющий крите рию поиска, а затем вернет сами эти записи, например:

556 Часть IV Создание эффективных приложений с использованием ADO.NET SELECT COUNT(OrderlD) FROM Orders WHERE CustomerlD = ?;

SELECT Order-ID, CustomerlD, QrderDate FROM Orders WHERE CustomerlD = ?

Visual Basic.NET Dim strConn, strSQL As String strConn = "Provider=SQLOLEDB;

Data Source=(local)\NetSDK;

" & "Initial Catalog=Northwind;

Trusted_Connection=Yes;

" Dim en As New OleDbConnection(strConn) strSQL = "SELECT COUNT(OrderlD) FROM Orders WHERE CustomerlD = ? ;

" & _ "SELECT OrderlD, CustomerlD, OrderDate FROM Orders " & _ "WHERE CustomerlD = ?" Dim cmd As New 01eDbCommand(strSQL, en) cmd.Parameters.Add("@CustomerID", OleDbType.WChar, 5) cmd.Parameters.Add("@CustomerID2", OleDbType.WChar, 5) cmd.Parameters("@CustomerID").Value = "ALFKI" cmd.Parameters("@CustornerID2").Value = "ALFKI" cn.OpenO Dim rdr As OleDbDatafteader = cmd.ExecuteReaderO rdr.ReadO If rdr(O) > 0 Tnen 'Запрос вернул записи rdr.NextResultQ gridOrders.DataSource = rdr gridOrders.DataBindO Else 'Запрос не вернул записей End If rdr.CloseO cn.CloseC) Visual C#.NET string strConn, strSQL;

strConn = "Provider=SQLOLEDB;

Data Source=(local)\\NetSDK;

" + "Initial Catalog=Northwind;

Trusted_Connection=Yes;

";

OleDbConnection en = new OleDbConnection(strConn);

StrSQL = "SELECT COUNT(OrderlD) FROM Orders WHERE CustomerlD = ?;

" + "SELECT OrderlD, CustomerlD, OrderDate FROM Orders " + "WHERE CustomerlD = ?";

OleDbCommand cmd = new 01eDbCommand(strSQL, en);

cmd.Parameters,Add("@CustomerID", QleDbType.WChar, 5);

cmd.Parameters.Add("@CustomerID2", OleDbType.WChar, 5);

cmd.Parameters["®CustomerID"].Value = "ALFKI";

cmd.Parameters["@CustomerID2"].Value = "ALFKI";

cn.OpenO;

OleDbDataReader rdr = cmd.ExecuteReaderO;

rdr.ReadO;

if (Convert.Tolnt32(rdr[0]) > 0) ГЛАВА 14 Создание эффективных Web-приложений //Запрос вернул записи rdr.NextResult();

gridOrders.DataSource = rdr;

gridOrders.Datafiind();

> else < //Запрос не вернул записей } rdr. CloseC);

cn.CloseO;

При работе с БД, не поддерживающей пакетные запросы, следует воспользо ваться таким же способом, но выполнять не пакет, а отдельные запросы, Вопрос. Как использовать в Web-приложении оптимистическое управление бло кировками при передаче изменений в БД?

Ответ. На самом деле ответ зависит от требований вашего приложения. В при ложении ShoppingCart при передаче обновлений в БД используются только поля первичного ключа. Эта логика работает, потому что приложение поддерживает отдельную корзину для каждого сеанса. Таким образом, возможность редактиро вания содержимого одной корзины несколькими пользователями исключена, Для более жесткого контроля параллелизма можно непосредственно перед тем, как пользователь начнет редактировать запись, кэширошть ее содержимое. Тогда у вас будут оригинальные значения полей записи, которыми можно воспользо ваться в разделе WHERE запроса UPDATE и исключить возможность обновления записи, если ее уже успел изменить другой пользователь.

Более изящное решение — добавить в БД поле с типом данных timestamp и использовать в разделе WHERE значения первичного ключа и этого поля. При этом уменьшается объем данных, кэшируемых в объекте ViewState, Session или в скры тых полях, Вопрос. У меня есть объект DataSet, включающий два объекта DataTable, между которыми определено отношение на основе объекта DataRelation. Как вывести в связанном элементе управления DataGrid только дочерние записи конкретной родительской записи?

Ответ. У объекта DataRcnv имеется метод GetChtidRows, возвращающий массив объектов DataRow, который содержит только дочерние записи. Тем не менее свя зать элементы управления типа DataGrid с массивом объектов DataRow нельзя.

Можно создать объект DataView, инициализировать его, заполнив содержимым дочернего объекта DataTable, и затем задать свойству RowFiUer объекта DataView такое значение, при котором через DataView окажутся доступными только дочерние записи. К счастью, есть более простой способ.

Создайте объект DataView и инициализируйте его, заполнив содержимым ро дительского объекта DataTable. Затем найдите в объекте DataView нужную роди тельскую запись и с помощью метода Cre&teChildView создайте объект DataView, содержащий только дочерние записи.

558 Часть IV Создание эффективных приложений с использованием ADO.NET Visual Basic.NET Dim dsCustomersOrders As New DataSetf) Dim vueCustomers, vueOrders As DataView vueCustomers = New DataView(dsCustomersOrders.Tables("Customers")) vueCustomers.Sort = "CustomerlD" Dim intCustomerlndex As Integer = vueCustomers.FindC'ALFKI") If intCustomerlndex >= 0 Then 'Located the desired parent row Dim drvCustomer As DataRowView = vueCustomers(intCustomerlndex) vueOrders = drvCustomer.CreateChildView("CustomersOrders") gridOrders.DataSource = vueOrders gridOrders.OataBindO Else 'Невозможно найти нужную родительскую запись End If Visual C#.NET DataSet dsCustomersOrders = new DataSetO;

DataView vueCustomers, vueOrders;

vueCustomers = new DataView(dsCustomersOrders.Tables["Custcnners"]);

vueCustomers.Sort = "CustomerlD";

int intCustomerlndex = vueCustomers.FindC'ALFKI");

if {intCustomerlndex >= 0) { //Located the desired parent row DataRowView drvCustomer = vueCustomers[intCustomerIndex];

vueOrders = drvCustomer,CreateChildViewC'CustomersOrders");

gridOrders.DataSource = vueOrders;

g ridOrders.DataSindQ;

) else I //Невозможно найти нужную родительскую запись ;

ПРИЛОЖЕНИЯ ПРИЛОЖЕНИЕ А Прочие поставщики данных.NET Одесь подробно обсуждается работа с поставщиками данных.NET, отличающи мися от поставщика OLE DB.NET Data Provider. В большинстве показанных ранее фрагментов кода, а также в книге в целом я взаимодействовал с БД при помощи поставщика OLE DB.NET Data Provider. Конечно, существуют и другие поставщи ки данных.NET. Первая версия Microsoft.NET Framework включала поставщик SQL Client.NET Data Provider. Вскоре после этого Microsoft выпустила поставщик ODBC.NET Data Provider. Когда я работал над этой книгой, специалисты Microsoft раз рабатывали поставщик данных Oracle Client.NET Data Provider.

Сейчас мы поговорим о том, как использовать эти поставщики данных.NET и чем они отличаются от поставщика OLE DB.NET Data Provider.

Поставщик данных SQL Client.NET Data Provider Назначение поставщика SQL Client,NET Data Provider — обеспечить максимально быстрый доступ к БД Microsoft SQL Server и Microsoft Desktop Engine (MSDE).

Именованные параметры и маркеры параметров В отличие драйверов OLE DB и ODBC, использующих маркер параметров ?, по ставщик SQL Client.NET Data Provider поддерживает именованные параметры.

Чтобы создать для поставщика SQL Client.NET Data Provider параметризованный запрос, возвращающий заказы конкретного клиента, нужно использовать такой синтаксис:

SELECT OrderlD, Customer-ID, EmployeelD, OrderD ate FROM Orders WHERE CustomeriD = @CustomarID Приложение А Прочие поставщики данных.NET Поставщик OLE DB.NET Data Provider использует позиционные маркеры па раметров ?, и для него приведенный выше запрос будет выглядеть так:

SELECT OrderlD, CustomerlD, EmployeelD, OrderD ate FROM Orders WHERE CustomerXD = ?

Чем вызвана разница в синтаксисе? В целях помощи разработчикам, имеющим опыт работы предыдущими технологиями доступа к данным (OLE DB и ODBC), в поставщике OLE DB.NET Data Provider предусмотрена поддержка универсальных маркеров параметров, использовавшиеся в этих технологиях для создания запросов.

OLE DB и ODBC разрабатывались как универсальные технологии доступа к дан ным. Их целью было создать независимый от СУБД код и заставить базовые ком поненты преобразовывать стандартный синтаксис в код, специфичный для БД.

Так почему же поставщик SQL Client.NET Data Provider применяет именован ные параметры? Потому что того требует SQL Server. Выполнить в SQL Server па раметризованный запрос, включающий маркеры параметров ?. нельзя.

Когда вы обращаетесь к БД SQL Server через поставщик OLE DB.NET Data Provider с использованием параметризованного запроса, поставщик SQL Server OLE DB Provider анализирует запрос и заменяет маркеры параметров именованными па раметрами. Поставщик SQL Server OLE DB Provider поддерживает универсальный стандарт и преобразует запрос в формат, приемлемый для SQL Server. Назначе ние поставщика SQL Client.NET Data Provider — максимально точно сопоставить свои функции аналогичным функциям SQL Server и обеспечить наибольшую про изводительность при работе с БД SQL Server. Таким образом, SQL Client.NET Data Provider не анализирует ваши запросы для преобразования маркеров параметров в именованные параметры.

Специфичные для СУБД поставщики данных.NET рассчитаны на обеспечение максимальной производительности при работе с соответствующими БД. Как след ствие, для достижения высокой производительности приходится частично жерт вовать независимостью от платформы.

Подключение к БД SQL Server с помощью объекта SqIConnection Для подключения к БД поставщик SQL Client.NET Data Provider использует объект SqIConnection. Этот объект позволяет подключаться к БД SQL Server и MSDE. За дать свойство ConnectionString объекта SqIConnection можно явно или при помо щи конструктора. Затем следует вызвать метод SqlConnection.Open-.

Visual Basic.NET Dim strConn As String strConn = "Data Source=(local)\NetSDK;

Initial Catalog=No rthwind;

" & "Trusted_Connection=Yes;

" Dim en As New SqlConnection(strConn) cn.OpenQ cn.CloseO 562 Приложения Visual C#.NET string strConn;

strConn = "Data Source=(local)\\NetSDK;

Initial Catalog=N orthwind;

" + "Trusted_Connection=Yes;

";

SqlConnection en = new SqlConnection(strConn);

cn.0pen();

en.Close();

Вы, вероятно, заметили, что строка подключения здесь практически идентич на строке, использовавшейся для подключения к БД SQL Server и MSDE при помо щи объекта OleDbConnection. Единственное отличие в том, что опущен атрибут Provider^.... Подробнее об атрибутах строки подключения, которые следует при менять при работе с объектом SqlConnection — в разделе документации MSDN, посвященном свойству ConnectionString.

Объект SqlConnection также предоставляет два свойства, отсутствующих у объекта OleDbConnection: PacketSize и Workstationld. Они доступны только для чтения, од нако их значения задают с помощью свойства ConnectionString объекта SqlConnection.

Получение результатов запроса с помощью объекта SqIDataAdapter Для получения результатов запроса и помещения их в объект DatoSet или DataTable применяют объект SqIDataAdapter. Работа с ним идентична использованию объекта OleDbDataAdapter, но есть одно важное отличие. Как уже говорилось ранее, для выполнения параметризованного запроса следует использовать именованные параметры.

Visual Basic.NET Dim strConn, strSQL As String strConn = "Data Source=(local)\NetSDK;

Initial Catalog=No rthwind;

" & _ "Trusted_Connection=Yes;

" strSQL = "SELECT OrderlD, CustomerlD, OrderDate FROM Or ders " & _ "WHERE CustomerlD = eCustomerlO" Dim da As New SqlDataAdapter(strSQL, strConn) Dim param As SqlParameter param = da.SelectCommand.Parameters.Add("@Cust omerlD", SqlDbType.NChar, 5) param.Value = "ALFKI" Dim tbl As New DataTable("Orders") da.Fill(tbl) Visual C#.NET string strConn, strSQL;

strConn = "Data Source=(local)\\NetSDK;

Initial Catalog=N orthwind;

" + "Trusted_Connection=Yes;

";

strSQL = "SELECT OrderlO, CustomerlD, OrderDate FROM Or ders " + "WHERE CustomerlD = $CustomerID";

SqIDataAdapter da = new SqlDataAdapter{strSQL, strConn);

SqlParameter param;

Прочие поставщики данных.NET Приложение А param = da.SelectCommand.Parameters,Add("@Cust omerlD", SqlDOType.NChar, 5);

param.Value = "ALFKI";

DataTable tbl = new DataTablef"Orders");

da.Fill(tbl);

Использование объектов SqICommand и SqIDataReader Объект SqICommand позволяет выполнять командные запросы, а также получать результаты запросов при помощи объекта SqIDataReader.

Visual Basic.NET Dim strConn, strSQL As String strConn = "Data Source=(local)\NetSDK;

Initial Catalog=No rthwind;

" & "Trusted_Connection=Yes;

" strSQL = "SELECT OrderlD, CustomerlD, OrderDate FROM Or ders " & _ "WHERE CustomerlD = @CustomerID" Dim en As New SqlConnection(strConn) Dim crnd As New SqlCommandCstrSQL, en) Dim param As SqlParameter param = cmd.Parameters.Add("@CustomerID", SqiD bType.NChar, 5) param.Value = "ALFKI" cn.0pen() Dim rdr As SqIDataReader = cmd,ExecuteReaderO Do While rdr.Read() Console.WriteLine("OrderID = " & rdr.Get!nt32(0)) Console.WriteLine("CustomerlD = " & rdr.GetString(f)) Console.WriteLine("OrderDate = " & rdr.GetDateTime(2)) Console.WriteLineO Loop rdr.CloseO en,Close() Visual C#.NET string strConn, strSQL;

strConn = "Data Source={local)\\NetSDK;

Initial Catalog=N o r t h w i n d ;

" + "Trusted_Connection=Yes;

";

StrSQL = "SELECT OrderlD, CustomerlD, OrderDate FROM Or ders " + "WHERE CustomerlD = @CustomerID";

SqlConnection en = new SqlConnection(strConn);

SqICommand end = new SqlCommandCstrSQL, en);

SqlParameter param;

param = cmd.Parameters.Add{"@CustomerID", SqlD bType.NChar, 5);

param.Value = "ALFKI";

cn.0pen();

SqIDataReader rdr = cmd. ExecuteReaderO;

while (rdr.ReadO) < Console.WriteLinef'OrderlD = " + rdr.Get!nt32(0));

Console.WriteLine("CustomerID = " +• rdr.GetString(l));

564 Приложения Console. WriteLine("OrderDate = " + rdr.GetDateTime(2));

Console.WriteLineO;

I rdr.Closef);

cn.Close();

Примечание Объект Command не поддерживает значение Table из перечисления CommandType.

Как вы помните из главы 12, объект SqlCommand также предоставляет объект ExecuteXmlReader. Используя его, вы получите результаты запроса FOR XML с по мощью объекта XmlReader, Методы GetSqkTnnfiaHHbix> и пространство имен SqlTypes Как и объект QleDbDataType, объект SqlDataReader предоставляет несколько ме тодов Ое1<ТипДанных>1 позволяющих возвращать значения с разными типами данных.NET. Кроме того, SqlDataReader предоставляет и дополнительные методы СеКТицЦанныхУ, соответствующие различным типам данных из пространства имен System JDataSqlTypes.

Следующий фрагмент получает данные одной из записей таблицы Orders и сохраняет это содержимое с использованием типов данных, относящихся к про странству имен SqlTypes — Sqllnt32. SqlString и SqlDateTime-.

Visual Basic.NET 'Imports System.Data.SqlTypes Dim strConn, strSQL As String strConn = "Data Source=(local)\NetSDK;

Initial Catalog=No rthwind;

" & "Trusted_Connection=Yes;

" strSQL = "SELECT OrderlD, CustomerlD, OrderDate FROM Or ders " & _ "WHERE OrderlD = 10643" Dim en As New SqlConnection(strConn) Dim cmd As New SqlCommand(strSQL, en) Dim rdr As SqlDataReader Dim intOrderlD As Sqllnt Dim strCustomerlD As SqlString Dim datOrderOate As SqlDateTime cn.OpenO rdr = cmd.ExecuteReader(CommandBehavior,Single Row) If rdr.Read Then intOrderlD = rdr.GetSqlInt32(0) StrCustomerlD = rdr.GetSqlString(l) datOrcterDate = rdr.GetSqlDateTime(2) End If rdr.Close() cn.Close() Прочие поставщики данных.NET Приложение А Visual C#.NET //using System.Data.SqlTypes;

string strConn, strSQL;

strConn = "Data Source=(local)\\NetSDK;

Initial Catalog=N orthwind;

" + "Trusted_Connection=Yes;

";

strSQL = "SELECT OrderlD, CustomerlD, OrderDate FROM Or ders " + "WHERE OrderlD = 10643";

SqlConnection en = new SqlConnection(strConn);

SqlCommand cmd = new SqlCommandfstrSQL, en);

SqlDataReader rdr;

Sqllnt32 intOrderlD;

SqlStrlng strCustomerlD;

SqlDateTime datOrderDate;

cn.0pen();

rdr = cmd.ExecuteReader(CommandBehavior.Single Row);

if (rdr.ReadO) { intOrderlD = rdr.GetSqlInt32(0);

strCustomerlD = rdr,GetSqlString(1);

datOrderDate = rdr.GetSqlDateTime(2);

} rdr.CloseO;

cn.CloseO;

Зачем использовать эти специфичные для поставщика типы данных? Основ ных причин две.

• Производительность. Типы данных из пространства имен SqlTypes повыша ют производительность кода, поскольку именно их внутренне использует по ставщик SQL Client.NET Data Provider. Если возвращать данные с использова нием типов данных.NET, вызывая методы Getlnt32, GetString и т.д., поставщику SQL Client.NET Data Provider придется преобразовывать эти данные. Исполь зование специфичных для поставщика типов данных позволяет избежать та кого преобразования. Я обнаружил, что производительность кода на основе пространства имен SqlTypes обычно на 10—15% выше производительности кода, использующего стандартные типы данных.NET, • Простота кода. Мало кому из программистов нравится обрабатывать значе ния NULL. В показанном ранее фрагменте кода, использовавшем стандартные типы данных.NET, нет проверок на наличие значений NULL. Если бы любое из полей в запросе содержало значение NULL, код сгенерировал бы исключение.

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

Тем не менее специфичные для поставщика типы данных позволяют исполь зовать значения NULL. Все классы из пространства имен SqlTypes предоставля ют метод IsNulL Таким образом, результаты запроса можно сохранять с исполь зованием этих типов, не проводя предварительную проверку данных. И хотя такая проверка данных в коде все же требуется, ее можно выполнить позже.

При применении типов SqlTypes обращение к объекту SqlDataReader упроща 566 Приложения ется, т. е. результаты запросов удается получить быстрее. Кроме того, это по зволяет быстрее закрыть объект SqlDataReader и освободить соединение, Вызов хранимых процедур Объект SqlCommand позволяет вызывать хранимые процедуры SQL Sewer и MSDE.

Данный объект предоставляет свойство CommandType, упрощающее код для вы зова хранимый процедур. Можно задать свойству CommandText объекта SqlCommand имя хранимой процедуры, свойству CommandType — значение StoredProcedure и затем вызвать эту хранимую процедуру:

Visual Basic.NET Dim strConn As String strConn = "Data Source=(local)\NetSDK;

Initial CataLog=No rthwind;

" "Trusted_Connection=Yes;

" Dim en As New SqlConnection(strConn) Dim cmd As New SqlCommand("CustOrdersQrders", en) cmd.CommandType = CommandType.StoredProcedure Dim param As SqlParameter param = cmd.Parameters.Add("@CustomerID", SqlD bType.NChar, 5) param.Value = "ALFKI" cn.0pen() Dim rdr As SqlDataReader = cmd.ExecuteReader() Do While rdr.ReadO Console.WriteLine(rdr("QrderID")) Loop rdr.Close() cn.Close() Visual C#.NET string strConn;

strConn = "Data Source=(local)\\NetSDK;

Initial Catalog=N orthwind;

" + "Trusted_Connection=Yes;

";

SqlConnection en = new SqlConnection(strConn);

SqlCommand cmd = new SqlCommandC'CustOrdersOrd ers", en);

cmd.CommandType = CommandType.StoredProcedure;

SqlParameter param;

param = cmd.Parameters.Add("@CustomerID", SqlD bType.NChar, 5);

param.Value = "ALFKI";

cn.OpenQ;

SqlDataReader rdr = cmd. ExecuteReaderQ;

while (rdr.ReadO) Console.WriteLine(rdr["OrderID"]);

rdr.CloseO;

cn.CloseO;

Воспользовавшись средствами трассировки SQL Server, вы увидите, что постав щик SQL Client.NET Data Provider преобразовал эту информацию в следующий синтаксис:

Прочие поставщики данных.NET Приложение А EXEC CustOrdersOrders @CustomerID Для обеспечения максимальной производительности кода используйте такой же синтаксис, но не изменяйте значение свойства CommandType no умолчанию — Text. Чтобы получить с использованием этого синтаксиса данные при помощи параметров вывода, добавьте после имени параметра ключевое слово OUT;

EXEC ХранимаяПроцедура ФЛараметрВвода, @ПараметрВывода OUT Получение информации схемы БД Объект OleDbConnection предоставляет метод GetOleDbScbemaTable, позволяющий получить из БД информацию схемы, например список таблиц или столбцов. Пря мого эквивалента этой функции у поставщика SQL Client.NET Data Provider нет.

Тем не менее SQL Server позволяет получить такие данные с помощью пред ставлений информационной схемы. Следующий запрос возвращает сведения о таблицах БД SQL Server:

SELECT * FROM INFORMATION.SCHEMA.TABLES Для получения сведений о таблицах, столбцах, хранимых процедурах, ограни чениях и т.д. предусмотрены различные представления. Чтобы вам было от чего отталкиваться, я покажу некоторые наиболее распространенные запросы.

Данный запрос возвращает список имен таблиц:

SELECT TABLE_NAME FROH INFORMATION_SCHEMA.TABLES WHERE TABLE.TYPE = 'BASE TABLE Данный запрос возвращает список имен представлений:

SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE.TYPE = 'VIEW Данный запрос возвращает список имен столбцов таблиц:

SELECT TABLE.NAME, COLUMN_NAHE, DATA_TYPE, CHARACTER_MAXIMUM_LENGTH, NUMERIC_PRECISrON, NUMERIC_SCALE FROH INFORMATION.SCHEMA.COLUMNS WHERE TABLE_NAME IN (SELECT TABLE.NAME FROM INFORMATION.SCHEMA.TABLES = 'BASE T A B L E 1 ) WHERE TABLE.TYPE ORDER BY TABLE.NAME Данный запрос возвращает список имен процедур:

SELECT SPECIFIC.NAME FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE.TYPE = 'PROCEDURE' Данный запрос возвращает список параметров этих процедур:

SELECT SPECIFIC.NAME, PARAMETER.NAME, PARAMETER_MODE, DATAJTYPE, CHARACTER_MAXIHUM_LENGTH, NUMERIC_PRECISION, NUMERIC_SCALE FROH INFORMATION_SCHEMA.PARAMETERS WHERE SPECIFIC.NAME IN (SELECT SPECIFIC_NAME FROM INFORMATION SCHEMA.ROUTINES Приложения WHERE ROUTINE. TYPE = 'PROCEDURE') ORDER BY SPECIFIC NAME Подробнее об использовании представлений информационной схемы — в SQL Server Books Online.

Поставщик данных ODBC.NET Data Provider Вскоре после выхода.NET Framework Microsoft выпустила третий поставщик данных.NET — ODBC.NET Data Provider. Он предназначен для взаимодействия с БД, ис пользующими ODBC-драйверы.

Поскольку первая версия поставщика ODBC.NET Data Provider не входит в состав.NET Framework, нельзя просто создать в Visual Studio.NET новый проект и на чать работать с этим поставщиков. Загрузив с Web-узла MSDN и установив постав щик ODBC.NET Data Provider, добавьте в своем проекте ссылку на него при помо щи диалогового окна Add Reference (рис. Л-1).

•NET [COM | Projects Tpa№ ~~~~ ™~ T*l Version O:\WIhlrJHMicrosoft, NEHFra...

7.0.3300..NET Co,,.

D:I.WINNHMicroEoFt.NET\Fra.,, 7,0.3300,.NETRu,,.

d Mterpsoft.DaU.Qcbc.dl I.Q.3300.G O:\Pfogr am Rte^MfcrQSOft.tJ.,.

D;

\ProgramFile5l.SQLXML3,0...

3,0.1523, Microsoft. Cat d,5qlXm D : \WINNT\Micro5oft,NET\Frd.,, 7,0.3300, Microsoft JScript D:\ProgfamFile5y4iciasoft.N,..

Microsoft.msht ml 'I..IV DilProgiam Files \тл\ его soft. N...

7,0.3300, Microsoft, stdformar.

Mcrosoft. VisualBasi с, V,.sa, D;

\WlNNT\Microsoft.NET\Fra...

7,0.3300. D:lW,INNTlMiCtOSOrt.NET\F[a...

7,0.3300, Microsoft.VisualC D : ^S,NETiCommon7\roE\Pu...

Microsoft, VisualStudio,.vccod...

VCCod 7,0.3300..VCProiect 7,0.3300,0 D : \VS.NET\Common7UoriPu.., Microsoft.Visu.

7.П.^ПП П П' \V1.NFTlrnrnmnn7lrnFlfti... \ Mirrrnnfr Umi,.WPrm...

eeted Components:

c soft.oats iOdbt.dl Cancel Рис. А-1. Добавление ссылки на поставщик ODBC.NET Data Provider Из рис. А-1 видно, что пространство имен поставщика ODBC.NET Data Provider отличается от пространств имен поставщиков OLE DB и SQL Client.NET Data Provider. Объекты поставщика ODBC.NET Data Provider, по крайней мере первой его версии, относятся к пространству имен MicrosoftData.Qdbc. Данный поставщик, вероятно, войдет в состав будущих версий.NET Framework, и вполне возможно.

что его пространством имен станет SystemData.Odbc.

В приведенных далее фрагментах кода предполагается, что вы при помощи соответствующих конструкций языка по вашему выбору (команда Import в Visual Basic.NET и команда using в Visual С*.NET) добавили в проект и модуль кода ссылки на поставщик ODBC.NET Data Provider.

Прочие поставщики данных.NET Приложение А Подключение к БД при помощи объекта OdbcConnection Для подключения к БД с помощью поставщика ODBC.NET Data Provider исполь зуется класс OdbcConnection. Создайте экземпляр объекта OdbcConnection, задай те его свойству ConnectionString нужное значение (явно или средствами конструк тора) и вызовите метод OdbcConnection.Open.

Вот несколько примеров строк подключения для взаимодействия с БД при помощи объекта OdbcConnection. Подробнее о подключении в БД — в документа ции, посвященной свойству ConnectionString объекта OdbcConnection, а также в документации вашего ODBC-драйвера.

Подключение к БД SQL Server с указанием имени пользователя и пароля:

Driver={SQL Server};

Server=(local)\NetSDK;

Database=Northwind;

1ЛО=ИмяПользователя;

РИО=Пароль;

Подключение к БД SQL Server по доверенному соединению:

Driver={SQL Serve г};

Server=(local)\NetSDK;

Database=Northwind;

Trusted_Connection=Yes;

Подключение к БД SQL Server с использованием DSN-имсни ODBC ODBC:

05Н=ИмяИсточнжаДаннь1х;

Подключение к БД SQL Server с использованием файлового DSN-имени ODBC:

ОЗН=ИмяФайловогоИсточникаДанных;

Следующий фрагмент кода подключается на локальном компьютере к экземп ляру БД MSDE, устанавливаемому вместе с.NET Framework SDK:

Visual Basic.NET Dim strConn As String strConn = "Driver={SQL Server};

Server=(local)\NetSDK;

" & "Database=Northwind;

Trusted_Connection=Yes;

" Dim en As New OdbcConnection(strConn) cn.OpenO cn.CloseO Visual C#.NET string strConn;

strConn = "Driver={SQL Server};

Server=(local)\\NetSDK;

" + "Database=Northwtnd;

Trusted_Connection=Yes;

";

OdbcConnection en = new OdbcConnection(strConn );

cn.OpenO;

cn.CloseO;

Использование параметризованных запросов Поставщик ODBC.NET Data Provider поддерживает параметризованные запросы точно так же, как и поставщик OLE DB.NET Data Provider. В строке запроса обо значьте параметры с помощью маркеров ? и затем добавьте в набор Parameters 570 Приложения объекта OdbcCommand соответствующие объекты OdbcParameter. Именованные параметры поставщиком ODBC.NET Data Provider не поддерживаются.

Получение результатов запроса с помощью объекта OdbcDataAdapter Получить результаты запроса и поместить их в объект DataSet или DataTahle по зволяет объект OdbcDataAdapter:

Visual Basic.NET Dim strConn, strSQL As String strConn = "Driver=(SQL Server};

Server=(local)\NetSDK;

" & _ "Database=Northwind;

Trusted_Connection=Yes;

" strSQL = "SELECT OrderlD, CustomerlD, OrderDate FROM Or ders " & "WHERE CustomerlD = ?" Dim da As New OdbcDataAdapter(strSQL, strConn} Dim param As OdbcParameter param = da.SelectCommand.Parameters.Add("@Cust omerlD", OdbcType.NChar, 5) param.Value = "ALFKI" Dim tbl As New DataTableC'Orders") da.Fill(tbl) Visual C#.NET string strConn, strSQL;

strConn = "Driver={SQL Server};

Server=(local)\\NetSDK;

" + "Database=Northwind;

Trusted_Connection=Yes;

";

StrSQL = "SELECT OrderlD, CustomerlD, OrderDate FROM Or ders " + "WHERE CustomerlD = ?";

OdbcDataAdapter da = new OdbcDataAdapter(strSQ L, strConn);

OdbcParameter param;

param = da.SelectCommand.Parameters.Add{"@Cust omerlD", OdbcType.NChar, 5);

param.Value = "ALFKI*;

DataTable tbl = new DataTableC'Orders");

da.Fill(tbl);

Просмотр результатов запроса при помощи объекта OdbcDataReader Следующий код основан на том же запросе, но получает и выводит его результа ты с помощью объектов OdbcCommand и OdbcDataReader.

Visual Basic.NET Dim strConn, strSQL As String strConn = "Driver={SQL Server};

Server=(local)\NetSDK;

" & "Database=Northwind;

Trusted_Connection=Yes;

" strSQL = "SELECT OrderlD, CustomerlD, OrderDate FROM Or ders " & _ "WHERE CustomerlD = ?" Dim en As New OdbcConnection(strConn) Прочие поставщики данных.NET Приложение А Dim cmd As New OdbcCommancKstrSQL, en) Dim param As OdocParameter param = cmd.Parameters.Add("@CustomerID", Odbc Type.NChar, 5) param.Value = "ALFKI" cn.OpenO Dim rdr As OdbcPataReader = cmd.ExecuteReader( ) Do While rdr.ReadO Console.WriteLine("OrderID = " & rdr.Get!nt32(0)) Console.WriteLineC'CustomerlD = " & rdr.GetString(1» Console.WriteLine("OrderDate = " & rdr.GetDateTime(2)) Console.WriteLine() Loop rdr.Close() cn.CloseO Visual C#.NET string strConn, strSQL;

strConn = "Driver=(SQL Server};

Server=(local)\\NetSDK;

" + "Database=Northwind;

Trusted_Connection=Yes;

";

strSQL = "SELECT OrderlD, CustomerlD, OrderDate FROM Or ders " + "WHERE CustomerlD = ?";

OdbcConnection en = new OdbcConnection(strConn );

DdbcCommand cmd = new OdbcCommand(strSQL, on);

OdbcParameter param;

param = cmd.Parameters.Add("@CustomerID", Odbc Type.NChar, 5);

param.Value = "ALFKI";

cn.OpenO;

OdbcDataReader rdr = crod.ExecuteReaderO;

while (rdr.ReadO) ( Console.WriteLine("QrderID = " + rdr.GetInt32(0)>;

Console.WriteLineC'CustomerlD = " + rdr.GetString(1»;

Console.WriteLine("OrderDate = " + rdr.GetDateTime(2));

Console.WriteLinef);

!

rdr.Closef);

en.Closef);

Вызов хранимой процедуры В первой версии поставщика ODBC.NET Data Provider объект OdbcCommand не поддерживает значений Table и StoredProcedure из перечисления CommandType. Для вызова хранимых процедур с помощью поставщика ODBC.NET Data Provider вам потребуется изучить синтаксис CALL ODBC. К счастью, он прост:

{? = CALL MyStoredProc(?, ?, ?)} Перед именем хранимой процедуры следует добавить ключевое слово O\LL.

Чтобы передать в вызове хранимой процедуры параметры, независимо от их типа (параметры ввода, вывода или ввода-вывода) используйте маркер ?. Маркеры па 572 Приложения раметров разделяются запятыми, а список параметров нужно заключить в скоб ки. Для перехвата возвращаемого значения добавьте перед ключевым словом кон струкцию ?=, точно так же, как если бы в коде требовалось получить значение, возвращаемое вызовом функции. Весь запрос следует заключить в фигурные скобки.

Следующий фрагмент кода вызывает параметризованную хранимую процеду ру с использованием поставщика ODBC.NET Data Provider:

Visual Basic.NET Dim strConn, strSQL As String strConn = "Driver={SQL Server};

Server={local)\NetSDK;

" & "Database=Northwind;

Trusted_Connection=Yes;

" strSQL = "{CALL CustOrdersOrdersC?)}" Dim en As New OdbcConnection(strConn) Dim cmd As New OdbcCommand(strSQL, en) Dim pa ram As OdbeParameter param = cmd. Parameters.Add("@CiJStomerID", Odbc Type.NChar, 5) param.Value = "ALFKI" cn.OpenO Dim rdr As OdbcDataReader = cmd,ExecuteReader( ) Do While rdr.ReadO Console.WriteLineC'OrderlD = " & rdr.Get!nt32(0)) Console.WriteLine("OrderDate = " & rdr.GetDateTime(l)) Console. WriteLineO Loop rdr.CloseO cn.Close() Visual C#.NET string strConn, strSQL;

strConn = "Driver={SQL Server};

Server=(local)\\NetSDK;

" + "Database=Northwind;

Trusted_Connection=Yes;

";

strSQL = "{CALL CustOrdersOrdersC?)}";

OdbcConnection en = new OdbcConnection(strConn };

OdbcCommand cmd = new OdbcCommand(strSQL, en);

OdbcParameter param;

param = cmd.Parameters.Add("@CustomerID", Odbc Type.NChar, 5);

param.Value = "ALFKI";

cn.OpenO;

OdbcDataReader rdr = cmd.ExecuteReaderO;

while (rdr.ReadO) -, Console.WriteLine("OrderID = " + rdr.Get!nt32(0));

Console.WriteLineC'QrderDate = " + rdr.GetDateTime(l));

Console.WriteLineO;

) rdr.CloseO;

cn.CloseO;

Прочие поставщики данных.NET Приложение А Получение информации схемы БД К сожалению, поставщик ODBC.NET Data Provider, no крайней мере первая его версия, не предоставляет средств получения информации схемы БД. У этого по ставщика нет эквивалента метода QleDhConnection.GetOleDbSchema. Чтобы полу чить из БД SQL Server и MSDE сведения схемы, по-прежнему можно выполнять запросы к представлениям информационных схем, обсуждавшимся в разделе, посвященном поставщику SQL Client.NET Data Provider, но такие запросы, под держиваются не всеми СУБД. Возможно, в следующих версиях поставщика эти ограничения будут преодолены, Поставщик данных Oracle Client.NET Data Provider На момент написания этой книги специалисты Microsoft разрабатывали постав щик данных.NET для БД Oracle. Он рассчитан на взаимодействие с БД Oracle вер сий 8i и более поздних и позволит работать с новыми типами данных Oracle, такими, как LOB и BFILE. Кроме того, поставщик позволит выбирать содержимое нескольких курсоров REF из хранимой процедуры.

Microsoft не сообщает, как и где будет выпущен поставщик Oracle Client.NET Data Provider и будет ли он отдельным компонентом или составной частью по следующих версий.NET Framework. Если поставщик станет отдельным компонен том, в проектах на него придется добавлять ссылку, как описано в разделе, посвя щенном поставщику ODBC.NET Data Provider. На момент написания данной кни ги пространство имен поставщика Oracle Client.NET Data Provider — MicrosoftDa ta.OracteCHent.

Предполагается, что Oracle Client.NET Data Provider будет взаимодействовать с вашими БД Oracle при помощи клиентских библиотек Oracle. Для взаимодей ствия с БД Oracle посредством поставщика Oracle Client.NET Data Provider вам следует установить клиентские компоненты Oracle версии 8.1.7 или более поздней.

Кроме того, для каждой БД, к которой вы будете подключаться, необходимо с помощью утилиты конфигурирования клиента Oracle определить псевдоним.

В показанных далее фрагментах кода предполагается, что вы при помощи со ответствующих конструкций языка по вашему выбору (команда Import в Visual Basic.NET и команда using в для Visual С*.NET) добавили в проект и модуль кода ссыл ки на поставщик Oracle Client.NET Data Provider.

Подключение к БД при помощи объекта OracleConnection Для подключения к БД Oracle используется объект OracleConnection. Как и при работе с другими поставщиками данных.NET, создайте экземпляр объекта Oracle Connection, задайте его свойству ConnectionString нужное значение (явно или сред ствами конструктора) и вызовите метод OracleConnection.Open.

Visual Basic.NET Dim strConn As String strConn = "Data Source=MyOracleDatabaseAlias;

" & _ "User ID=MyUserID;

Password=MyPasswor d;

" 574 Приложения Dim en As New OracleConnection(strConn) cn.Openf) cn.Close() Visual C#.NET string strConn;

strConn = "Data Source=MyOracleDatabaseAlias;

" + "User ID=MyUserID;

Password=MyPasswor d;

";

OracleConnection en = new OracleConnection(str Conn);

cn.OpenO;

cn.CloseO;

Использование параметризованных запросов Как и поставщик SQL Client.NET Data Provider, Oracle Client.NET Data Provider поддерживает только именованные параметры. Единственное отличие в том, что перед параметром должно стоять двоеточие, т. е. параметризованный Oracle запрос выглядит так:

SELECT EMPNO, ENAME FROM EHP WHERE JOB = ;

JOB Получение результатов запроса с помощью объекта OracleDataAdapter Следующий фрагмент кода заполняет с помощью объекта OracleDataAdapter объект DataTable результатами показанного ранее параметризованного запроса.

Visual Basic.NET Dim strConn, strSQL As String strConn = "Data Source=MyOracleDatabaseAlias;

" & _ "User ID=HyUserID;

Password=MyPasswor d;

" StrSQL = "SELECT EMPNO, ENAME FROM EHP WHERE JOB = :JOB " Dim da As New OracleDataAdapter(strSQL, strCon n) Dim param As OracleParameter param = da.SelectCommand.Parameters.Add(":JOB", OracleType.VarChar, 9) param.Value = "CLERK" Dim tbl As New DataTable() da.Fill(tbl) Console.WriteLine("Retrieved " & tbl.Rows.Count & " row(s)") Visual C#.NET string strConn, strSQL;

strConn = "Data Source=MyOracleDatabaseAlias;

" + "User ID=MyUserID;

Password=MyPasswor d;

";

StrSQL = "SELECT EMPNO, ENAHE FROM EMP WHERE JOB = :JOB ";

OracleDataAdapter da = new OracleDataA6apter(s trSQL, strConn);

OracleParameter param;

param = da.SeLectCommand.Parameters.Addf";

JOB", OracleType.VarChar, 9);

Прочие поставщики данных.NET Приложение А param.Value = "CLERK";

DataTable tbl = new DataTableO;

da.Fill(tbl);

Console.WriteLine("Retrieved " + tbl.Rows.Count + " row(s}");

Просмотр результатов запроса при помощи объекта OracleDataReader Следующий фрагмент кода возвращает те же данные с использованием объекта OracleDataReader.

Visual Basic.NET Dim strConn, strSQL As String strConn = "Data Source=MyOracleDatabaseAlias;

" & "User ID=MyUserID;

Password=HyPasswor d ;

" strSQL = "SELECT EHPNO, ENAME FROM EHP WHERE JOB = :JOB " Dim en As New OracleConnection(strConn) Dim cmd As New OracleCommandCstrSQL, en) Dim param As OracleParameter param = cmd.Parameters.Add(":JOB", OracleType. VarChar, 9) param.Value = "CLERK" cn.Openf) Dim rdr As OracleDataReader = cmd.Executefleade r() Do While rdr.ReadO Console.WriteLine("EmpNo = " & rdr.GetDecimal(Q)) Console.WriteLineC'EName = " & rdr.GetString(l)) Console.WritelineO Loop rdr.Close{) cn.CloseO Visual C#.NET string strConn, strSQL;

strConn = "Data Source=MyOracleDatabaseAHas;

" + "User ID=MyUserID;

Password=MyPasswor d;

";

strSQL = "SELECT EMPNO, ENAME FROM EMP WHERE JOB = :JOB ";

OracleConnection en = new OracleConnection(str Conn);

OracleCommand cmd = new OracleCommand(strSQL, en);

OracleParameter param;

param = cmd.Parameters.Add(":JOB", OracleType. VarChar, 9);

param.Value = "CLERK";

cn.OpenO;

OracleOataReader rdr = cmd.ExecuteReader();

while (rdr.ReadO) { Console.WriteLineC'EmpNo = " + rdr.GetDecimal(O));

Console.WriteLineC'EName = " + rdr.GetString{1»;

Console.WriteLineO;

576 Приложения rdr.Close();

cn.CloseO;

Специфичные для Oracle типы данных Поставщик Oracle Client.NET Data Provider включает специфичные для Oracle типы данных, точно так же, как SQL Client.NET Data Provider — для SQL Server. Исполь зование таких типов данных повышает производительность кода и ускоряет вы борку данных из объекта DataReader, поскольку сохранять значения с этими ти пами данных допустимо без предварительной проверки на наличие значений NULL.

Кроме того, многие из этих типов данных предоставляют дополнительную фун кциональность, недоступную при использовании соответствующего типа дан ных.NET.

Следующий фрагмент кода получает и выводит результаты запроса с исполь зованием специфичных для Oracle типов данных.

Visual Basic.NET Dim strConn, strSQL As String strConn = "Data Source=HyOracleDatabaseAlias;

" & _ "User ID=MyUserID;

Password=MyPasswor d;

" StrSQL = "SELECT EMPNO, ENAME FROM EMP WHERE JOB = :JOB " Dim en As New OracleConnection(strConn) Dim cmd As New OracleCommand(strSQL, en) Dim param As OracleParameter param = cmd.Parameters.Add(": JOB", QracleType. VarChar, 9) param.Value = "CLERK" Dim numEmpNo As OracleNumber Dim strEName As OracleString cn.QpenO Dim rdr As OracleDataReader = cmd.ExecuteReade r() Do While rdr.Read() numEmpNo = rdr.GetOracleNumber(O) strEName = rdr.GetOracleString(l) Console.WriteLineC'EmpNo = " & numEmpNo.ToStringO) Console.WriteLlne("EName = " & strEName.ToStringO} Console. WriteLineO Loop rdr.Close() cn.CloseO Visual C#.NET string strConn, strSQL;

strConn = "Data Source=MyOracleDatabaseAlias;

" + "User ID=MyUserID;

Password=MyPasswor d;

";

StrSQL = "SELECT EMPNO, ENAME FROM EMP WHERE JOB = :JOB ";

OracleConnection en = new QracleConnection(str Conn);

OraclaCommand cmd = new OracleCommand(strSQL, en);

OracleParameter param;

Прочие поставщики данных.NET Приложение А param = cmd.Parameters.Add(":JOB", QracleType. VarChar, 9);

param,Value = "CLERK";

QracleNumber numEmpNo;

OracleString strEName;

cn.OpenO;

OracleDataReader rdr = cmd.ExecuteReaderC);

while (rdr.ReadO) ( numEmpNo = rdr.GetOracleNumber(O);

strEName = rdr.GetOracleString(l);

Console.WrlteLineC'EmpNo = " + numEmpNo. ToStringO);

Console.WriteLine("EName = " + strEName. ToStringO);

Console.WriteLine();

} rdr.CloseO;

cn,Close();

Вызов хранимой процедуры Задайте свойству CommandText объекта OracleCommand имя нужной хранимой процедуры и затем добавьте параметры в набор Parameters объекта Command.

Добавляя параметры в набор, поставьте перед их именами двоеточия. Затем вы зовите метод ExecuteNonQuery-, Visual Basic.NET Dim strConn As String strConn = "Data Source=MyOracleDatabaseAlias;

" & "User ID=MyUserID;

Password=MyPasswor d;

" Dim en As New OracleConnection(strConn) Dim cmd As New OracleCommand("GetNumOrders", с n) cmd.CommandType = CommandType.StoredProcedure Dim param As OracleParameter param = cmd.Parameters.AddC'pCustomerlD", Orac leType.Char, 5) param.Value = "ALFKI" param = cmd.Parameters.AddC'pNumOrders", Oracl eType.Int32) param,Direction = ParameterDirection. Output cn.OpenO cmd.ExecuteNonQuery() Console.WriteLine(pa ram.Value) cn.CloseO Visual C#.NET string strConn;

strConn = "Data Source=MyOracleDatabaseAlias;

" + "User ID=MyUserID;

Password=MyPasswor d;

";

OracleConnection en = new OracleConnection(str Conn);

OracleCommand cmd = new OracleCommandC'GetNumO rders", en);

cmd.CommandType = CommandType.StoredProcedure;

OracleParameter param;

578 Приложения param = cmd.Parameters.AddC'pCustomerlD", Orac leType.Char, 5);

param.Value = "ALFKI";

param = cmd.Parameters.Add("pNumOrders", Oracl eType.Int32);

param.Direction = ParameterDirection.Output;

cn.0pen();

cmd. ExecuteNonQueryO;

Console.WriteLine(param. Value);

en.Closet);

Чтобы избежать нагрузки по преобразованию поставщиком этого кода в со ответствующий синтаксис Oracle, не изменяйте значение свойства Command-Type по умолчанию, Text, и задайте свойству CommandText запрос в таком формате:

BEGIN GetNumOrders(;

pCustomerID, :pNumdrders);

END;

Выборка данных из курсоров REF Поставщик Oracle Client.NET Data Provider позволит выбирать посредством вы зова хранимой процедуры данные из нескольких курсоров REF. Скажем, у вас есть такое определение пакета Oracle:

CREATE PACKAGE PackCursorTest AS TYPE curOrders IS REF CURSOR RETURN OrdersKR OWTYPE;

TYPE curDetails IS REF CURSOR RETURN Order.D etailsXROWTYPE;

PROCEDURE OrdersAndDetailsForCustomer (pCustomerlD IN CHAR, pQrders OUT curOrder s, pDetails OUT curDetails);

END;

CREATE PACKAGE BODY PackCursorTest AS PROCEDURE OrdersAndDetailsForCustomer ( pCustomerlD IN CHAR, pOrders OUT curOrders, pDetails OUT curDetails ) AS BEGIN OPEN pOrders FOR SELECT * FROM Orders WHER E CustomerlD = pCustomerlD;

OPEN pDetails FOR SELECT * FROM Order.Deta Us WHERE OrderlD IN (SELECT OrderlD FROM Orders WHERE Custom erID = pCustomerlD);

END;

END;

Следующий фрагмент кода вызывает хранимую процедуру и помещает содер жимое обоих курсоров REF в один объект DataSet:

Visual Basic.NET Dim strConn, strSQL As String strConn = "Data Source=MyOracleDatabaseAlias;

" "User ID=HyUserID;

Password=MyPasswor d;

" Dim en As New OracleConnection(strConn) Прочие поставщики данных.NET Приложение А strSQL = "PackCursorTest.OrdersAndDetailsForCustomer" Dim cmd As New OracleCommand(strSQL, en) cmd-CommandType = CommandType.StoredProcedure Dim param As OracleParameter param = cmd,Parameters.Add("pCustomerID", Orac leType.Char, 5) param.Value = "ALFKI" param = cmd.Parameters.AddC'pOrders", OracleTy pe.Cursor) param.Direction = ParameterDirection.Output param = cmd.Parameters.Add("pDetails", Oracle! ype.Cursor) param,Direction = ParameterDirection.Output Dim da As New OracleDataAdapter(cmd) da.TableMappings.Add("Table", "Orders") da.TableMappings.Add("Table1", "Order_Details") Dim ds As New DataSetf) Dim tbl As DataTabLe da.Fill(ds) For Each tbl In ds,Tables Console.WriteLine(tbl.TableName & " now has " & tbl.Rows.Count & " row(s)") Next tbl Visual C#.NET string strConn, strSOL;

strConn = "Data Source=MyOracleDatabaseAlias;

" + "User ID=MyUserID;

Password=MyPasswor d ;

" ;

OracleConnection en = new OracleConnection(str Conn);

strSQL = "PackCursorTest.OrdersAndDetailsForCustomer";

OracleCommand cmd = new OracleCommand(strSQL, en);

cnid.ComniandType = CommandType.StoredProcedure;

OracleParameter param;

param = cmd.Parameters.Add("pCustomerIO", Orac leType.Char, 5):

param.Value = "ALFKI";

param = cmd.Parameters.AddC'pOrders", OracleTy pe.Cursor);

param.Direction = ParameterDirection.Output;

param = cmd.Parameters.AddC'pDetails", OracleT ype.Cursor);

pa ram.Direction = ParameterDirection.Output;

OracleDataAdapter da = new OracleDataAdapterfc md);

da.TableMappings.Add("Table", "Orders");

da.TableMappings.Add("Tablel", "Order_Details");

DataSet ds = new DataSetO;

da.Fill(ds);

foreach (DataTable tbl in ds.Tables) Console,WriteLine(tbl.TableName + " now has " + tbl.Rows.Count + " row(s)");

580 Приложения Получение информации схемы БД У поставщика Oracle Client.NET Data Provider нет собственных функций для по лучения информации схемы, например имен таблиц и столбцов, из БД Oracle.

Тем не менее вы сможете обращаться к словарю Oracle и получать нужные сведе ния. Так, следующие запросы возвращают из БД список таблиц и столбцов:

SELECT TABLE_NAME FROM USER.TABLES SELECT TABLE_NAHE, COLUMN_NAME FROM USER_TAB_COLUHNS ORDER BY TABLE_NAME Подробнее об использовании словаря данных Oracle — в документации на Oracle.

Проблемы, общие для поставщиков данных.NET Поставщики данных.NET обеспечивают повышенную производительность и пре доставляют расширенные возможности управления, поскольку каждый из них можно настроить под потребности конкретной СУБД, на работу с которой он рассчитан. Тем не менее переход к отдельным поставщикам данных.NET вызвал в среде разработчиков некоторое замешательство.

Создание кода, независимого от поставщика Предположим, вы создали приложение, использующее поставщик SQL Client.NET Data Provider. Время не стоит на месте, и в соответствии с потребностями клиен та вы решили модифицировать приложение так, чтобы оно могло работать и с БД SQL Server, и с БД Oracle. Чем больше кода в приложении основано на постав щике SQL Client.NET Data Provider, тем больше придется менять.

Однако, если разделить код на компоненты и организовать их взаимодействие при помощи универсальных интерфейсов типа DataSet, DataTable, IDataReader и DbDataAdapter, вам потребуется изменить лишь код конкретных компонентов.

Рассмотрим два примера, использующих такой метод. В первом примере мы создадим функцию, которая внутренне использует поставщик SQL Client.NET Data Provider, но возвращает данные посредством универсального интерфейса DataTable.

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

Следующий фрагмент кода вызывает функцию GetQrdersForCustomer, прини мающую строку со значением столбца CustomerlD и возвращающую объект Data Table с заказами указанного клиента. Внутренне функция использует параметри зованный объект SqlDataAdapter.

Visual Basic.NET Dim strCustomerlD As String = "ALFKI" Dim tblOrders As DataTable tblOrders = GetOrdersForCustomer(strCustomerID ) Прочие поставщики данных.NET Приложение А Private Function GetOrdersForCustomer(Customer ID As String) As DataTable Dim strSQL, strConn As String strSQL = "SELECT OrderlD, CustomerlD, EmployeelD, Order Date " & _ "FROM Orders WHERE CustomerlD = ©CustomerlD" strConn = "Data Source=(local)\NetSDK;

" & "Initial Catalog=Northwind;

Trusted_Connection= Yes;

" Dim da As New SqlDataAdapter(strSQL, strCo nn) Dim param As SqlParameter param = da.SelectCommand.Parameters.Add("@ CustomerlD", SqlDbType.NChar, 5} param,Value = CustomerlD Dim tbl As New DataTable("Orders") da.Fill(tbl) Return tbl End Function Visual C#.NET string strCustomerlD = "ALFKI";

DataTable tblOrders;

tblOrders = GetOrdersForCustomer(strCustoirerID );

private DataTable GetOrdersForCustomer(string CustomerlD) { string strSQL, strConn;

strSQL = "SELECT OrderlD, CustomerlD, EmployeelD, Order Date " + "FROM Orders WHERE CustomerlD = @CustomerID";

strConn = "Data Source=(local)\\NetSDK;

" + "Initial Catalog=Northwind;

Trusted_Connection= Yes;

";

SqlDataAdapter da = new SqlDataAdapter(str SQL, strConn);

SqlParameter pa'ram;

param = da.SelectCommand.Parameters.Add("@ CustomerlD", SqlDbType.NChar, 5);

param.Value = CustomerlD;

DataTable tbl = new DataTable("Orders");

da.Fill(tbl);

return tbl;

} Как уже говорилось, вам может потребоваться модифицировать приложение для взаимодействия с другими СУБД. Функция GetOrdersForCustomer внутренне работает с поставщиком SQL Client.NET Data Provider, но для параметра и воз вращаемого значения использует универсальные типы данных — string и DataTable.

Таким образом, функцию можно переписать для другого поставщика.NET, не из меняя код с объектом DataTable. Вот как я откорректировал код функции GetOrders ForCustomer, не трогая ее сигнатуру.

Visual Basic.NET Private Function GetOrdersForCustomer(Customer ID As String) As DataTable Dim strSQL, strConn As String strSQL = "SELECT OrderlD, CustomerlD, EmployeelD, Order Date " & _ "FROM Orders WHERE CustomerlD = :CustomerID" 582 Приложения strConn = "Data Source=MyOracleDatabaseAlias;

" 4 _ "User ID=MyUserID;

Password=MyPassword;

" Dim da As New OracleDataAdapter(strSQL, st rConn) Dim param As OracleParameter param = da.SelectCommand.Parameters.Add(": CustomerlD", OracleType.Char, 5) param.Value = CustomerlD Dim tbl As New DataTable("Orders") da.FillCtbl) Return tbl End Function Visual C#.NET private DataTable GetOrdersForCustomer(string CustomerlD) !

string strSQL, strConn;

strSQL = "SELECT OrderlD, CustomerlD, EmployeelD, Order Date " + "FROM Orders WHERE CustomerlD = :CustomerlD";

strConn = "Data Source=MyOracleDatabaseAHas;

" + "User ID=MyUserID;

Password=MyPassword;

";

OracleDataAdapter da = new OracleDataAdapt er{strSQL, strConn);

OracleParameter param;

param = da.SelectCommand.Parameters.Add(": CustomerlD", OracleType.Char, 5);

param.Value = CustomerlD;

DataTable tbl = new DataTableC"Orders");

da.FillCtbl);

return tbl;

I Еще один способ основан на том, что код доступа к данным возвращает объекты при помощи универсальных интерфейсов, поддерживаемых различными постав щиками.NET. Так, можно написать функцию, создающую экземпляр объекта SqlData Adapter и возвращающую его средствами универсального интерфейса IDbData Adapter.

Visual Basic.NET Dim daOrders As IDbDataAdapter = GetOrdersAdap ter() Dim strCustomerlD As String = "ALFKI" Dim param As IDbDataParameter param = CType(daOrders.SelectCommand. Parameter s{0), IDbDataParameter) param.Value = StrCustomerlD Dim ds As New DataSetQ Dim tblOrders As DataTable = ds.Tables.AddC'Or ders") daOrders,Fill(ds) Private Function GetOrdersAdapterO As IDbData Adapter Dim strSQL, strConn As String strSQL = "SELECT OrderlD, CustomerlD, EmployeelD, Order Date " & _ "FROM Orders WHERE CustomerlD = «CustomerlD" strConn = "Data Source=(local)\NetSDK;

" & Приложение А Прочие поставщики данных.NET "Initial Catalog=Northwind;

Trusted_Connection= Yes;

" Dim da As New SqlDataAdapter(strSQL, strCo nn) da.TableMappings.Add("Table", "Orders") da.SelectCommand.Parameters.Add{"@Customer ID", SqlDbType.NChar, 5) Return da End Function Visual C#.NET IDbDataAdapter daOrders = GetOrdersAdapterf);

string strCustomerlD = "ALFKI";

IDbDataPararneter param;

param = (IDbDataParameter) daOrders.SelectComm and.Parameters[0];

param.Value = strCustomerlD;

DataSet ds = new DataSetO;

DataTable tblOrders = ds.Tables.Add("0rders");

daOrders,Fill(ds);

private IDbDataAdapter GetOrdersAdapterQ I string strSQL, strConn;

strSQL = "SELECT OrderlD, CustomerlD, EmployeelD, Order Date " + "FROM Orders WHERE CustomerlD = @CustomerID";

strConn = "Data Source=(local)\\NetSDK;

" + "Initial Catalog=Northwind;

Trusted_Connection= Yes;

";

SqlDataAdapter da = new SqlDataAdapter(str SQL, strConn);

da.TableMappings.Add{"Table", "Orders");

da.SelectCommand.Parameters.Add("©Customer ID", SqlDbType.NChar, 5);

return da;

:

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

Visual Basic.NET Private Function GetOrdersAdapterC) As IDbData Adapter Dim strSQL, strConn As String strSQL = "SELECT OrderlD, CustomerlD, EmployeelD, Order Date " & "FROM Orders WHERE CustomerlD = :CustomerID" strConn = "Data Source=MyOracleDatabaseAlias;

" "User ID=MyUserID;

Password=MyPassword;

" Dim da As New QracleDataAdapter(strSQL, st rConn) da.TableMappings.Add("Table", "Orders") da.SelectCommand.Parameters.Add(":Customer ID", OracleType.Char, 5) Return da End Function 584 Приложения Visual C#.NET private IDbDataAdapter GetOrdersAdapter() { string strSQL, strConn;

strSQL = "SELECT OrderlD, CustomerlD, EmployeelD, Order Date " + "FROM Orders WHERE CustomerlD = :CustomerID";

strConn = "Data Source=HyOracleOatabaseAlias;

" + "User ID=MyUserID;

Password=HyPassword;

";

OracleDataAdapter da = new OracleDataAdapt er(strSQL, strConn);

da. TableMappings.Addf "Table", "Orders");

da. SelectCommand. Pa ramete rs. Add( " : Custome r ID", 0 racleType. Char, 5) ;

return da;

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

Вот один из вопросов по поставщику ODBC.NET Data Provider, наиболее час то задаваемых в открытых группах новостей, посвященных ADO.NET: «Как мне выбрать для параметров подходящий тип данных поставщика?» Обычно разработ чикам приходится его решать, когда они создают собственную логику обновле ния для объектов DataAdapter. Скажем, в объекте UpdateCommand вашего объекта DataAdapter используется такой запрос:

UPDATE Orders SET CustomerlD = ?, OrderDate = ?

WHERE OrderlD = ?

Какой тип данных поставщика лучше всего подходит для параметра QrderDate?

К счастью, правильный тип данных можно выбрать на основании типа данных, определенного для столбца таблицы. Однако все не столь просто. Если вы обра щаетесь к БД SQL Server Northwind при помощи поставщика ODBC.NET Data Provider, свойству OdbcType объекта QdbcParameter следует задать значение Qdbc TypeDateTime, Однако при использовании поставщика OLE DB.NET Data Provider свойству OleDbType объекта OleDbParameter нужно задать значение OleDbTypeDB TimeStamp. Как же бедному разработчику быть?

Самый лучший способ, который я могу предложить, — • воспользоваться мето дом GetScbemaTableDataReader. Если параметр соответствует столбцу БД. создай те запрос, возвращающий данные этого столбца. Затем примените объект Command и выполните запрос с помощью метода ExecuteReader. Вызовите метод GetScbema Table итогового объекта DataReader. Каждая запись объекта DataTable, возвращен ного методом DataReader.GetScbemaTable, соответствует столбцу оригинального запроса. Найдите в этом объекте DataTable запись, соответствующую вашему па раметру. Просмотрите содержимое поля ProviderType данной записи и преобра зуйте целое число в значение из соответствующего перечисления.

Прочие поставщики данных.NET Приложение А Следующий фрагмент кода определяет подходящее значение свойства Odbc Type для столбца OrderDate БД Northwind.

Visual Basic.NET Dim strConn, strSQL As String strConn = "Driver={SQL Server};

Server=(local)\NetSDK;

" & "Database=Northwlnd;

Trijsted_Connection=Yes;

" Dim en As New OdbcConnection(strConn) cn.OpenO strSQL = "SELECT OrderDate FROM Orders" Dim cmd As New OdbcCommand(strSQL, en) Dim rdr As OdbcDataReader rdr = cmd.ExecuteReader(CommandBehavior.Schema Only) Dim tbl As DataTable = rdr.GetSchemaTableO rdr.CloseQ cn.Close() Dim intOrderDateType As Integer intOrderDateType = CType(tbl.Rows(0)("Provider Type"), Integer) Dim odbcOrderDateType As OdbcType odbcOrderDateType = CType(intOrderDateType, Od bcType) Console.WriteLine("OrderDate") Console.WriteLineCvbTab & "ProviderType = " & intOrderDateType) Console,WriteLinefvbTab & "OdbcType = " & OdbcOrderDateType.ToStringO) Visual C#.NET string strConn, strSQL;

strConn = "Driver={SQL Server};

Server=(local)\\NetSDK;

" + "Database=Northwind;

Trusted_Connection=Yes;

";

OdbcConnection en = new OdbcConnection(strConn );

cn.OpenO;

strSQL = "SELECT OrderDate FROM Orders";

OdbcCommand cmd = new OdbcCommand(strSQL, en);

OdbcDataReader rdr = ctnd. ExecuteReader(Comroand Behavior.SchemaOnly);

DataTable tbl = rdr.GetSchemaTable();

rdr.Close();

cn.CloseO;

int intOrderDateType = (int) tbl.Rows[0]["Prov iderType"];

OdbcType odbcOrderDateType * (OdbcType) intOrd erDateType;

Console.WriteLine("OrderDate");

Console.WriteLine("\tProviderType = " + intOrderDateType);

Console. WriteLine( "\tOdbcType = " + odbcOrderDateType.ToStringO);

Если писать такой код вам не хочется, воспользуйтесь утилитой Ad Hoc Query Tool, записанной на прилагаемом к книге компакт-диске (подробнее об этой ути лите — в приложении Б). На рис. А-2 утилита Ad Hoc Query Tool отображает ин формацию схемы о результатах запроса, включая столбец с именем специфич ного для поставщика.NET типа данных. Как видно, столбцу OrderDate БД соот ветствует значение DateTime из перечисления OdbcType.

20 595В 586 Приложения Рис. А-2. Определение подходящего типа данных поставщика.NET с помощью утилиты Ad Hoc Query Tool ПРИЛОЖЕНИЕ Б Утилиты 3дссь рассматриваются записанные на прилагаемом к книге компакт-диске ути литы, разработанные мной, чтобы упростить программистам создание приложе ний для доступа к данным — ADO.NET Ad Hoc Query- Tool ADO.NET DataAdapter Builder и ADO.NET Navigation Control.

Каждая утилита представляет собой незавершенный проект. Я собираюсь пе риодически размещать в Интернете обновления, добавляющие новые функции и исправляющие обнаруженные ошибки. Они доступны на Web-узле, адрес которого указан в записанном на компакт-диске файле Readme.

Как гласит пословица, невозможно постоянно удовлетворять требования всех окружающих вас людей. Помня об этом, я поместил на компакт-диск и исходный код каждой утилиты. Ad Hoc Query Tool и DataAdapter Builder написаны па Microsoft Visual Basic.NET исходный код утилиты Navigation Control дан как на Visual Basic.NET так и на Visual С*.NET Заметьте: эти утилиты не обеспечиваются технической поддержкой и не пред назначены для распространения (подробнее — в Лицензионном соглашении Microsoft в конце книги). Используйте их на свой собственный страх и риск.

Утилита ADO.NET Ad Hoc Query Tool При создании приложений для доступа к данным мне нередко хочется проверить содержимое таблиц БД. Visual Studio.NET позволяет сделать это. но не предостав ляет способа для выполнения произвольных запросов к БД с использованием выбранного вами поставщика данных.NET В связи с этим я решил создать ути литу, предоставляющую нужную мне функциональность.

Утилита ADO.NET Ad Hoc Query Tool (рис. Б-1) позволяет выполнять произволь ные запросы к БД с использованием поставщика данных.NET по вашему выбору.

Кроме того, она позволяет редактировать результаты запросов и передавать эти Приложения изменения обратно в БД. С помощью ADO.NET Act Hoc Query Tool удастся также просмотреть информацию схемы о результатах запроса и сгенерировать код на ADO.NET, создающий объект DataTable для храпения результатов вашего запроса, -,||.... I I Рис. Б-1. Утилита ADO.NET Ad Hoc Query Tool Давайте вкратце рассмотрим эту утилиту.

Подключение к БД Для подключения к БД выберите в главном меню приложения команду Connect.

Откроется диалоговое окно (рис. Б-2), где можно указать строку подключения и НУЖНЫЙ поставщик данных.NET.

Connection String. jProvider=50LOLEDB.Data Souce=(local]\NetSDK;

l.NET Date Provider;

fgfebb Рис. Б-2. Создание строки подключения средствами Ad Hoc Query Tool Добавление поставщиков данных.NET По умолчанию в списке поставщиков данных утилиты Ad Hoc Query Tool указаны лишь два поставщика, поставляемых в составе Microsoft.NET Framework — OLE DB.NET Data Provider и SQL Client.NET Data Provider. Тем не менее утилита под держивает и другие поставщики данных.NET.

Для работы с поставщиком данных.NET, установленным на вашем компьюте ре и не входящим по умолчанию в состав Microsoft.NET Framework, выберите из Приложение Б Утилиты списка поставщиков в диалоговом окне Connection пункт

i* Arlrf.NET Data Pnwmter Re Name Resouice Nam* radeDienJ Delimiters Ptefi* Рис. Б-3. Добавление поставщика данных.NET в Ad Hoc Query Tool Объектная модель ADO.NET не предоставляет универсального способа, позво ляющего определить, какие именно символы-разделители применять в именах таблиц и столбцов для конкретного соединения, и поэтому в окне Add.NET Data Provider можно указать, какие именно символы-разделители должен использовать поставщик. Утилите Ad Hoc Query Tool понадобятся эти параметры при генера ции логики обновления.

Поставщики OLE DB.NET Data Provider и ODBC.NET Data Provider рассчитаны на взаимодействие с различными СУБД. Если вы используете их, то при подклю чении к БД Ad Hoc Query Tool самостоятельно определяет подходящие символы разделители.

Выполнение запросов После подключения к БД утилита Ad Hoc Query Tool выводит окно для ввода и выполнения запросов. Введите текст запроса и щелкните кнопку Execute. Утили та выполнит запрос и выведет его результаты в сетке на вкладке Results (рис. 15-4).

На вкладке DataTable Code можно также просмотреть код на ADO.NET, необ ходимый для создания результирующего объекта DataTable.

Просмотр информации схемы Информация схемы, возвращаемая запросом, отображается на вкладке Schema (рис. Б-5). Утилита Ad Hoc Query Tool генерирует эту информацию с помощью метода DataReader.GetschemaTable. Флажок Extended MetaData определяет, будет ли Ad Hoc Query Tool использовать при вызове метода CommandExecuteReader константу Keylnfo из перечисления CommandBehavior. Если флажок установлен, из БД запрашиваются имена таблиц и столбцов, используемых в запросе, а также ин формация о ключевых столбцах набора результатов запроса, Многие разработчики сталкивались с проблемами, пытаясь сгенерировать для своих запросов логику обновления с помощью объекта CommandBuilder и масте ра Data Adapter Configuration Wizard. Эти проблемы зачастую связаны с тем, что поставщики OLE DB и ODBC-драйверы не возвращают информацию схемы, не обходимую объекту и мастеру для генерации логики обновления, как-то: имена таблиц, столбцов и сведения о ключевых столбцах. Утилита Ad Hoc Query Tool Приложения позволяет легко и просто просмотреть информацию схемы, возвращаемую вмес те с результатами запроса.

Стоит подробно остановиться на одном из столбцов с информацией схемы.

Большинство имен столбцов на рис. Б-5 интуитивно понятны — ColumnName, ColumnSize, DataType и т.д. Однако странно, что наиболее ценному столбцу таб лицы схемы дано наименее понятное имя — Provider Type. Этот столбец содержит целочисленное значение, особенно полезное само по себе.

ctena \ DataTaWe I l «e lonp.in'Narit tcrfacWanio Phone UBloraeilO к ALFM HanaAndeit Alre* F Jteikiitn ' 030X107*.ANATR AniTiuiillo ErnpaiAns Truiillo [5] 555- ".". CANTON Jrto™ Hoietw Т Antonio Morano [5] 555-Э9Э i,, ( "AROLir Thomas Haidy • ChiBtma Beiojund ОЭ21- ""BIKK Elaua SEE Deht.it H«ia Moos 0621- ;

iLAUS BLCNP ilondc-: : 1 peie : FiedeiH^ue Citeau.BOLD БоЫо [lunidas pi Mart in Sommei (91) EE5 22 SOUfF Laurence Lebihan Bon ц» 81 24 45 : BDTTM Elizabeth Lincoln (604) 555- BSBEv E's B--!-jges Viclona Ashworth (171)555- CiCIL Ilad^f: IWiidas p Falicio Simpson (1)135- :E'IT: Cantig comaicial Fiancisco Chang [61 555- O«p-$uey China] Yang Wang CHOPS 0452- sxui Comaicio M.nano PedioAfonso (11)555-76^ " " CONSH Consohnalcd Holdi Elizabeth Blown (171) 555- DiKhenblut Dehk Sven Dttheb 0241-03812:

ЭЧдСС '•зимам DiinnnleEntiei Janme Labiune 40 67 88 Рис. Б-4. Выполнение запросов к БД средствами Ad Hoc Query Tool (Л AtKI.MIl nil M lokwiNsme Cdi-fnnlDrdrr ColuronBize NumericPreci NumencScale DataType Picn-ide'ipe 0*0bTjpe 1*UOHS Рис. Б-5. Просмотр информации схемы о наборе результатов Утилиты Приложение Б Числа 130 и 202 (рис. Б-5) вам особо ничего не скажут, но для поставщика данных.NET они имеют глубокий смысл. В следующем фрагменте кода задействован поставщик OLE DB.NET Data Provider. Выполнив код, вы увидите, что при исполь зования этого поставщика тип данных столбца CustomerlD — WCbar, а столбца CompanyName — VarWChar.

Visual Basic -NET Dim typCustomerlD, typCompanyName As OleDbType typCustomerlD = CType(130, OleDbType) typCompanyName = CType(202, OleDbType) Console.WriteLineC'CustomerlD is " & typCustomerlD.ToStringO) Console.WriteLinef"CompanyName is " & typCompanyName.ToStringO) Visual C#.NET OleObType typCustomerlD, typCompanyName;

typCustomerlD = (OleDbType} 130;

typCompanyName = (OleDbType} 202;

Console.WriteLineC'CustomerlD is " + typCustomerlD.ToStringO);

Console.WriteLine("CompanyName is " +• typCompanyName.ToStringO);

Полагаю, усвоив эту информацию, вы согласитесь, что данные столбца Provider Type очень полезны, Утилита Ad Hoc Query Tool получает информацию схемы, показанную па рис. Б-5, с помощью метода GetSchemaTable объекта DataReader. Вы, вероятно, заметили столбец OleDbType справа от столбца ProviderType;

он содержит соответствующие значения из перечисления OleDbType. Фактически столбец OleDbType не являет ся частью объекта DataTable, возвращаемого методом GetSchemaTable, Утилита Ad Hoc Query' Tool вставляет этот столбец в таблицу с информацией схемы, исполь зуя перечисление, соответствующее задействованному поставщику данных.NET Затем она на основе значений столбца ProviderType заполняет этот добавленный столбец значениями.

Внимание! На самом деле четко определенного набора требований к постав щикам данных.NET не существует. Отличный пример этому — постав щик SQL XML.NET Data Provider. Он реализует лишь часть объектов и конструкторов, предоставляемых поставщиками OLE DB.NET и SQL Client.NET.

К счастью, принципы работы поставщиков данных.NET, созданных специали стами Microsoft — OLE DB, SQL Client. ODBC и Oracle Client, практически одина ковы. Благодаря этому, я смог создать утилиты Ad Hoc Query Tool и DataAdapter Builder, одинаково хорошо работающие со всеми этими поставщиками.

Утилиты используют механизм Reflection и предполагают имена классов. Так, если при работе с утилитой Ad Hoc Query Tool применяется поставщик ODBC.NET Data Provider, утилита, чтобы обеспечить поддержку передачи обновлений в БД.

ищет среди предоставляемых поставщиком классов классы, имена которых окан чиваются на CommandBuilder. Утилита DataAdapter Builder точно так же ищет клас 592 Приложения сы, имена которых оканчиваются на DataAdapter. Кроме того, DataAdapter Builder проверяет наличие в объекте DataTable, возвращенном методом Data.Reader.Get SchemaTable, специфических столбцов, чтобы определить, как генерировать ло гику' обновления.

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

Передача обновлений В окне Query есть флажок Updateable. Если он помечен, при выполнении запроса утилита Ad Hoc Query Tool создаст объект CommandBuilder, чтобы сгенерировать для этого запроса логику обновления. После того как логика будет успешно сге нерирована, в нижней части окна появится кнопка Submit Changes (рис, Б-4).

Щелкните ее, и Ad Hoc Query Tool передаст с помощью объекта CommandBuilder изменения в БД, а также уведомит вас об исходе такой попытки обновления, Параметры приложения Утилита Ad Hoc Query Tool хранит свои параметры, в том числе и список постав щиков данных.NET, прошлых соединений и прошлых запросов, в объекте DataSet со строгим контролем типов. Если вам потребуется изменить эти параметры, вос пользуйтесь командой Settings основного меню утилиты. При завершении рабо ты утилита сохраняет свои параметры в XML-файл, находящийся в nanKe\Documents and Settings\zaffl_wortb3oe#mu8\Application Data\Microsoft ADO.NET\Ad Hoc Query Tool\, а при загрузке — считывает их из него.

Утилита ADO.NET DataAdapter Builder Объект CommandBuilder и мастер Data Adapter Configuration Wizard осуществля ют удивительную задачу — генерируют логику обновления объекта DataAdapter, однако возможности каждого из них ограниченны. Объект CommandBuilder — весьма полезное средство времени выполнения, но он не генерирует код. Мастер Data Adapter Configuration Wizard генерирует код, но только для поставщиков данных.NET из состава.NET Framework. Ни объект, ни мастер не создают логику обновления, если в запросе нет полей первичного ключа.

Для решения этих задач и предназначена моя утилита ADO.NET DataAdapter Builder. Вам необходимо сгенерировать логику обновления, но поставщик OLE DB или драйвер ODBC не возвращает имен таблиц, столбцов и сведений о ключевых столбцах? Или требуется сгенерировать логику для объекта DataAdapter, не вхо дящего в состав.NET Framework? Нет проблем.

Пользовательский интерфейс ADO.NET DataAdapter Builder аналогичен утилите Ad Hoc Query Tool. О работе диалогового окна Connect говорилось ранее. Вам нужно лишь ввести строку подключения и выбрать требуемый поставщик данных.NET.

Утилита DataAdapter Builder отобразит форму, позволяющую вводить и выполнять запросы. Как и Ad Hoc Query Tool, DataAdapter Builder выполняет запросы и выво дит их результаты, а также информацию схемы о наборе результатов.

Приложение Б Утилиты J«v Stmg ISELECT OrderlD CustomerlD, Employee». GrderDals FFCM Ordeii'-'HE^E CuttomelD • ЙМП» Рис. Б-б. Генерирование логики обновления средствами ADO.NET DataAdapter Builder Основное различие утилит в том, что DataAdapter Builder позволяет вам опре делить логику обновления для объекта DataAdapter и выводит код на ADO.NET для создания этого объекта.

Определение логики обновления Утилита DataAdapter Builder генерирует для объекта DataAdapter логику обновле ния, создавая на основе результатов вашего запроса параметризованные запросы INSERT, UPDATE и DELETE.

Чтобы управлять логикой, которую DataAdapter Builder генерирует для запро сов UPDATE и DELETE, достаточно пометить флажок Concurrency Check (рис. Б-б).

По умолчанию DataAdapter Builder использует в разделах WHERE этих запросов оригинальные значения всех столбцов. Можно указать, что должны использоваться только столбцы первичного ключа или столбцы первичного ключа и столбцы со значениями типа timestamp.

Если пометить флажок Custom и выполнить запрос, откроется диалоговое окно, показанное на рис. Б-7. В нем отображается информация о столбцах и таблицах из схемы запроса, а также используемые при подключении символы-разделители.

Для управления столбцами в разделах SET и WHERE логики обновления объекта DataAdapter используйте доступные в сетке флажки. Не забывайте, что при этом стоит создать запрос UPDATE или DELETE, обновляющий несколько записей БД.

Кроме того, в данном диалоговом окне можно указать имя обновляемой базовой таблицы.

Я разработал собственную функцию контроля параллелизма в расчете на три ситуации. Во-первых, она пригодится вам при работе с поставщиками OLE DB и Приложения драйверами ODBC, не возвращающими сведений о ключевых полях. К таким по ставщикам относятся Microsoft V i s u a l FoxPro OLE DB Provider и Oracle OLE DB Provider. Сведения о ключевых полях позволяют объекту CommandBuilder и мас теру Data Adapter Configuration Wizard гарантировать, что сгенерированный ими запрос UPDATE или DELETE обновит по крайней мере одну запись. Без этих све дений утилиты не смогут сгенерировать логику обновления. Если вы имеете дело с поставщиком OLE DB, не возвращающим информации о ключевых полях, для создания логики обновления для объекта DataAdapter примените нестандартную функцию контроля параллелизма, реализованную в утилите DataAdapter Builder.

Custom Updating Logic Рис. Б-7. Определение нестандартной логики обновления Кроме того, эта функция удобна, когда необходим нестандартный контроль параллелизма, отличный от основанного на всех столбцах, столбцах первичного ключа или столбцах первичного ключа и столбцах со значениями типа time-stamp, Так, иногда требуется использовать в разделе WHERE запросов UPDATE и INSERT к таблице Customers БД North wind лишь поднабор этих столбцов. Это вполне осуществимо при помощи нестандартного контроля параллелизма.

Нестандартный контроль параллелизма также удобен, когда запрос возвраща ет данные из нескольких таблиц. Например, следующий запрос возвращает ин формацию из таблицы Order Details, включая в результаты названия товарок из таблицы Products:

SELECT O.OrderlD, 0. ProctuctID, p. ProductName, 0. Quantity, O.UnitPrice FROM [Order Details] 0, Products P WHERE P.ProductID = Q.ProductlD AND O.Orde ПО = Как рассказывалось в главе 10, объект DataAdapter предназначен для передачи обновлений R отдельную таблицу. Функция нестандартного контроля параллелизма, реализованная в DataAdapter Builder, позволяет передавать обновления только в таблицу Order Details. В диалоговом окне Custom Updating Logic укажите, что об новления требуется передавать в таблицу Order Details и что из разделов SET и WHERE обновляющих запросов следует исключить столбец ProductName.

Приложение Б Утилиты Элемент управления ADO.NET Navigation Control Б главе 13 обсуждались этапы создания стандартного Windows-приложения для доступа к данным. Вы, возможно, заметили, что на создание кнопок для переме щения по содержимому объекта DataSet требуется больше времени, чем на созда ние объектов DataAdapter и объектов DataSet со строгим контролем типов, а так же на создание связанных элементов управления. Тем не менее код и кнопки, необходимые, чтобы добавить в ваш код возможность перемещения по содержи мому объекта DataSet, очень просты.

Для решения этой проблемы я создал элемент управления ADO.NET Navigation Control. Он включает кнопки, позволяющие перемешаться по содержимому DataSet, Кроме того, он позволяет добавлять и удалять записи в объекте DataSet, а также передавать в БД отложенные изменения. На рис. Б-8 показана простая форма, использующая элемент управления ADO.NET Navigation Control.

Я Fermi J»JjH» Rowl ol \ Cancel AddHew J_ Delete ! :

Discaid FHI Submit Рис. Б-8. Элемент управления ADO.NET Navigation Control на Windows-форме Добавление элемента управления ADO.NET Navigation Control на панель инструментов Visual Studio.NET Если при разработке решения в Visual Studio.NET добавить в это решение проект ADO.NET Navigation Control, одноименный элемент управления автоматически станет доступным на вкладке Windows Forms панели инструментов Visual Studio.NET.

Кроме того, добавить элемент управления ADO.NET Navigation Control на па нель инструментов Visual Studio.NET можно, щелкнув панель правой кнопкой и выбрав в контекстном меню команду Customize Toolbox. В открывшемся диалого вом окне перейдите на вкладку.NET Framework Components, щелкните кнопку Browse и затем выберите библиотеку Navigation Control. Щелкните OK, и элемент управления станет доступным на панели инструментов, Конфигурирование свойств ADO.NET Navigation Control, обеспечивающих взаимодействие с данными Добавив элемент управления Navigation Control на Windows-форму, вы увидите, что он предоставляет четыре свойства, обеспечивающих взаимодействие с дан ными: DataSource, DataMember, DataAdapter и DataTahle.

596 Приложения Свойства DataSource и DataMember конфигурируются точно так же, как и од поименные свойства объекта DataGrid. Элемент управления Navigation Control функционирует в целом аналогично элементам управления, связанным с данны ми, типа TextBox и DataGrid. На основе заданных вами значений свойств DataSource и DataMember элемент управления Navigation Control ссылается на соответству ющий объект CurrencyManager Windows-формы и внутренне использует этот объект для перемещения по базовой структуре данных.

Кроме того, элемент управления Navigation Control включает кнопки Fill и Update. Чтобы они заработали, задайте соответствующие значения свойствам DataAdapter и DataTable этого элемента управления.

Конфигурирование прочих свойств ADO.NET Navigation Control Элемент управления Navigation Control также предоставляет FillQnload. Confirm Deletes и ShowTips.

Значение свойства FillOnLoadno умолчанию — True. Данное свойство опреде ляет, будет ли элемент управления Navigation Control при открытии формы неяв но вызывать метод DataAdapter fill.

Значение свойства ConflrmDeletes по умолчанию — также True. Оно определя ет, выдается ли при щелчке по кнопке Delete запрос на подтверждение удаления записей или нет.

По умолчанию, если подвести мышь к какой-либо кнопке элемента управле ния Navigation Control, выводится всплывающая подсказка. Отключить вывод под сказок можно, задав свойству ShowTips элемента управления значение False.

Предметный указатель Data Form Wizard 21, 22, 27, 28, 32, 35, 38, 48, 59, action query см. запрос, командный Data Manipulation Language CM. DML Active Server Pages см. ASP DDL (Data Definition Language) ActiveX Data Objects aw. ADO disconnected object см. объект.

ADO (ActiveX Data Objects} 3, 5, отсоединенный 9-14, 18, 20, 47, 61, 86, 134-136, DML (Data Manipulation Language) 179, 257, - библиотека - интерфейс 7 extensible Stylesheet Language - ядро курсоров 3, И Transformations CM. XSLT ADO.NET 2-5, 7, 10, 16, 18, 20, 36, 71, 86, 91, 179, firehose cursor см. курсор, пожарный ASP (Active Server Pages) ASP.NET G globally unique identifier CM. GUID GUID (globally unique identifier) CLR (Common Language Runtime) 4, К COM (Component Object Model) 4, Kagera COM+ M Common Language Runtime CM. CLR Component Object Model CM. COM managed code см. код управляемый Component Services 446, 452 MDAC (Microsoft Data Access connected object см. объект, Components) подсоединенный metadata см. метаданные conscraint см. ограничение Microsoft Access 8, 22, 6l, 408, cookie 538 Microsoft Data Access Components CM. MDAC Microsoft Desktop Engine CM. MSDE DAO (Data Access Objects) 3, 9-14, Microsoft Visual InterDev 18, 134, 136, 179, 257, MSDE (Microsoft Desktop Engine) 41, Data Access Objects CM. DAO 413, Data Adapter Configuration Wizard 151, 155, 327, 377, 379, 382, 416, 452, 498 ODBC 8,46, 47, 55,61, Data Definition Language CM. DDL ODBCDirect 598 Предметный указатель Web-форм а OLE DB 8, 61, Windows Forms Oracle 3, 8, 47, 59, 61, 150, Windows-форма 62, P X Performance Monitor XDR (XML Data Reduced) Q XML 3, 7, 16,68, 176, QBU (query-based updates) XML Data Reduced CM. XDR см. обновление под управлением XML Schema Definition CM. XSD запросов XML Schema Definition Tool 324, 325, Query Builder 102, 153, 155, 334. 335, 336, R XPath 454, RAD (rapid application development) XSD (XML Schema Definition) 136 XSLT (extensible Stylesheet Language RDO (Remote Data Objects) 3, 134, Transformations) 16, 454, RegSvcs.exe Relations Collection Editor 281 автоинкремент 192, Remote Data Objects CM. RDO Б s блокировка sequence см. последовательность быстрая разработка приложений см.

Server Explorer 58, 59, 105, 155 RAD Sn.exe Г SQL DMO глобально уникальный SQL Profiler 41, идентификатор см. GUID SQL Server 3, 7, 8, 22, 41, 58;

59, 61.

д SQL Server Query Analyzer 41, 84 двухфазная фиксация strong name см. строгое имя диспетчер ресурсов 445, Ж transaction см. транзакция журнал событий two-phase commit cm, двухфазная фиксация запрос V - DDL Visual Basic 3, 62 - DML Visual Basic.NET 22, 55, 77 - командный, 82, Visual Basic 6 3, 36 - обработка Visual Studio.NET 2, 19, 21, 36, 48, 58. - отдельный 100, 102, 151, 211. 279, 306, - пакетный Visual Studio 6 3, 48, - параметризованный 10, Visual Studio 97 - просмотр результатов w - соединяющий 256, — шаблонный 473, Web Forms Web-сервис 35, 62, 426, Предметный указатель - Nothing И - null интерфейс - Stream 456, 458 - SCOPE_IDENTITY - SET NOCOUNT ON - TextReader - WithEvents - TextWriter код управляемый - XmlReader конструктор - XmlWriter - ConnectionString — доступа к данным - DataAdapter - пользователя - DataRelation - программирования - Windows Forms Designer К курсор ЕСТ асе - пожарный 85, - Command 6 - серверный - Connection м - CurrencyManager метаданные 2, 11, 12, - CustomersDataTabte - DataAdapter 134, 140 VIC ГОД - AcceptChanges 224, 225, 232, 233, - DataColumn 244, 245, 355, - DataColumnMappings - Add 119, 190, 200. - DataProvider - AddNew 305, 310, - DataRow 14, - AddRange - DataRowCollection - AppendChunk - DataSet 16, 36, 324, 328, - BeginEdit 202, 209, 244, 245, 305, - DataTable 12, 316, 332, - Decimal - Beginlnit 224. 226, 232, 233, 310.

- HttpSessionState - OdbcConnection - BeginLoadDaca 232, - OleDbConnection 45, 53, 67, 68, - BeginTransaction 10, 55, - OrdersDataTable 329 - Call - Page 541 - Cancel - Parameter 6, - CancelEdit 15, 209, 244, 245, 305, - SqlConnection 68 316, - String 293 - ChangeDatabase 70, - Transaction 6 - Clear 206, 224, 226, 232, - XmlDataDocument 464 - ClearErrors 244, - компонентов 62 - Clone 187, 224, 226, 232, ключ - Close 50, 52-54, 70,72, 75;

112, - внешний 190 115, - первичный 146, 166, 188, 189, - Collect 218, 231,434 - Commit 70, - уникальный 190 - Compute 232, 234, ключевое слово - Conneccion.Open - New 81, 177 — ContextUtil - NOCOUNT 600 Предметный указатель - GetEnumerator 301, 311, - Сору 187, 225, 226, 232, - GetErrors 233, - СоруТо 310, - GetFieldType - CreateChildView - GetFillParameters 163, - CreateCommand 54, 55, 70, 72, - GetlnsertCommand 390, 396, - CreateParameter 110, 120, - DataAdapter.Fill 10, 12, 146, 148, - Getlnt32 150 - GetName 115, - DataBind 536 - GetOleDbSchemaTable 56, 57, 58, - Delete 205, 244, 247, 305, 310, 316: 70, 72, 317 - GetOrdinal 87, 115, - DeriveParameters 396 - GetParentRow 244, 248, 263, 265, - Dispose 53—55 - EditDetail 506 - GetParentRows 244, 248, 264, - GetSchemaTable 112, 115, - EndCurrentEdit - GetString 88, - EndEdit 15, 202, 209, 244, 245, 305, 316, 332,499 - GetUpdateCommaiid 390, 396, - Endlnit 225, 226. 233, ЗЮ, 311 - GetValue 115, - EndLoadData 233 - GetValues 115, - Eval 533 - GecXml 225, 227, - ExecuteNonQuery 9, 83, 85, 110, - GetXmlSchema 225, 111, 355,419,420,481 - HasChanges 225, - ExecuteReader 9, 85, 92, 95, 110. - HasVersion 245, I l l, 112, - ImportRow 233, - ExecuteScalar 93,94,110, - InferXmlSchema 225, 227, 458, - ExecuteXmlReader 9, - IsDBNull - F i l l 5,31,32,135,141-145,163, - IsNull 205, 245, 177, 178. 186, 472, 515, - Item 181, - FillSchema 151, 163, 166, 167, 185, - Load 464, 186, 337, - LoadDataRow 201, 233, - Find 184, 289, 290, 291, 303, ЗЩ - Merge 16, 36, 225, 227, 342, 428, 312, 431, 433, - FindRows 304, 311, - MoveFirst - Get - MoveLast - СеКТипДанных> 115, - MoveNext 179, - GetBytes 115, - MovePrevious - GetChanges 16, 35, 225, 226, 233, - Navigate 235, 342, 423, - NewRow 201, 233, - GetChars 115, - NextRecordset 90, - GetChildRows 244, 247, 263, 265, - NextResult 89,92, 115, - GetChunk 519 - Open 5, 50, 53, 67, 68, 70, 74, 145, - GetColumnError 244, - Prepare 110, - GetColumnsInError 244, - Read 86, 89, - GetData 114, 115, - ReadXml 225, 227, 335, 456, 458, - GetDatalypeName 115, 459, - GetDeleteCommand 390, 396, Предметный указатель ConflictAdapter - ReadXmlSchema 225, 227, 337, 458,459 Connection 6, 9, 10, 40, 41, 50-52, - Refresh 127, 512 54, 55. 62, 63, 68. 78: 81, 140, 144, 145, - RefreshSchema 396, 39" Constraint 14, - RejectChanges 225, 233. ConstraintCollection - ReleaseConnectionPool CurrencyManagcr 494, 497, 499, - ReleaseObjectPool 70, 506, - Remove Customers - RemoveAt 206, 49/ DataAdapter 5, 9, 10, 11, 32, 34-36.

- Replace 106, 107, 134-139, 141, 143, 144, - Reset 225, 227, 233, 146, 148, 149, 151, 155, 157, 158.

- ResetCo'mmandTimeout 110, 159, 161, 179, 211, 362, 408, 490.

- ResumeBinding 512 502, - Rollback 70, 100 Database - Select 233, 236, 289, 292, 295, 297, DataColumn 12, 13, 14, 142, 177, 300, 343,421,424 178, 184, 188, - SetAbort 449, 450 DataColumnMappingCollection - SetColumnError 245, 247 DataColumnMappingsCollection - SetCompiete 450 - SetParentRow 248 DataConnection - SuspendBinding 512 DataGridTableStylc - ToString 510 DataReader 9, 20. 81, 85-89, 9 1.

92,95, 1 1 2, 133, 179, 181, - Update 5, 6, 11, 34, 135, 159, 162, 163, 167, 363, 368, 442, 479, 498, DataRelation 16, 17, 32, 177, 184, 504 255, 259, 260, 262, 266, 269, 279, 281, - UpdateBatch 5, DataRow 12, 14-16, 177, 180, 181, - WhteXml 225, 227, 286, 335, 342, 200, 263, 456, 462, 464, DataRowCollection 184, - \VriteXmlSchema 212, 225, 227, 324,458 DataRowView 194, 300, 305, 5u DataSet 2, 5,6, 11, 15, 16, 18-20, 0 24, 31, 32, 33-36, 107, 133-135, обновление под управлением 137, 143, 145, 146, 148, 174, 182, запросов 82 183, 197, 211, 279, 324, 329, 337, общеязыковая среда выполнения 455,461,490, 499, 519, см. CLR DataTable 11-15, 20, 27;

32, 57, объект 74, 134, 135, 137, 142, 143, 146: 150, 177, 178, 179, 181, 186, 187, 201, - Application 542, 262, 289, 300, 331,461, - Binding DataTableMapping - Cache DataTableMappingCollection 146, - Command 8,9, 10, 11, 35,41, 54, 147, 72, 81,83, 86,92,95, 100, 105, DataTableMappings 133-135, 137, 139, 155, 157, 159, 352 DataTableMappingsCollection - CommandBuilder 346, 374, 375, DataTablesColiection 416,452 DataView 17, 194, 297;

299, 602 Предметный указатель - со строгим контролем типов 19, - Field - ForeignKeyConstraint 184, - считывающий - HttpCookie ограничение 183, - lEnumerator - ForeignKeyConstraint 184, 197, - InsertCommand 219, 220, 266, 268, 269, 272, - OdbcDataAdapter - PrimaryKey 184, - OleDbCommand 55, 97, 101, 105, - UniqueConstraint 184, 106, 110. 159, - UniqueKey 190, 266, - OleDbCommandBuilder - создание - OleDbConnection 6, 40, 44, 46, 50, 53, 55, 56, 58, 63-68, 70, 74, 75, 77, очередь сообщений 101,471, п - OleDbDataAdapter 31, 32, 37, 159, панель компонентов 36, 165, 327, 472,479,490, параллелизм - OleDbDataReader 114, 115, параметр вывода - OleDbParameter 109, 120, 122, перечисление - Orders - DataRowVersion - Parameter 10,81,95, 119, - DataViewRowState 297, - ParameterCollection последовательность - QueryDef 9. 10, поставщик данных 6, 8, - Recordset 3, 5, 11, 12, 14, 18, 20, - Microsoft Jet 4.0 OLE DB 90, 91, 135, 136, 1.62, 179, 258, Provider 47, - Request - Microsoft OLE DB Provider For - Response ODBC Drivers - Session - Microsoft OLE DB Provider for - SqlCommand 8, 9, 97, 105, 159, Oracle 47, 67, - SqIConnection 6, 53, 55, 63, - Microsoft OLE DB Provider for SQL - SqlDataAdapter 159, Server - SqlXmlAdapter 471,472,479 - OLE DB.NET Data Provider 6, 8, - SqlXmlCommand 471,472,477, 46, 478.479, 481, - SQL Client.NET Data Provider 6, 7, - SqlXmlParameter 471, 476 8, - Stream 324 - SQL Server OLE DB Provider - StreamReacler 85 - SQL XML.NET Data Provider 8, - TextReader 85 470, 472, 473, - TextWriter 324 - пространство имен - Transaction 10, 41, 54, 55, 70, 100 проверка подлинности - UniqueConstraint 190 пространство имен - ViewState 545 - Microsoft.Data.SqlXml - XmlDataDocument 464 - System - XmlDocument 463, 469 - System.Collections - XmlReader 85, 468 - System.Data 6, 40, 69, 148, 150, - XmlWriter 324 161, 166, 177, - отсоединенный 4, 5, 6, 11. 12 - System.Data.OleDb 6, - подсоединенный 4, 5, 8 - System.Data.SqlClient 6, Предметный указатель - System.EnterpriseServices 448 ContinueUpdateOnError 158, 162, 223, пул соединений 50, Count 301, 307, С Current 313, сбор мусори 53 DataAdapter сборка 5 Database 67, свойство DataMember 503, 504, - AcceptChangesDuringFill 158, 162 DataSet 187, 228;

230, - AcceptRejectRule 251, 279 DataSetName 177, 221, 222, - AllowCustomPaging 547 DataSourcc 67, 68, 503, 509, - AllowDBNull 13, 183, 189, 237, 238 DataTable - ADowDeletc 307 DataType 120, 178, 188, 237, - AllowEtlit 307 DataView 315, - AllowNew 307 DataViewManager 307, - AllowPaging 546, 547 DbType 120, 122, - ApplyDefaultSort 307, 308 Default - Autolncrement 13, 192, 193, 237, DefauttValue 210, 237, 238, DefaultView 228, - AutoIncrementSeed 192, 193, 197, DeleteCommand 11, 35, 138, 158, 237, 238,423,490, 159, 363, 378, 381, 388, 407, - AutolncrementStep 192, 193, 197, DeleteRule 251, 277, 237, 238, 423, 490, Depth 114, - Cache DesignMode 221, 222, 228, - Caption 237, Direction 10, 98, 120, - CaseSensitive 221, 228, Display-Member - ChildColumns 281, Driver - ChildKeyConstraint EnforceConstraints 221, 222. 291, - ChildRelations 228, - ChildTable Expires - ColumnMapping 23", Expression 13, 197, 237, 240. 274, - ColumnMappings 11, 138, 159, 461 - ColumnName 215, 237, 239 ExtendedProperties 221, 222, 228, - Columns 12. 178, 228, 229, 250, 230, 237, 241, 250;

251, 252, 251, 252 HieldCount 114, - CommandText 9, 83, 97, 105, 107. Fields 155, 377, 378, 387, 406,411,415, Filter 471,476, GetName - CommandTimeout HasErrors 221, 223, 228, 230, 243, - CommandTVpe 9, 96;

97, 105, 107, 109, 150, 474, InsertCommand 11, 35, 138, 158, - Connection 9, 54, 72, 83, 101, 105, 159, 363, 374, 380, 381, 388, 407, 416,418, - ConnectionString 6, 63, 64, 67, IsClosed - ConnectionTimeout IsEdit - ConstraintName 250, 251, IsNew - Constraints 12, 228, 604 Предметный указатель - Rows 12, 200, 229, - IsNullable - RowState 162, 201, 207, 243, 244, - IsPrimaryKey 250, 300, - Item 14, 15, 86, 88, 114, 181, 200, - RowStateFifter 300, 307, 202, 243, 307, 308, - RowUpdate - ItemArray 203, - Row-Version 315, - Locale 221, 223, 228, - Scale 120, 122, - MaxLength 183, 189, 197, 215, 237, 241 - SchemaPath 477, - MinimumCapacity 231 - SelectCommand 11, 32, 137, 139, - MissingMappingAction 148, 158, H I, 144, 155, 158, 159, 163, 167, 161, 163 362, 375, 380, 381, - MissingSchemaAction 150, 151, - SelectedValue 158, 161, 163, 185 - ServerVersion 67, - MissingSchemAction 161 - Session - Name 178, 491 - Size 120, 122, 125, 167, - Namespace 221, 224, 228, 231, 237, - Sort 17, 303, 307, 242, 461 - SourceColumn 120, 122, - Nested 282,461 - SourceVersion 120, 122, - OleDbType 120, 122, 125 - SqlDbType - Ordinal 178, 237, 242 - State 67, 69, - PagerS tyle 546 - Table 181, 238, 242, 243, 244, 250, - ParameterName 120 251, 252, 299, 307, ЗЮ, - Parameters 107, 109 - TableMappings 11, 138, 146, 158, - ParentColumns 282, 284 - ParentKeyConstraint 282, 284 - TableName 186, 229, - ParentRelations 228, 229 - Tables 221, - ParentTable 282, 284 - Text - Position 494 - Transaction 99, 107, 109, - Precision 120, 122, 167, 397 - Type - Prefix 221, 224, 228, 231, 237, 461 - Unique 13, 183, 184, 189, 238, - Primary-Key 146, 189, 218, 229, 231. - UpdateCommand 11, 35, 138, 158, 515 159, 363, 380, 381, 388, 405, 407, 419, - Provider 67, - UpdatedDataSource - QuotePrefix - UpdatedRowSource 107, 109, - QuoteSuffix - UpdateRule 251, 277, - Readonly 13, 183, 189, 238, 242.

500 - Value, 120 121, - RecordsAffected 91, 92, 114, 115 - ValueMember - RelatedColumns 251, 252 - ViewState 539, - RelatedTable 251, 252 - VirtualltemCount - RelationName 282, 284 - XslPath 478, - Relations 16, 221, 224 строгий контроль типов - Row 315 строгое имя - RowError 243, 244 строка подключения 46, 48, 49, — RowFilter 307, 309 счетчик производительности Предметный указатель Т Я транзакция 10, 55, 99, 388, 444 ядро - координатор 445,446 - доступа к данным - распределенная 44б - курсором 3, 349, Y язык - определения данных си. DDL хранилище данных 6, 7. - управления данными си. DML Об авторе ^7то вторая книга Дэвида Сеппы (David Sceppa) для Microsoft Press. В 2000 г. он написал «Programming ADO".

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

В команде разработчиков Visual Basic.NET Дэвид занимается тестированием функций доступа к данным.

Он обладает званием сертифицированного разработ чика Microsoft, выступает на конференциях по техни ческим вопросам, а также активно участвует в обсуж дениях, разворачивающихся в обще доступ ной группе новостей microsoft public.dotnc-tframework.adonet, посвя щенной ADO.NET.

Выступив на недавней конференции по SQL Server в Сиднее (Австралия), Дэвид наконец-то смог посмот реть пару матчей по австралийскому футболу на престижном стадионе Melbourne Cricket Grounds.

Незадолго до того, как Марио Лемье и Майкл Джордан вернулись в спорт, про изошло еще одно событие, не получившее столь широкого резонанса, но от это го не менее важное. После долгого перерыва в колыбель мини-футбола (Редмонд.

Pages:     | 1 |   ...   | 8 | 9 || 11 |



© 2011 www.dissers.ru - «Бесплатная электронная библиотека»

Материалы этого сайта размещены для ознакомления, все права принадлежат их авторам.
Если Вы не согласны с тем, что Ваш материал размещён на этом сайте, пожалуйста, напишите нам, мы в течении 1-2 рабочих дней удалим его.