Skip to content

Instantly share code, notes, and snippets.

@sunmeat
Created September 12, 2026 14:07
Show Gist options
  • Select an option

  • Save sunmeat/7699fb742a6182434e4e45768ac3f3ef to your computer and use it in GitHub Desktop.

Select an option

Save sunmeat/7699fb742a6182434e4e45768ac3f3ef to your computer and use it in GitHub Desktop.
ДЗ: багаторівнева архітектура, шар доступу до даних DAL

Багаторівнева архітектура в ASP.NET Core MVC

Рівень доступу до даних (Data Access Layer)

Веб-додаток «Кінопошук» / «10 найкращих фільмів»

Завдання

Модифікувати раніше розроблений веб-додаток «Кінопошук» («10 найкращих фільмів») з монолітною архітектурою таким чином, щоб отримати трирівневу (three-layer) архітектуру:

  1. Presentation Layer — контролери, представлення (Views) або Web API ендпоінти.
  2. Business Logic Layer / Service Layer — сервіси для обробки бізнес-логіки та файлів (наприклад, IMovieService).
  3. Data Access Layer (DAL) — рівень доступу до даних (реалізується в цьому завданні).

Необхідно реалізувати Data Access Layer, зокрема:

  • Створити класи-репозиторії для роботи з сутностями бази даних.
  • Забезпечити взаємодію з репозиторіями через абстракцію IRepository<T> для досягнення слабкої зв’язаності (low coupling).
  • Застосувати патерн Unit of Work, який:
    • Спрощує роботу з кількома репозиторіями.
    • Гарантує, що всі репозиторії використовують один і той же контекст даних (DbContext).

Структура Data Access Layer

Компонент Призначення
IRepository<T> Загальний інтерфейс репозиторію (CRUD-операції та інші загальні методи).
Repository<T> Базова реалізація репозиторію на основі Entity Framework Core.
Specific repositories Окремі репозиторії (наприклад, IMovieRepository, MovieRepository), якщо потрібні спеціальні запити (наприклад, фільтрація за жанром або режисером).
IUnitOfWork Інтерфейс, що надає доступ до всіх репозиторіїв та методу SaveChangesAsync().
UnitOfWork Реалізація патерну: тримає один DbContext і повертає екземпляри репозиторіїв.

Ключові інтерфейси та класи

1. Загальний репозиторій

public interface IRepository<T> where T : class
{
    Task<T?> GetByIdAsync(int id);
    Task<IEnumerable<T>> GetAllAsync();
    Task AddAsync(T entity);
    void Update(T entity);
    void Delete(T entity);
    IQueryable<T> Query(); // для спеціальних запитів та фільтрації
}

2. Unit of Work

public interface IUnitOfWork : IDisposable
{
    IRepository<Movie> Movies { get; }
    IRepository<Genre> Genres { get; }
    IRepository<Director> Directors { get; }
    // Додати інші репозиторії за потреби

    Task<int> SaveChangesAsync();
}

3. Реалізація Unit of Work

public class UnitOfWork : IUnitOfWork
{
    private readonly MovieDbContext _context;
    
    public IRepository<Movie> Movies { get; private set; }
    public IRepository<Genre> Genres { get; private set; }
    public IRepository<Director> Directors { get; private set; }

    public UnitOfWork(MovieDbContext context)
    {
        _context = context;
        Movies = new Repository<Movie>(context);
        Genres = new Repository<Genre>(context);
        Directors = new Repository<Director>(context);
    }

    public async Task<int> SaveChangesAsync()
    {
        return await _context.SaveChangesAsync();
    }

    public void Dispose()
    {
        _context.Dispose();
    }
}

Реєстрація в DI-контейнері (Program.cs)

builder.Services.AddDbContext<MovieDbContext>(options =>
    options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));

builder.Services.AddScoped<IUnitOfWork, UnitOfWork>();

Використання у сервісі / контролері (Приклад)

public class MovieService : IMovieService
{
    private readonly IUnitOfWork _unitOfWork;
    private readonly IWebHostEnvironment _environment;

    public MovieService(IUnitOfWork unitOfWork, IWebHostEnvironment environment)
    {
        _unitOfWork = unitOfWork;
        _environment = environment;
    }

    public async Task<IEnumerable<Movie>> GetAllMoviesAsync()
    {
        return await _unitOfWork.Movies.GetAllAsync();
    }

    public async Task CreateMovieAsync(Movie movie)
    {
        await _unitOfWork.Movies.AddAsync(movie);
        await _unitOfWork.SaveChangesAsync();
    }
}

Переваги впровадженої архітектури

  • Слабка зв’язаність — сервіси та контролери залежать лише від абстракцій (IUnitOfWork, IRepository<T>).
  • Єдиний контекст — патерн Unit of Work гарантує використання одного DbContext у межах одного HTTP-запиту.
  • Покращена тестованість — легко мокувати IUnitOfWork для написання юніт-тестів.
  • Масштабованість — зручна підготовка проєкту до трансформації в Web API та підключення SPA-фронтенду (React).
  • Відповідність найкращим практикам — чітке розділення шарів та використання класичних патернів Repository + Unit of Work.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment