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

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

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 287 288 289 290 291 292 293 294 295 ... 407
Перейти на страницу:
поступить и по-другому: удалить хранимую процедуру из базы данных и затем применить миграцию. В итоге нарушится парадигма "одно место для обновлений", но это часть перехода со способа "сначала база данных" на способ "сначала код".

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

Добавление модели представления

Теперь, когда представление SQL Server на месте, самое время создать модель представления, которая будет использоваться для отображения данных из представления. Модель представления будет добавлена как DbSet<T> без ключа. Преимущество такого подхода в том, что данные можно запрашивать с помощью нормального процесса LINQ, общего для всех коллекций DbSet<T>.

Добавление класса модели представления

Добавьте в проект AutoLot.Models новый каталог по имени ViewModels, создайте в нем файл класса CustomerOrderViewModel.cs и поместите в него такие операторы using:

using System.ComponentModel.DataAnnotations.Schema;

using Microsoft.EntityFrameworkCore;

Приведите код к следующему виду:

namespace AutoLot.Models.ViewModels

{

  [Keyless]

  public class CustomerOrderViewModel

  {

    public string? FirstName { get; set; }

    public string? LastName { get; set; }

    public string? Color { get; set; }

    public string? PetName { get; set; }

    public string? Make { get; set; }

    public bool? IsDrivable { get;set; }

    [NotMapped]

    public string FullDetail =>

     $"{FirstName} {LastName} ordered a {Color} {Make} named {PetName}";

   public override string ToString() => FullDetail;

  }

}

Аннотация данных [KeyLess] указывает, что класс является сущностью, работающей с данными, которые не имеют первичного ключа и могут быть оптимизированы как данные только для чтения (с точки зрения базы данных). Первые пять свойств соответствуют данным, поступающим из представления. Свойство FullDetail декорировано посредством аннотации данных [NotMapped], которая информирует инфраструктуру EF Core о том, что это свойство не должно включаться в базу данных, и не может поступать из базы данных в результате операций запросов. Инфраструктура EF Core также игнорирует переопределенную версию метода ToString().

Добавление класса модели представления к ApplicationDbContext

Финальный шаг предусматривает регистрацию и конфигурирование CustomerOrderViewModel в ApplicationDbContext.

Добавьте к ApplicationDbContext оператор using для AutoLot.Models.ViewModels и затем свойство DbSet<T>:

public virtual DbSet<CustomerOrderViewModel>?

  CustomerOrderViewModels { get; set; }

Помимо добавления свойства DbSet<T> необходимо с помощью Fluent API сопоставить модель представления с представлением SQL Server. Метод HasNoKey() из Fluent API и аннотация данных [KeyLess] делают то же самое, но метод Fluent API замещает аннотацию данных. Ради ясности рекомендуется оставлять аннотацию данных на месте. Добавьте в метод OnModelCreating() следующий код:

modelBuilder.Entity<CustomerOrderViewModel>(entity =>

{

  entity.HasNoKey().ToView("CustomerOrderView","dbo");

});

Добавление хранилищ

Распространенный паттерн проектирования для доступа к данным называется "Хранилище" (Repository). Согласно описанию Мартина Фаулера (http://www.martinfowler.com/eaaCatalog/repository.html) ядро этого паттерна является посредником между уровнями предметной области и сопоставления с данными. Наличие обобщенного хранилища, которое содержит общий код доступа к данным, помогает устранить дублирование кода. Наличие специфических хранилищ и интерфейсов, производных от базового хранилища, также хорошо подходит для работы с инфраструктурой внедрения зависимостей в ASP.NET Core.

Каждая сущность предметной области внутри уровня доступа к данным AutoLot будет иметь строго типизированное хранилище для инкапсуляции всей работы по доступу к данным. Первым делом создайте в проекте AutoLot.Dal новый каталог по имени Repos, предназначенный для хранения всех классов.

На заметку! Не воспринимайте следующий раздел как буквальную интерпретацию паттерна проектирования "Хранилище". Если вас интересует исходный паттерн, который послужил мотивом для создания приведенной здесь версии, тогда почитайте о нем по ссылке http://www.martinfowler.com/eaaCatalog/repository.html.

Добавление базового интерфейса IRepo

Базовый интерфейс IRepo предоставляет множество общих методов, используемых при доступе к данным. Добавьте в проект AutoLot.Dal новый каталог по имени Repos и создайте в нем еще один каталог под названием Base. Поместите в каталог ReposBase новый файл интерфейса по имени IRepo.cs. Обновите операторы using, как показано ниже:

using System;

using System.Collections.Generic;

Так выглядит полный интерфейс:

namespace AutoLot.Dal.Repos.Base

{

  public interface IRepo<T>: IDisposable

  {

    int Add(T entity, bool persist = true);

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

    int Update(T entity, bool persist = true);

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

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

    int Delete(T entity, bool persist = true);

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

    T? Find(int? id);

    T? FindAsNoTracking(int id);

    T? FindIgnoreQueryFilters(int id);

    IEnumerable<T> GetAll();

    IEnumerable<T> GetAllIgnoreQueryFilters();

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

    int SaveChanges();

  }

}

Добавление класса BaseRepo

Добавьте в каталог ReposBase файл класса по имени 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<T>:

public abstract class BaseRepo<T> : IRepo<T> where T : BaseEntity, new()

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

private readonly bool _disposeContext;

public ApplicationDbContext Context { get; }

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

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