Для взаимодействия с базой данных для контекста данных должна быть определена конфигурация подключения. Для ее установки можно применять два способа:
Переопределение у класса контекста данных метода OnConfiguring()
Передача конфигурации в конструктор базового класса DbContext
В предыдущих темах использовался первый метод. Например:
public class ApplicationContext : DbContext { public DbSet<User> Users { get; set; } = null!; public ApplicationContext() => Database.EnsureCreated(); protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseSqlite("Data Source=helloapp.db"); } }
В этот метод передается объект класса DbContextOptionsBuilder, который позволяет установить параметры подключения.
Для их конфигурации параметров подключения у этого класса определено ряд методов в зависимости от того, какую именно систему баз данных мы собираемся
использовать. Например, для установки подключения к SQLite вызывается метод UseSqlite()
, в который передается строка подключения.
Это способ вполне рабочий и может использоваться. Единственно, что хочется отметить, что нам необязательно жестко определять строку подключения внутри контекста, мы можем получать ее извне:
using Microsoft.EntityFrameworkCore; public class ApplicationContext : DbContext { public DbSet<User> Users { get; set; } = null!; public string connectionString; public ApplicationContext(string connectionString) { this.connectionString = connectionString; // получаем извне строку подключения Database.EnsureCreated(); } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseSqlite(connectionString); } } public class User { public int Id { get; set; } public string? Name { get; set; } public int Age { get; set; } }
Затем при создании объекта контекста передать строку подключения:
using (ApplicationContext db = new ApplicationContext("Data Source=helloapp.db")) { var users = db.Users.ToList(); Console.WriteLine("Пользователи:"); foreach (User user in users) { Console.WriteLine($"{user.Id}.{user.Name} - {user.Age}"); } }
Второй способ предполагает передачу в конструктор базового класса объекта DbContextOptions, который инкапсулирует параметры конфигурации. Для применения этого способа изменим класс контекста следующим образом:
using Microsoft.EntityFrameworkCore; public class ApplicationContext : DbContext { public DbSet<User> Users { get; set; } = null!; public ApplicationContext(DbContextOptions<ApplicationContext> options) : base(options) { Database.EnsureCreated(); } } public class User { public int Id { get; set; } public string? Name { get; set; } public int Age { get; set; } }
Тогда мы могли бы использовать класс контекста следующим образом:
using Microsoft.EntityFrameworkCore; var optionsBuilder = new DbContextOptionsBuilder<ApplicationContext>(); var options = optionsBuilder.UseSqlite("Data Source=helloapp.db").Options; using (ApplicationContext db = new ApplicationContext(options)) { var users = db.Users.ToList(); foreach (User user in users) Console.WriteLine($"{user.Id}.{user.Name} - {user.Age}"); }
Здесь опять же применяется метод UseSqlServer класса DbContextOptionsBuilder для создания конфигурации по той же строке подключения. Только результат этой операции - объект DbContextOptions затем передается в контекст данных. А контекст данных далее передает этот параметр в конструктор базового класса.
Оба выше представленных способа вполне работают, однако в том определении, в котором они представлены, они имеют один недостаток - строка подключения жестко определена в коде C#. И было бы неплохо, если бы она была бы определена в каком-нибудь внешнем файле подключения, где мы ее могли бы поменять без перекомпиляции приложения.
Для этого добавим в проект новый файл, который назовем appsettings.json и который будет представлять конфигурацию в формате json.
Определим в этом файле следующий код:
{ "ConnectionStrings": { "DefaultConnection": "Data Source=helloapp.db" } }
Здесь опять же определена наша строка подключения.
Чтобы ее использовать, нам надо добавить в проект через Nuget пакет: Microsoft.Extensions.Configuration.Json. Этот пакет специально предназначен для работы с конфигурацией в формате json.
Если мы работаем в Visual Studio, то для файла в окне свойств установим опции Copy to Output Directory значение "Copy if newer" (или "Copy always")
Для работы с БД возьмем ранее определенный класс контекста:
using Microsoft.EntityFrameworkCore; public class ApplicationContext : DbContext { public DbSet<User> Users { get; set; } = null!; public ApplicationContext(DbContextOptions<ApplicationContext> options) : base(options) { Database.EnsureCreated(); } }
Далее в файле Program.cs определим следующий код:
using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; var builder = new ConfigurationBuilder(); // установка пути к текущему каталогу builder.SetBasePath(Directory.GetCurrentDirectory()); // получаем конфигурацию из файла appsettings.json builder.AddJsonFile("appsettings.json"); // создаем конфигурацию var config = builder.Build(); // получаем строку подключения var connectionString = config.GetConnectionString("DefaultConnection"); var optionsBuilder = new DbContextOptionsBuilder<ApplicationContext>(); var options = optionsBuilder.UseSqlite(connectionString).Options; using (ApplicationContext db = new ApplicationContext(options)) { var users = db.Users.ToList(); foreach (User user in users) Console.WriteLine($"{user.Id}.{user.Name} - {user.Age}"); }
Для создания конфигурации применяется класс ConfigurationBuilder. Метод AddJsonFile() добавляет все настройки из файла конфигурации.
С помощью метода Build()
создается объект конфигурации, из которого мы можем получить строку подключения:
string connectionString = config.GetConnectionString("DefaultConnection");
Для получения строки подключения используется ее имя - "DefaultConnection", которое указано в appsettings.json. В остальном работа с контекстом данных будет протекать также.
Приведенный выше способ позволяет локально при вызове констекста задать файл конфигурации. Но если у нас всего один файл конфигурации, который планируется использовать при всех обращениях к контексту данных, то проще задать его непосредственно в контексте данных:
using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; public class ApplicationContext : DbContext { public DbSet<User> Users { get; set; } = null!; public ApplicationContext() : base() { Database.EnsureCreated(); } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { var config = new ConfigurationBuilder() .AddJsonFile("appsettings.json") .SetBasePath(Directory.GetCurrentDirectory()) .Build(); optionsBuilder.UseSqlite(config.GetConnectionString("DefaultConnection")); } } public class User { public int Id { get; set; } public string? Name { get; set; } public int Age { get; set; } }
В данном случае установка конфигурации производится в методе OnConfiguring()
контекста данных. Применение контекста:
using (ApplicationContext db = new ApplicationContext()) { var users = db.Users.ToList(); foreach (User user in users) Console.WriteLine($"{user.Id}.{user.Name} - {user.Age}"); }