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를 종속성 주입 시스템에 등록합니다.
- 단위 테스트 프로젝트에서 테스트를 위해 실제 리포지토리를 가짜 구현으로 쉽게 교체할 수 있습니다.