Генератор поставщиков данных. Пример независимого кода

В статье «ADO.Net. Элементы теории» отмечалось, что двумя основными компонентами ADO.NET для доступа к данным и их обработки являются поставщики данных .NET Framework и DataSet. На примере реляционной модели БД будет показано, как создать единую кодовую базу с помощью обобщенных типов доступа к данным (библиотека System.Data.Common) и конфигурационных файлов. В примере используется БД автотранспортного предприятия Garage из статьи «Создание базы данных SQL Server«.

В примере «Продажа билетов в кинотеатре» для источника подключения — «Файл базы данных Microsoft Access» доступен  единственный поставщик данных — .Net Framework для OLE DB. Для работы с БД на основе SQL Server необходим поставщик данных SqlClient, для других источников данных потребуется Odbs. Возможно ли написать код программы, независимый от конкретного поставщика? Ведь в  библиотеке System.Data.Common содержится описание классов, наследуемых в библиотеках System.Data.SqlClient, System.Data.OleDb и System.Data.Odbc.

Постановка задачи

Используя файл конфигурации App.config  и сборку System.Configuration, а также классы библиотеки System.Data.Common написать приложение, в котором явно не указывается конкретный поставщик данных.

Решение

1) Создадим в Visual Studio 2017 Community  консольное приложение ГенераторПоставщиковДанных. Добавим сразу оператор using System.Data.Common;

2) Добавим оператор using System.Configuration;
Примечание. Рекомендуется проверить наличие ссылки на эту сборку, для чего выберите Проект/Добавить ссылку, после чего в окне «Менеджер ссылок» отметить позицию System.Configuration и нажать Ok.

3) Откройте для редактирования файл App.config (Если его нет в вашем проекте, добавьте его: Проект/Добавление нового элемента/Файл конфигурации приложения). В редакторе кода App.config добавьте элемент <appSettings> с двумя ключами (key): «provider» со значением «System.Data.SqlClient» и «conStr» с указанием подключения к базе данных Garage (см. предыдущий пример). Подключение к БД получите через Обозреватель объектов SQL Server, кликнув правой кнопкой на БД Garage, и в окне Свойства объекта Garage скопируйте строку подключения, у меня, например:
Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=Garage;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False

Текст файла App.config:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
   <startup> 
      <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
   </startup>
   <appSettings>
     <!-- Поставщик -->
       <add key="provider" value="System.Data.SqlClient"/>
     <!-- Строка подключения -->
       <add key="conStr" value="Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=Garage;
           Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;
           ApplicationIntent=ReadWrite;MultiSubnetFailover=False"/>
   </appSettings>
</configuration>

Теперь все необходимое находится в файле конфигурации. Понятно, что при смене провайдера изменится первая строка в <appSetting>, а при смене БД — вторая строка и только!

4) Перейдем к редактированию Program.cs. В метод Main( ) добавим три оператора:

// Получение поставщика и строки подключения из App.config
string dp = ConfigurationManager.AppSettings["provider"];
string cnStr = ConfigurationManager.AppSettings["conStr"];
// Получение генератора поставщика df
DbProviderFactory df = DbProviderFactories.GetFactory(dp);

Класс System.Data.Common.DbProviderFactory представляет набор методов для создания экземпляров реализации поставщика для классов источника данных. Метод GetFactory( ) возвращает экземпляр класса. Далее нам будет нужны только генератор поставщика df и строка подключения cnStr.

5)  Зададимся целью прочитать содержимое трех таблиц БД Garage: Cars, Drivers, Routes. Для этого нам понадобятся объекты трех классов DbConnection, DbCommand и DbDataReader из библиотеки System.Data.Common. Используем вложенную конструкцию using {  }, упомянутую в конце статьи «Сборка мусора и финализаторы«. Напомним, что конструкция  упрощает работу с объектами, которые реализуют интерфейс IDisposable. Интерфейс IDisposable содержит один метод .Dispose(), который используется для освобождения ресурсов,
которые захватил объект.

Тогда полный текст Program.cs:

// Генератор поставщиков данных 
using System;
using System.Configuration;
using System.Data.Common;

namespace ГенераторПоставщиковДанных
{
  class Program
  {
    static void Main(string[] args)
    {
      // Получение строки подключения и поставщика из App.config
      string dp = ConfigurationManager.AppSettings["provider"];
      string cnStr = ConfigurationManager.AppSettings["conStr"];

      // Получение генератора поставщика df
      DbProviderFactory df = DbProviderFactories.GetFactory(dp);

      // Получение объекта "подключение" (через df)
      using (DbConnection cn = df.CreateConnection())
      {
        Console.WriteLine("Объект подключения: " + cn.GetType().Name);
        cn.ConnectionString = cnStr;
        cn.Open();

        // Создание объекта "команда" (через df)
        DbCommand cmd = df.CreateCommand();
        Console.WriteLine("Объект команды: " + cmd.GetType().Name);
        cmd.Connection = cn;
        // cmd.CommandText = strSQL + "TableName";
        string strSQL = "Select * From ";

        // Вывод парка машин с помощью объекта "чтение данных" dr
        cmd.CommandText = strSQL + "Cars";
        using (DbDataReader dr = cmd.ExecuteReader())
        {
          Console.WriteLine("Объект чтения данных: " + dr.GetType().Name);
          Console.WriteLine("\n Автопарк");
          while (dr.Read())
            Console.WriteLine("-> ID авто-{0} | ТипАвто-{1} | госномер-{2} | число пассажиров-{3}",
dr[0], dr[1], dr[2], dr[3]);
        }

        // Вывод списка водителей
        cmd.CommandText = strSQL + "Drivers"; ;
        using (DbDataReader dr = cmd.ExecuteReader())
        {
          Console.WriteLine("\n Водители");
          while (dr.Read())
            Console.WriteLine("-> ID водителя-{0} | Фамилия_имя-{1} | права-{2} | работа/выходной-{3}",
dr[0], dr[1], dr[2], dr[3]);
        }

        // Вывод маршрутов (водитель-авто)
        cmd.CommandText = strSQL + "Routes";
        using (DbDataReader dr = cmd.ExecuteReader())
        {
          Console.WriteLine("\n Маршруты");
          while (dr.Read())
           Console.WriteLine("-> ID маршрута-{0} | Номер маршрута-{1} | ID авто-{2} | ID водителя-{3}",
dr[0], dr[1], dr[2], dr[3]);
        }

        Console.ReadKey();
      }
    }
  }
}

Результат:

Первые три строки содержат информацию по объектам «подключение», «команда» и «чтение данных».

Вывод. Поставленная задача написания независимого (от типа БД) кода выполнена.

В следующей статье «Примеры SQL-запросов. Microsoft SQL Server и язык T-SQL» описаны действия по удалению, вставке и изменению записей в таблицах БД .

Оставьте комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *