Россия |
Основы ADO.NET
Фабрики поставщиков
Классы поставщиков оптимизированы под конкретный тип источника данных. Производители, разрабатывающие новую структуру источника данных, должны заботиться и о разработке соответствующего типа поставщика, чтобы этим источником данных могли пользоваться программисты (мы с вами) в своих приложениях. Но традиционный переход на новый тип поставщика требует существенной переделки кода приложения, что не всегда удобно для программистов. Поэтому в ASP.NET 2.0 предусмотрены специальные классы, которые позволяют "подкрутить" настройки только в одном месте, общедоступном для всех страниц приложения или группы страниц без необходимости изменения кода в каждой странице, использующей поставщик. Такой механизм называется фабриками поставщиков.
Основная идея модели фабрик заключается в том, что можно использовать единственный объект-фабрику для создания всех прочих необходимых для конкретного поставщика объектов. Но это можно выполнить и созданием конкретных объектов поставщика. Самое главное удобство заключается в том, что конкретную фабрику поставщика можно создавать из обобщенного класса фабрик System.Data.Common.DbProviderFactories программным способом, используя информацию, заложенную в файлы web.config (в масштабах конкретного приложения) или machine.config (в масштабах конкретного компьютера-сервера)
<?xml version="1.0"?> <configuration> <connectionStrings> <add name="Northwind" connectionString="Data Source=localhost; Initial Catalog=Northwind; user id=sa; password=;"/> </connectionStrings> <system.data> <DbProviderFactories> <add name="SqlClient Data Provider" invariant="System.Data.SqlClient" type="System.Data.SqlClient.SqlClientFactory" /> <add name="Odbc Data Provider" invariant="System.Data.Odbc" type="System.Data.Odbc.OdbcFactory" /> <add name="OleDb Data Provider" invariant="System.Data.OleDb" type="System.Data.OleDb.OleDbFactory" /> <add name="OracleClient Data Provider" invariant="System.Data.OracleClient" type="System.Data.OracleClient.OracleClientFactory" /> </DbProviderFactories> </system.data> <system.web> <compilation debug="true"/> </system.web> </configuration>
Этот шаг регистрации идентифицирует коллекцию фабрик с идентификатором name, значение которого удобно принять подобным имени поставщика. Конкретную фабрику можно прочитать из кода по ее идентификатору.
Обобщенный класс System.Data.Common.DbProviderFactories имеет статический метод GetFactory(string), который возвращает объект конкретной фабрики, указанной в строке аргумента. Например, для случая явного указания в коде конкретной фабрики это будет выглядеть так
string factory = "System.Data.SqlClient"; System.Data.Common.DbProviderFactory provider = System.Data.Common.DbProviderFactories.GetFactory(factory);
Получив конкретную фабрику из строки аргумента или конфигурационного файла далее с конкретным поставщиком можно работать через объект provider одноименной фабрики, устанавливая соединение с БД и посылая в нее SQL-запросы. Для создания объектов Connection и Command используются методы объекта (например, provider ) фабрики CreateXXX(), которые возвращают эти объекты
Для создания независимого от поставщика универсального кода мы должны исходить из того, что не знаем заранее тип поставщика. Поэтому взаимодействовать с источником данных нужно только через методы объекта фабрики, возвращающие специфичные объекты Connection, Command, Parameter, DataAdapter базовых классов DbConnection, DbCommand, DbParameter, DbDataAdapter.
Пример независимого от поставщика кода с использованием фабрик
Чтобы лучше понять, как все вышесказанное работает, рассмотрим пример SQL-запроса, реализованного на странице TestDataReader.aspx. Первый шаг - настроить в файле web.config строку соединения, имя поставщика и текст SQL-запроса.
-
Откорректируйте файл web.config, чтобы он окончательно выглядел следующим образом
<?xml version="1.0"?> <configuration> <connectionStrings> <add name="Northwind" connectionString="Data Source=localhost; Initial Catalog=Northwind; user id=sa; password=;"/> </connectionStrings> <appSettings> <add key="factory" value="System.Data.SqlClient" /> <add key="employeeQuery" value="SELECT * FROM Employees" /> </appSettings> <system.web> <compilation debug="true"/> </system.web> </configuration>
-
Создайте из копии TestDataReader.aspx новую страницу с именем TestFactory.aspx, назначьте ее стартовой и заполните следующим кодом
<%@ Page Language="C#" %> <script runat="server"> protected void Page_Load(object sender, EventArgs e) { // Получить по ключу фабрику из файла web.config string factory = System.Web.Configuration. WebConfigurationManager.AppSettings["factory"]; System.Data.Common.DbProviderFactory provider = System.Data.Common.DbProviderFactories.GetFactory(factory); // Использовать фабрику для получения объекта соединения // и извлечь строку соединения из файла web.config System.Data.Common.DbConnection con = provider.CreateConnection(); con.ConnectionString = System.Web.Configuration. WebConfigurationManager.ConnectionStrings["Northwind"].ConnectionString; // Создать базовый объект DbCommand. Для его настройки // и извлечь по ключу команду из файла web.config System.Data.Common.DbCommand cmd = provider.CreateCommand(); cmd.Connection = con; cmd.CommandType = System.Data.CommandType.Text; cmd.CommandText = System.Web.Configuration. WebConfigurationManager.AppSettings["employeeQuery"]; // Создаем ссылку на вспомогательную строку System.Text.StringBuilder htmlStr = new StringBuilder(""); using (con) { // Открыли соединение con.Open(); // Выполняем обобщенную команду и получаем результирующий набор данных System.Data.Common.DbDataReader reader = cmd.ExecuteReader(); // Перебираем все записи результирующего набора // и строим HTML-строку while (reader.Read()) { htmlStr.Append("<li>Служащий "); htmlStr.Append(reader["TitleOfCourtesy"]); htmlStr.Append(" <b>"); htmlStr.Append(reader.GetString(1)); htmlStr.Append("</b>, "); htmlStr.Append(reader.GetString(2)); htmlStr.Append(" - работает с "); htmlStr.Append(reader.GetDateTime(6).ToString("d")); htmlStr.Append("</li>"); } // Закрываем набор данных reader.Close(); } // Выдаем результаты запроса lblInfo.Text = htmlStr.ToString(); } </script> <html xmlns="http://www.w3.org/1999/xhtml" > <head runat="server"> <title>Untitled Page</title> </head> <body> <form id="form1" runat="server"> <div> <asp:Label ID="lblInfo" runat="server" Text="Label"></asp:Label></div> </form> </body> </html>
-
Выполните страницу TestFactory.aspx. Должен получиться такой же результат, что и на странице TestDataReader.aspx, а именно
- Служащий Ms. Davolio, Nancy - работает с 01.05.1992
- Служащий Dr. Fuller, Andrew - работает с 14.08.1992
- Служащий Ms. Leverling, Janet - работает с 01.04.1992
- Служащий Mrs. Peacock, Margaret - работает с 03.05.1993
- Служащий Mr. Buchanan, Steven - работает с 17.10.1993
- Служащий Mr. Suyama, Michael - работает с 17.10.1993
- Служащий Mr. King, Robert - работает с 02.01.1994
- Служащий Ms. Callahan, Laura - работает с 05.03.1994
- Служащий Ms. Dodsworth, Anne - работает с 15.11.1994
- Служащий Зиборов, Алексей - работает с 07.05.2007
Чтобы убедиться, что код получился действительно универсальным и настройка на конкретного поставщика осуществляется только в файле web.config, поменяем поставщика в этом файле без изменения кода самой страницы.
-
Откорректируйте файл web.config, чтобы он окончательно выглядел следующим образом
<?xml version="1.0"?> <configuration> <connectionStrings> <add name="Northwind" connectionString="Provider=SQLOLEDB; Data Source=localhost; Initial Catalog=Northwind; user id=sa; password=;"/> </connectionStrings> <appSettings> <add key="factory" value="System.Data.OleDb" /> <add key="employeeQuery" value="SELECT * FROM Employees" /> </appSettings> <system.web> <compilation debug="true"/> </system.web> </configuration>
-
Исполните страницу TestFactory.aspx для нового поставщика, указанного в файле web.config, и убедитесь, что прежний код страницы генерирует тот же самый результат, но уже с новым поставщиком
Механизм применения фабрик поставщиков не решает всех проблем, связанных с разработкой независимого от поставщика кода. Например, не существует обобщенных объектов исключений базы данных, а только специфичные для конкретных поставщиков. Поставщики могут различаться некоторыми специфическими параметрами или поддерживать специальные средства, недоступные для общих базовых классов. Тем не менее, продемонстрированных возможностей в большинстве практических случаев может быть достаточно для написания независимого кода страниц.