Добавьте в каталог Repos\Base файл класса по имени BaseRepo.cs. Класс BaseRepo будет реализовывать интерфейс IRepo и предлагать основную функциональность для хранилищ, специфичных к типам (рассматриваются далее). Приведите операторы using к следующему виду:

using System;

using System.Collections.Generic;

using System.Linq;

using AutoLot.Dal.EfStructures;

using AutoLot.Dal.Exceptions;

using AutoLot.Models.Entities.Base;

using Microsoft.EntityFrameworkCore;

Сделайте класс обобщенным с типом Т и добавьте к нему ограничения BaseEntity и new, что сузит набор типов до классов, которые имеют конструктор без параметров. Реализуйте интерфейс IRepo:

public abstract class BaseRepo : IRepo where T : BaseEntity, new

Классу хранилища нужен экземпляр ApplicationDbContext, внедренный через конструктор. В случае использования с контейнером внедрения зависимостей ASP.NET Core временем жизни контекста будет управлять контейнер. Второй конструктор будет принимать DbContextOptions и должен создавать экземпляр ApplicationDbContext, который понадобится освобождать. Поскольку этот класс является абстрактным, оба конструктора определяются как защищенные. Добавьте в открытый класс ApplicationDbContext следующий код:

private readonly bool _disposeContext;

public ApplicationDbContext Context { get; }

protected BaseRepo(ApplicationDbContext context)

{

  Context = context;

  _disposeContext = false;

}

protected BaseRepo(DbContextOptions options) : this(new

ApplicationDbContext(options))

{

  _disposeContext = true;

}

public void Dispose

{

  Dispose(true);

  GC.SuppressFinalize(this);

}

private bool _isDisposed;

protected virtual void Dispose(bool disposing)

{

  if (_isDisposed)

  {

    return;

  }

  if (disposing)

  {

    if (_disposeContext)

    {

      Context.Dispose;

    }

  }

  _isDisposed = true;

}

~BaseRepo

{

  Dispose(false);

}

На свойства DbSet класса ApplicationDbContext можно ссылаться с использованием метода Context.Set. Создайте открытое свойство по имени Table типа DbSet и установите его начальное значение в конструкторе:

public DbSet Table { get; }

protected BaseRepo(ApplicationDbContext context)

{

  Context = context;

  Table = Context.Set;

  _disposeContext = false;

}

<p id="AutBody_Root992"><strong>Реализация метода SaveChanges</strong></p>

Класс BaseRepo имеет метод SaveChanges, который вызывает переопределенную версию SaveChanges и демонстрирует обработку специальных исключений. Добавьте в класс BaseRepo показанный ниже код:

public int SaveChanges

{

  try

  {

    return Context.SaveChanges;

  }

  catch (CustomException ex)

  {

    // Подлежит надлежащей обработке -- уже зарегистрировано в журнале.

    throw;

  }

  catch (Exception ex)

  {

    // Подлежит регистрации в журнале и надлежащей обработке.

    throw new CustomException("An error occurred updating the database", ex);

  }

}

<p id="AutBody_Root993"><strong>Реализация общих методов чтения</strong></p>

Следующий комплект методов возвращает записи с применением операторов LINQ. Метод Find принимает первичный ключ (ключи) и сначала выполняет поиск в ChangeTracker. Если сущность уже отслеживается, тогда возвращается отслеживаемый экземпляр, иначе запись извлекается из базы данных.

public virtual T? Find(int? id) => Table.Find(id);

Дополнительные два метода Find расширяют базовый метод Find. Приведенный далее метод демонстрирует извлечение записи, но без ее добавления в ChangeTracker, используя AsNoTrackingWithldentityResolution. Добавьте в класс показанный ниже код:

public virtual T? FindAsNoTracking(int id) =>

Перейти на страницу:

Похожие книги