Repository Pattern

Repository Pattern이란?

Repository Pattern은 데이터 액세스 계층의 추상화입니다. 기본 데이터 원본에서 데이터가 정확히 어떻게 저장되거나 검색되는지에 대한 세부 정보를 숨깁니다. 데이터 저장 및 검색 방법에 대한 세부 정보는 해당 저장소에 있습니다. 예를 들어 메모리 내 컬렉션에서 데이터를 저장하고 검색하는 Repository 가 있을 수 있습니다. SQL Server와 같은 데이터베이스에서 데이터를 저장하고 검색하는 다른 Repository 가 있을 수 있습니다. XML 파일에서 데이터를 저장하고 검색하는 또 다른 저장소입니다.

Repository Pattern Interface

Repository Pattern의 인터페이스는 다음을 지정합니다.

  • 리포지토리에서 지원하는 작업(예: 메서드)
  • 각 작업에 필요한 데이터, 즉 메서드에 전달해야 하는 매개변수와 메서드가 반환하는 데이터
  • 리포지토리 인터페이스에는 수행할 수 있는 작업은 포함되지만 수행 방법, 수행할 수 있는 작업은 포함되지 않습니다.
  • 구현 세부 사항은 리포지토리 인터페이스를 구현하는 각 리포지토리 클래스에 있습니다.
public interface IEmployeeRepository
{
    Task<IEnumerable<Employee>> GetEmployees();
    Task<Employee> GetEmployee(int employeeId);
    Task<Employee> AddEmployee(Employee employee);
    Task<Employee> UpdateEmployee(Employee employee);
    void DeleteEmployee(int employeeId);
}

IEmployeeRepository 인터페이스는 다음 작업을 지원합니다.

  • Get all the employees
  • Get a single employee by id
  • Add a new employee
  • Update an employee
  • Delete an employee

이러한 작업이 구현되는 방법에 대한 세부 정보는 이 IEmployeeRepository 인터페이스 를 구현하는 리포지토리 클래스에 있습니다 .

리포지토리 패턴 – SQL Server 구현

다음 EmployeeRepository 클래스는 IEmployeeRepository 에 대한 구현을 제공합니다 . 이 특정 구현은 SQL Server 데이터베이스에서 직원을 저장하고 검색합니다.

using EmployeeManagement.Models;
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace EmployeeManagement.Api.Models
{
    public class EmployeeRepository : IEmployeeRepository
    {
        private readonly AppDbContext appDbContext;

        public EmployeeRepository(AppDbContext appDbContext)
        {
            this.appDbContext = appDbContext;
        }

        public async Task<IEnumerable<Employee>> GetEmployees()
        {
            return await appDbContext.Employees.ToListAsync();
        }

        public async Task<Employee> GetEmployee(int employeeId)
        {
            return await appDbContext.Employees
                .FirstOrDefaultAsync(e => e.EmployeeId == employeeId);
        }

        public async Task<Employee> AddEmployee(Employee employee)
        {
            var result = await appDbContext.Employees.AddAsync(employee);
            await appDbContext.SaveChangesAsync();
            return result.Entity;
        }

        public async Task<Employee> UpdateEmployee(Employee employee)
        {
            var result = await appDbContext.Employees
                .FirstOrDefaultAsync(e => e.EmployeeId == employee.EmployeeId);

            if (result != null)
            {
                result.FirstName = employee.FirstName;
                result.LastName = employee.LastName;
                result.Email = employee.Email;
                result.DateOfBrith = employee.DateOfBrith;
                result.Gender = employee.Gender;
                result.DepartmentId = employee.DepartmentId;
                result.PhotoPath = employee.PhotoPath;

                await appDbContext.SaveChangesAsync();

                return result;
            }

            return null;
        }

        public async void DeleteEmployee(int employeeId)
        {
            var result = await appDbContext.Employees
                .FirstOrDefaultAsync(e => e.EmployeeId == employeeId);
            if (result != null)
            {
                appDbContext.Employees.Remove(result);
                await appDbContext.SaveChangesAsync();
            }
        }
    }
}

DepartmentRepository 인터페이스

public interface IDepartmentRepository
{
    IEnumerable<Department> GetDepartments();
    Department GetDepartment(int departmentId);
}

DepartmentRepository 구현

using EmployeeManagement.Models;
using System.Collections.Generic;
using System.Linq;

namespace EmployeeManagement.Api.Models
{
    public class DepartmentRepository : IDepartmentRepository
    {
        private readonly AppDbContext appDbContext;

        public DepartmentRepository(AppDbContext appDbContext)
        {
            this.appDbContext = appDbContext;
        }

        public Department GetDepartment(int departmentId)
        {
            return appDbContext.Departments
                .FirstOrDefault(d => d.DepartmentId == departmentId);
        }

        public IEnumerable<Department> GetDepartments()
        {
            return appDbContext.Departments;
        }
    }
}

사용하기 위한 정의

다음 두 줄의 코드를 사용하여 ASP.NET Core는 IEmployeeRepository 인스턴스가 요청될 때 EmployeeRepository 클래스 의 인스턴스를 제공합니다 . 마찬가지로 DepartmentRepository 클래스 의 인스턴스는 IDepartmentRepository 인스턴스가 요청될 때 제공됩니다.

public void ConfigureServices(IServiceCollection services)
{
    // Rest of the code
    services.AddScoped<IDepartmentRepository, DepartmentRepository>();
    services.AddScoped<IEmployeeRepository, EmployeeRepository>();
}

주어진 HTTP 요청의 전체 범위에서 인스턴스가 활성 상태이고 사용 가능하기를 원하기 때문에 AddScoped() 메서드를 사용하고 있습니다 . 또 다른 새 HTTP 요청의 경우 EmployeeRepository 클래스 의 새 인스턴스가 제공되며 해당 HTTP 요청의 전체 범위에서 사용할 수 있습니다.

전체 애플리케이션에서 IEmployeeRepository가 주입되는 모든 위치에서 EmployeeRepository 인스턴스가 제공됩니다. 애플리케이션이 대신 다른 구현을 사용하도록 하려면 다음 한 줄의 코드만 변경하면 됩니다.

services.AddScoped<IEmployeeRepository, EmployeeRepository>();

Repository Pattern 의 이점

  • 코드가 더 깨끗하고 재사용 및 유지 관리가 더 쉽습니다.
  • 느슨하게 결합된 시스템을 만들 수 있습니다. 예를 들어 애플리케이션이 SQL Server 대신 Oracle과 함께 작동하도록 하려면 Oracle 데이터베이스를 읽고 쓰는 방법을 알고 있는 OracleRepository를 구현하고 OracleRepository를 종속성 주입 시스템에 등록합니다.
  • 단위 테스트 프로젝트에서 테스트를 위해 실제 리포지토리를 가짜 구현으로 쉽게 교체할 수 있습니다.

답글 남기기