ЯЗЫК ПРОГРАММИРОВАНИЯ С# 2005 И ПЛАТФОРМА .NET 2.0. 3-е издание - Эндрю Троелсен
Шрифт:
Интервал:
Закладка:
public static void OpenConnection(IDbConnection cn) {
// Открытие входного соединения для вызывающей стороны.
cn.Open();
}
То же можно сказать и о возвращаемых значениях. Рассмотрите, например, следующую простую программу на C#, которая позволяет вызывающей стороне получить конкретный объект соединения, используя значение пользовательского перечня (здесь предполагается, что вы указали оператор using для System.Data).
namespace ConnectionApp {
enum DataProvider { SqlServer, OleDb, Odbc, Oracle }
class Program {
static void Main(string[] args) {
// Получение соединения.
IDbConnection myCn = GetConnection(DataProvider.SqlServer);
// Требуется соединение с базой данных SQL Server Pubs.
myCn.ConnectionString = "Data Source=localhost;uid=sa;pwd=;Initial Catalog=Pubs";
// Открытие соединения с помощью вспомогательной функции.
OpenConnection(myCn);
// Использование соединения и его последующее закрытие.
…
myCn.Close();
}
static IDbConnection GetConnection(DataProvider dp) {
IDbConnection conn = null;
switch (dp) {
case DataProvider.SqlServer:
conn = new SqlConnection();
break;
case DataProvider.OleDb:
conn = new OleDbConnection();
break;
case DataProvider.Odbc:
conn = new OdbcConnection();
break;
case DataProvider.Oracle:
conn = new OracleConnection();
break;
}
return conn;
}
}
}
Преимущество использования общих интерфейсов System.Data заключается в том, что в этом случае у вас больше шансов создать более гибкий программный код, который дольше сможет оставаться актуальным. Например, если сегодня вы построите приложение, использующее Microsoft SQL Server, то что вы сможете сделать, если через год-другой руководство вашей компании примет решение перейти на использование Oracle? Если в приложении "жестко" запрограммированы имена типов System.Data.SqlClient, то вам, очевидно, придется сначала их отредактировать, а затем перекомпилировать и повторно инсталлировать компоновочный блок.
Файлы конфигурации и гибкость приложений
Для повышения гибкости своих приложений ADO.NET вы можете на стороне клиента использовать файл *.config, в котором в рамках элемента ‹appSettings› можно указать пользовательские пары ключей и значений. Вспомните из главы 11, что пользовательские даяние можно прочитать программно с помощью типов из пространства имен System.Configuration. Предположим, что в файле конфигурации вы указали строки соединения и поставщика данных так, как показано ниже.
‹configuration›
‹appSettings›
‹add key="provider" value="SqlServer" /›
‹add key="cnStr" value="Data Source=localhost;uid=sa;pwd=;Initial Catalog=Pubs"/›
‹/appSettings›
‹/configuration›
В этом случае вы можете добавить в Main() строки, обеспечивающие программное чтение этих значении. В результате вы, по существу, создадите источник (т.е. генератор) поставщика данных. Вот как может выглядеть соответствующая модификация указанного метода.
static void Main(string[] args) {
// Чтение значения ключа provider.
string dpStr = ConfigurationManager.AppSettings["provider"];
DataProvider dp = (DataProvider)Enum.Parse(typeof(DataProvider), dpStr);
// Чтение значения cnStr.
string cnStr = ConfigurationManager.AppSettings["cnStr"];
// Получение соединения.
IDbConnection myCn = GetConnection(dp);
myCn.ConnectionString = cnStr;
}
Замечание. Тип ConfigurationManager появился в .NET 2.0. He забудьте также установить ссылку на компоновочный блок System.Configuration.dll и указать using для пространства имен System.Configuration.
Если предыдущий пример преобразовать в библиотеку программного кода .NET (а не в консольное приложение), вы получите возможность создать любое число клиентов, которые могут устанавливать свои соединения, используя различные уровни абстракции. Но чтобы построить действительно полезную библиотеку, реализующую возможности источника поставщика данных, вы должны также использовать объекты команд, объекты чтения данных, адаптеры данных и другие типы, связанные с обработкой данных. Хотя построить такую библиотеку программного кода будет не слишком сложно, для нее потребуется весьма большой по объему программный код. К счастью, что касается .NET 2.0, добрые люди из Редмонда уже встроили все необходимое в библиотеки базовых классов,
Исходный код. Проект MyConnectionFactory размещен в подкаталоге, соответствующем главе 22.
Модель источника поставщика данных .NET 2.0
В .NET 2,0 предлагается модель источника поставщика данных, с помощью которой, используя обобщенные типы, можно построить единый базовый код для доступа к данным. Более того, используя файлы конфигурации приложения (в частности, их новый раздел ‹connectionStrings›), можно получать строки поставщиков и соединений декларативно, без необходимости перекомпиляции и повторной инсталляции программного обеспечения клиента.
Чтобы разобраться в реализации источника поставщика данных, вспомните из табл. 22.1, что все объекты поставщика данных получаются из одних и тех же базовых классов, определенных в пространстве имен System.Data.Common:
• DbCommand – абстрактный базовый класс для объектов команд;
• DbConnection – абстрактный базовый класс для объектов соединения;
• DbDataAdapter – абстрактный базовый класс для объектов адаптера данных
• DbDataReader – абстрактный базовый класс для объектов чтения данных;
• DbParameter – абстрактный базовый класс для объектов параметров;
• DbTransaction – абстрактный базовый класс для объектов транзакции.
Кроме того, в .NET 2.0 каждый поставщик данных от Microsoft предлагает специальный класс, получающийся из System.Data.Common.DbProviderFactory. Этот базовый класс определяет ряд методов, с помощью которых извлекаются объекты данных, специфичные для данного поставщика. Вот список соответствующих членов DbProviderFactory.
public abstract class DbProviderFactory {
…
public virtual DbCommand CreateCommand();
public virtual DbCommandBuilder CreateCommandBuilder();
public virtual DbConnection CreateConnection();
public virtual DbConnectionStringBuilder CreateConnectionStringBuilder();
public virtual DbDataAdapter CreateDataAdapter();
public virtual DbDataSourceEnumerator CreateDataSourceEnumeration();
public virtual DbParameter CreateParameter();
}
Для получения типа, производного от DbProviderFactorу и подходящего для вашего поставщика данных, пространство имен System.Data.Common предлагает тип класса DbProviderFactories. Используя статический метод GetFactory(), можно получить конкретный (и, кстати, уникальный) DbProviderFactory для указанного вами поставщика данных, например:
static void Main(string[] args) {
// Получение источника поставщика данных SQL.
DbProviderFactory sqlFactory = DbProviderFactories.GetFactory("System.Data.SqlClient");
…
// Получение источника поставщика данных Oracle.
DbProviderFactory oracleFactory = DbProviderFactories.GetFactory("System.Data.OracleClient");
…
}
Как вы, наверное, и подумали, вместо получения источника с помощью "жестко" закодированной буквальной строки, соответствующую информацию можно прочитать из файла. *.config клиента (аналогично тому, как это было сделано в предыдущем примере MyConnectionFactory). Чуть позже мы с вами так и сделаем. Но, так или иначе, создав источник своего поставщика данных, вы сможете получить объекты (соединения, команды и т.д.), соответствующие этому поставщику данных.
Зарегистрированные источники поставщиков данных
Перед тем как мы с вами рассмотрим вполне законченный пример использования источника поставщика данных ADO.NET, важно обратить внимание на то, что тип DbProviderFactories (в .NET 2.0) позволяет выбрать источники только некоторого подмножества всех возможных поставщиков данных. Список действительных источников поставщиков данных указывается в рамках элемента ‹DbProviderFactories› в файле machine.config вашей инсталляции .NET2.0 (заметим, что значение атрибута invariant идентично значению, передаваемому методу DbProviderFactories.GetFactory()).
‹system.data›
‹DbProviderFactories›
‹add name="Odbc Data Provider" invariant="System.Data.Odbc" description=".Net Framework Data Provider for Odbc" type="System.Data.Odbc.OdbcFactory, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" /›
‹add name="OleDb Data Provider" invariant="System.Data.OleDb" description=".Net Framework Data Provider for OleDb" type="System.Data.OleDb.OleDbFactory, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" /›
‹add name="OracleClient Data Provider" invariant="System.Data.OracleClient" description=".Net Framework Data Provider for Oracle" type="System.Data.OracleClient.OracleClientFactory, System.Data.OracleClient, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" /›
‹add name="SqlClient Data Provider" invariant="System.Data.SqlClient" description=".Net Framework Data Provider for SqlServer" type="System.Data.SqlClient.SqlClientFactory, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" /›