Книги онлайн и без регистрации » Разная литература » Язык программирования C#9 и платформа .NET5 - Эндрю Троелсен

Язык программирования C#9 и платформа .NET5 - Эндрю Троелсен

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 288 289 290 291 292 293 294 295 296 ... 407
Перейти на страницу:
class="code">protected BaseRepo(ApplicationDbContext context)

{

  Context = context;

  _disposeContext = false;

}

protected BaseRepo(DbContextOptions<ApplicationDbContext> 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<T> класса ApplicationDbContext можно ссылаться с использованием метода Context.Set<T>(). Создайте открытое свойство по имени Table типа DbSet<T> и установите его начальное значение в конструкторе:

public DbSet<T> Table { get; }

protected BaseRepo(ApplicationDbContext context)

{

  Context = context;

  Table = Context.Set<T>();

  _disposeContext = false;

}

Реализация метода SaveChanges()

Класс 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);

  }

}

Реализация общих методов чтения

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

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

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

public virtual T? FindAsNoTracking(int id) =>

  Table.AsNoTrackingWithIdentityResolution().FirstOrDefault(x => x.Id == id);

Другая вариация удаляет из сущности фильтры запросов и затем применяет сокращенную версию (пропускающую метод Where()) для получения FirstOrDefault(). Добавьте в класс следующий код:

public T? FindIgnoreQueryFilters(int id) =>

  Table.IgnoreQueryFilters().FirstOrDefault(x => x.Id == id);

Методы GetAll() возвращают все записи из таблицы. Первый метод извлекает их в порядке, поддерживаемом в базе данных, а второй по очереди обрабатывает все фильтры запросов:

public virtual IEnumerable<T> GetAll() => Table;

public virtual IEnumerable<T> GetAllIgnoreQueryFilters()

  => Table.IgnoreQueryFilters();

Метод ExecuteQuery() предназначен для выполнения хранимых процедур:

public void ExecuteQuery(string sql, object[] sqlParametersObjects)

  => Context.Database.ExecuteSqlRaw(sql, sqlParametersObjects);

Реализация методов добавления, обновления и удаления

Далее понадобится добавить блок кода, который будет служить оболочкой для соответствующих методов добавления, обновления и удаления, связанных со специфичным свойством DbSet<T>. Параметр persist определяет, выполняет ли хранилище вызов SaveChanges() сразу же после вызова методов добавления, обновления и удаления. Все методы помечены как virtual, чтобы сделать возможным дальнейшее переопределение. Добавьте в класс показанный ниже код:

public virtual int Add(T entity, bool persist = true)

{

  Table.Add(entity);

  return persist ? SaveChanges() : 0;

}

public virtual int AddRange(IEnumerable<T> entities, bool persist = true)

{

  Table.AddRange(entities);

  return persist ? SaveChanges() : 0;

}

public virtual int Update(T entity, bool persist = true)

{

  Table.Update(entity);

  return persist ? SaveChanges() : 0;

}

public virtual int UpdateRange(IEnumerable<T> entities, bool persist = true)

{

  Table.UpdateRange(entities);

  return persist ? SaveChanges() : 0;

}

public virtual int Delete(T entity, bool persist = true)

{

  Table.Remove(entity);

  return persist ? SaveChanges() : 0;

}

public virtual int DeleteRange(IEnumerable<T> entities, bool persist = true)

{

  Table.RemoveRange(entities);

  return persist ? SaveChanges() : 0;

}

Есть еще один метод удаления, который не следует этому шаблону. Для выдачи операции удаления он использует EntityState, что часто происходит при работе с ASP.NET Core с целью сокращения сетевого трафика:

public int Delete(int id, byte[] timeStamp, bool persist = true)

{

  var entity = new T {Id = id, TimeStamp = timeStamp};

  Context.Entry(entity).State = EntityState.Deleted;

  return persist ? SaveChanges() : 0;

}

Итак, класс BaseRepo завершен, и можно приступать к построению хранилищ, специфичных для сущностей.

Интерфейсы хранилищ, специфичных для сущностей

Каждая сущность будет иметь строго типизированное хранилище, производное от BaseRepo<T>, и интерфейс, который реализует IRepo<T>. Создайте в каталоге Repos проекта AutoLot.Dal новый каталог по имени Interfaces и добавьте в него пять файлов интерфейсов:

ICarRepo.cs

ICreditRiskRepo.cs

ICustomerRepo.cs

IMakelRepo.cs

IOrderRepo.cs

Содержимое интерфейсов будет представлено в последующих разделах.

Интерфейс хранилища данных об автомобилях

Откройте файл ICarRepo.cs и поместите в его начало такие операторы using:

using System.Collections.Generic;

using AutoLot.Models.Entities;

using AutoLot.Dal.Repos.Base;

Измените интерфейс на public и реализуйте IRepo<Car>, как показано ниже:

namespace AutoLot.Dal.Repos.Interfaces

{

  public interface ICarRepo : IRepo<Car>

  {

    IEnumerable<Car> GetAllBy(int makeId);

    string GetPetName(int id);

  }

}

Интерфейс хранилища данных о кредитных рисках

Откройте файл ICreditRiskRepo.cs. Интерфейс ICreditRiskRep не добавляет никакой функциональности сверх той, что предоставляется в BaseRepo. Обновите код следующим образом:

using AutoLot.Models.Entities;

using AutoLot.Dal.Repos.Base;

namespace AutoLot.Dal.Repos.Interfaces

{

1 ... 288 289 290 291 292 293 294 295 296 ... 407
Перейти на страницу:

Комментарии
Минимальная длина комментария - 20 знаков. В коментария нецензурная лексика и оскорбления ЗАПРЕЩЕНЫ! Уважайте себя и других!
Комментариев еще нет. Хотите быть первым?