Начало работы с Entity Framework Core в ASP.NET Core - модели, DbContext, конфигурация

Внимание

Данный материал является частью цикла статей «Основы Entity Framework Core». Не забудьте посмотреть другие статьи по этой теме :-)

  1. Начало работы с Entity Framework Core в ASP.NET Core - модели, DbContext, конфигурация
  2. Настройка нереляционных свойств в EF Core
  3. Миграции в Entity Framework Core
  4. Entity Framework Core – организация связей между моделями: соглашения, аннотации данных и Fluent API
  5. Запросы к базе данных в Entity Framework Core
  6. Изменение данных с помощью Entity Framework Core

Сущности (модели) - классы, отображаемые в базе данных

Прежде чем мы начнем говорить о классах модели, нам нужно создать проект ASP.NET Core, в котором будут размещаться классы модели. Итак, мы собираемся создать проект веб-API ASP.NET Core с помощью ASP.NET Core. версия 3.1:

Добавление нового проекта ASP.NET Core Web application

Нам необходимо установить библиотеки Microsoft.EntityFrameworkCoreи Microsoft.EntityFrameworkCore.SqlServer. Это можно сделать с помощью диспетчера NuGet или окна консоли диспетчера пакетов.

Класс модели (сущности) - это класс, который Entity Framework Core использует для сопоставления с таблицей базы данных. Итак, давайте создадим нашу первую сущность, а затем объясним, как EF Core создает таблицу из созданного класса.

Давайте создадим папку Entities и внутри класса с именем Student:

public class Student
{
    public Guid StudentId { get; set; }
    public string Name { get; set; }
    public int Age { get; set; }
}

Есть несколько правил, которые помогают EF Core сопоставить этот класс с таблицей базы данных, и мы собираемся объяснить весь процесс. Прежде всего, используя имя нашего класса, EF Core получает информацию, какую таблицу использовать для столбцов и сопоставлений конфигурации (как только мы создадим класс контекста, станет намного проще понять, откуда EF Core знает что).

Затем все общедоступные свойства этого класса будут сопоставлены с одноименными столбцами таблицы. Наконец, EF Core использует соглашение об именах для создания первичного ключа из свойства StudentId в таблице базы данных (позже, в разделе «Настройка нереляционных свойств», мы увидим, как это сделать).

Предоставление ConnectionString для EF Core в ASP.NET Core

Создание класса модели или классов модели - лишь одна часть головоломки. Чтобы в EF Core была необходимая информация о базе данных для работы, нам необходимо предоставить строку подключения, изменив файл appsettings.json.

Размещение строки подключения в файле appsettings.json - обычная практика (и мы собираемся использовать ту же практику в этой статье), потому что мы можем использовать разные файлы настроек приложения для разных сред:

  • Development.json - содержит настройки, относящиеся к среде разработки.
  • Production.json - содержит настройки, относящиеся к производственной среде.
  • appsettings.json - содержит настройки, общие для обеих сред.

Но вы должны знать, что использование файлов appsettings для хранения строки подключения (или других конфиденциальных данных) - не лучшая практика, особенно для производственной среды. В таком случае лучше использовать переменные среды.

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "ConnectionStrings": {
    "sqlConnection": "server=.; database=CodeMaze; Integrated Security=true" 
  },
  "AllowedHosts": "*"
}
Как видите, мы предоставляем имя сервера базы данных, имя самой базы данных и информацию для авторизации. Конечно, вам необходимо указать допустимое имя для серверной части.

Вот и все, мы можем перейти к классу контекста.

Класс DbContext и его регистрация в ASP.NET Core

Класс контекста - еще одна важная часть приложения. Этот класс должен наследовать от базового класса DbContext, который содержит информацию и конфигурацию для доступа к базе данных. Итак, давайте создадим наш контекстный класс с именем ApplicationContext в папке Entities:

public class ApplicationContext : DbContext
{
    public ApplicationContext(DbContextOptions options)
        :base(options)
    {
    }

    public DbSet<Student> Students { get; set; }
}

Дополнительные параметры отправляются в базовый класс DbContext через конструктор ApplicationContext с помощью параметра DbContextOptions. Наконец, мы видим свойство Student типа DbSet<Student>, и это довольно важная часть.

EF Core ищет все общедоступные свойства DbSet внутри класса контекста приложения, а затем сопоставляет их имена с именами таблиц в базе данных. Затем он входит в класс, который предоставляется в свойстве `DbSet` (в нашем случае это класс Student), и сопоставляет все общедоступные свойства в столбцы таблицы с одинаковыми именами и типами (StudentId, Name и Age).

Если наш класс Student имеет какие-либо ссылки на другие классы (прямо сейчас их нет, но мы создадим отношения в следующих статьях), EF Core будет использовать эти ссылочные свойства и создавать отношения в база данных.

Регистрация класса контекста в IOC ASP.NET Core

После того, как мы закончили создание класса ApplicationContext, мы можем перейти к его регистрации.

Для этого мы собираемся открыть класс Startup.cs и изменить метод ConfigureServices:

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<ApplicationContext>(opts =>
        opts.UseSqlServer(Configuration.GetConnectionString("sqlConnection")));

    services.AddControllers();
}

Мы используем метод расширения AddDbContext для регистрации нашего класса ApplicationContext в контейнере IOC. Внутри метода UseSqlSrver мы предоставляем строку подключения к нашему классу контекста, а также можем предоставить дополнительные параметры (если в этом появится необходимость).

О AddDbContextPool

Вместо метода AddDbContext мы можем использовать метод AddDbContextPool. Мы можем использовать либо первый, либо второй метод, но во втором методе мы включаем пул DbContext. Это не будет создавать каждый раз новый экземпляр, но сначала проверит, есть ли доступные экземпляры в пуле, и если они есть, он будет использовать один из них.

Сейчас наш класс контекста готов к использованию с инъекцией зависимостей (DI) внутри нашего приложения. Итак, давайте добавим контроллер Values ​​(API) и изменим его:

public class ValuesController : ControllerBase
{
    private readonly ApplicationContext _context;

    public ValuesController(ApplicationContext context)
    {
        _context = context;
    }

    [HttpGet]
    public IActionResult Get()
    {
        //код, выполняющий обращение к _context
    }
}

Как вы могли заметить, мы внедряем наш класс контекста внутрь конструктора контроллера, что является обычным решением для DI.

Углубляемся в класс DbContext

Наш класс ApplicationContext в настоящее время принимает один параметр типа DbContextOptionsвнутри конструктора. Но мы также можем предоставить общую версию параметра DbContextOptions:

public ApplicationContext(DbContextOptions<ApplicationContext> options)
    :base(options)
{
}

Независимо от того, используем ли мы универсальную или неуниверсальную версию параметра DbContextOptions, наше приложение будет работать одинаково. Основное отличие заключается в том, что неуниверсальную версию не рекомендуется использовать, если в нашем приложении есть несколько типов контекста, что сейчас не так.

Если мы перейдем к определению DbContext, мы увидим, что внутри у него есть три свойства:

  • База данных - это свойство отвечает за транзакции, перенос / создание базы данных и необработанные SQL-запросы (обо всем этом мы поговорим в следующих статьях).
  • ChangeTracker - это свойство используется для отслеживания состояний объектов, полученных с помощью одного и того же экземпляра контекста (это также будет рассмотрено в следующих статьях).
  • Модель - это свойство обеспечивает доступ к модели базы данных, которую EF Core использует при подключении или создании базы данных.

Мы можем использовать свойство Model для доступа к информации о каждой сущности и ее свойствах.

После установки мы можем изменить наше действие Get:

var entity = _context.Model
    .FindEntityType(typeof(Student).FullName);

var tableName = entity.GetTableName();
var schemaName = entity.GetSchema();
var key = entity.FindPrimaryKey();
var properties = entity.GetProperties();

Это всего лишь несколько примеров использования свойства Model, но, тем не менее, этого должно быть достаточно, чтобы понять зачем оно нужно.

Заключение

Отлично. Мы успешно интегрировали Entity Framework Core в наше приложение ASP.NET Core и можем перейти ко всем функциям, которые оно нам предоставляет.

Подводя итог, мы узнали:

  • Что представляет собой класс сущности (модели) в EF Core?
  • Как предоставить строку подключения для нашего приложения
  • Как создать класс контекста и почему это так важно для нас
  • Дополнительная информация о классе DbContext