Язык программирования C#9 и платформа .NET5 - Эндрю Троелсен
Шрифт:
Интервал:
Закладка:
using System;
using System.Data.Common;
using System.Data.Odbc;
#if PC
using System.Data.OleDb;
#endif
using System.IO;
using Microsoft.Data.SqlClient;
using Microsoft.Extensions.Configuration;
Очистите весь код в Program.cs и добавьте взамен следующий код:
using System;
using System.Data.Common;
using System.Data.Odbc;
#if PC
using System.Data.OleDb;
#endif
using System.IO;
using Microsoft.Data.SqlClient;
using Microsoft.Extensions.Configuration;
using DataProviderFactory;
Console.WriteLine("***** Fun with Data Provider Factories *****n");
var (provider, connectionString) = GetProviderFromConfiguration();
DbProviderFactory factory = GetDbProviderFactory(provider);
// Теперь получить объект подключения.
using (DbConnection connection = factory.CreateConnection())
{
if (connection == null)
{
Console.WriteLine($"Unable to create the connection object");
// He удалось создать объект подключения
return;
}
Console.WriteLine($"Your connection object is a: {connection.GetType().Name}");
connection.ConnectionString = connectionString;
connection.Open();
// Создать объект команды.
DbCommand command = factory.CreateCommand();
if (command == null)
{
Console.WriteLine($"Unable to create the command object");
// He удалось создать объект команды
return;
}
Console.WriteLine($"Your command object is a: {command.GetType().Name}");
command.Connection = connection;
command.CommandText =
"Select i.Id, m.Name From Inventory i inner join Makes m on m.Id =
i.MakeId ";
// Вывести данные с помощью объекта чтения данных.
using (DbDataReader dataReader = command.ExecuteReader())
{
Console.WriteLine($"Your data reader object is a:
{dataReader.GetType().Name}");
Console.WriteLine("n***** Current Inventory *****");
while (dataReader.Read())
{
Console.WriteLine($"-> Car #{dataReader["Id"]} is a
{dataReader["Name"]}.");
}
}
}
Console.ReadLine();
Добавьте приведенный далее код в конец файла Program.cs. Эти методы читают конфигурацию, устанавливают корректное значение DataProviderEnum, получают строку подключения и возвращают экземпляр DbProviderFactory:
static DbProviderFactory GetDbProviderFactory(DataProviderEnum provider)
=> provider switch
{
DataProviderEnum.SqlServer => SqlClientFactory.Instance,
DataProviderEnum.Odbc => OdbcFactory.Instance,
#if PC
DataProviderEnum.OleDb => OleDbFactory.Instance,
#endif
_ => null
};
static (DataProviderEnum Provider, string ConnectionString)
GetProviderFromConfiguration()
{
IConfiguration config = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", true, true)
.Build();
var providerName = config["ProviderName"];
if (Enum.TryParse<DataProviderEnum>
(providerName, out DataProviderEnum provider))
{
return (provider,config[$"{providerName}:ConnectionString"]);
};
throw new Exception("Invalid data provider value supplied.");
}
Обратите внимание, что в целях диагностики с помощью служб рефлексии выводятся имена лежащих в основе объектов подключения, команды и чтения данных. В результате запуска приложения в окне консоли отобразятся текущие данные из таблицы Inventory базы данных AutoLot:
*****
Fun with Data Provider Factories
*****
Your connection object is a: SqlConnection
Your command object is a: SqlCommand
Your data reader object is a: SqlDataReader
*****
Current Inventory
*****
-> Car #1 is a VW.
-> Car #2 is a Ford.
-> Car #3 is a Saab.
-> Car #4 is a Yugo.
-> Car #9 is a Yugo.
-> Car #5 is a BMW.
-> Car #6 is a BMW.
-> Car #7 is a BMW.
-> Car #8 is a Pinto.
Измените файл настроек, чтобы указать другого поставщика. Код выберет связанную строку подключения и произведет тот же вывод, что и ранее, исключая специфичную для типа информацию.
Конечно, в зависимости от опыта работы с ADO.NET у вас может не быть полного понимания того, что в действительности делают объекты подключений, команд и чтения данных. Не вдаваясь в детали, пока просто запомните, что модель фабрики поставщиков данных ADO.NET позволяет строить единственную кодовую базу, которая способна потреблять разнообразные поставщики данных в декларативной манере.
Потенциальный недостаток модели фабрики поставщиков данных
Хотя модель фабрики поставщиков данных характеризуется высокой мощностью, вы должны обеспечить применение в кодовой базе только типов и методов, общих для всех поставщиков, посредством членов абстрактных базовых классов. Следовательно, при разработке кодовой базы вы ограничены членами DbConnection, DbCommand и других типов из пространства имен System.Data.Common.
С учетом сказанного вы можете прийти к заключению, что такой обобщенный подход предотвращает прямой доступ к дополнительным возможностям отдельной СУБД. Если вы должны быть в состоянии обращаться к специфическим членам лежащего в основе поставщика (например, SqlConnection), то можете воспользоваться явным приведением:
if (connection is SqlConnection sqlConnection)
{
// Вывести информацию об используемой версии SQL Server.
WriteLine(sqlConnection.ServerVersion);
}
Однако в таком случае кодовая база становится чуть труднее в сопровождении (и менее гибкой), потому что придется добавить некоторое количество проверок времени выполнения. Тем не менее, если необходимо строить библиотеки доступа к данным наиболее гибким способом из числа возможных, тогда модель фабрики поставщиков данных предлагает замечательный механизм для решения такой задачи.
На заметку! Инфраструктура Entity Framework Core и ее поддержка внедрения зависимостей значительно упрощает построение библиотек доступа к данным, которым необходим доступ к разрозненным источникам данных.
Первый пример завершен, и теперь можно углубляться в детали работы с ADO.NET.
Погружение в детали объектов подключений, команд и чтения данных
Как было показано в предыдущем примере, ADO.NET позволяет взаимодействовать с базой данных с помощью объектов подключения, команд и чтения данных имеющегося поставщика данных. Для более глубокого понимания упомянутых объектов в ADO.NET будет создан расширенный пример.
В предыдущем примере демонстрировалось, что для подключения к базе данных и чтения записей посредством объекта чтения данных, необходимо было выполнить следующие шаги.
1. Создать, сконфигурировать и открыть объект подключения.
2. Создать и сконфигурировать объект команды, указав объект подключения в аргументе конструктора или через свойство Connection.
3. Вызвать