Repository Pattern이란?
데이터, 도메인, Data Access Layers(Entity Framework Core 또는 Dapper)사이의 중재 역할을 한다.
데이터를 저장 또는 가져오는데 필요한 로직을 갖는 클래스이다.
Repository Pattern의 장점
중복 쿼리 감소
Repository에 data access code를 작성하고, 여러개의 Controllers/Libraries에서 호출해서 사용할 수 있다.
Data Access Layer로부터 Application의 De-couples
ASP.NET Core에는 다양한 ORM이 유효하다. 현재 가장 유명한 것은 Entity Framework Core이다. 하지만 시간이 지나면서 새로운 기술이 발전함에 따라 새로운 ORM을 사용해야 할 수도 있다.
또는 여러개의 ORM을 하나의 프로젝트에 사용할 수도 있다. 앱의 퍼포먼스 최적화를 위해 Dapper는 data를 가져오기 위해 사용하고, EFCore는 data를 저장하기 위해 사용할 수 있다.
Repository Pattern은 DataAccess Layer를 추상화한다. 앱은 더이상 어떠한 ORM에도 종속되지 않으며 EFCore는 그 중 하나의 옵션이다.
Generic Repository
CRUD 동작은 entity만 다를뿐이지 계속 반복되는 동작이다. 따라서 Generic을 사용하여 어떠한 Entity Repository에서도 사용할 수 있는 Base Repository를 만들자.
IRepoBase.cs
using System.Linq.Expressions;
namespace SampleProject.Data
{
public interface IRepoBase<T>
{
IQueryable<T> FindAll();
IQueryable<T> FindByCondition(Expression<Func<T, bool>> expression);
T GetById(int id);
void Create(T entity);
void Update(T entity);
void Delete(T entity);
}
}
RepoBase.cs
using Microsoft.EntityFrameworkCore;
using System.Linq.Expressions;
namespace SampleProject.Data
{
public abstract class RepoBase<T> : IRepoBase<T> where T : class
{
protected AppDbContext _context { get; set; }
public RepoBase(AppDbContext context)
{
_context = context;
}
public IQueryable<T> FindAll() => _context.Set<T>().AsNoTracking();
public IQueryable<T> FindByCondition(Expression<Func<T, bool>> expression) =>
_context.Set<T>().Where(expression).AsNoTracking();
public T GetById(int id) => _context.Set<T>().Find(id);
public void Create(T entity) => _context.Set<T>().Add(entity);
public void Update(T entity) => _context.Set<T>().Update(entity);
public void Delete(T entity) => _context.Set<T>().Remove(entity);
}
}
Generic Repository 상속과 확장
이제 Entity Repository에서 RepoBase<T> abstract class를 상속받아서 사용해보자.
IUserRepo.cs
using SampleProject.Models;
namespace SampleProject.Data
{
public interface IUserRepo : IRepoBase<User>
{
bool SaveChanges();
IEnumerable<User> GetAllUsers();
User GetUserById(string id);
}
}
UserRepo.cs
using SampleProject.Models;
namespace SampleProject.Data
{
public class UserRepo : RepoBase<User>, IUserRepo
{
private readonly AppDbContext _context;
public UserRepo(AppDbContext context) : base(context)
{
_context = context;
}
public IEnumerable<User> GetAllUsers()
{
return FindAll().ToList();
}
public User GetUserById(string id)
{
return FindByCondition(owner => owner.EmpId.Equals(id)).FirstOrDefault();
}
public bool SaveChanges()
{
return (_context.SaveChanges() >= 0);
}
}
}
Program.cs
builder.Services.AddScoped<IUserRepo, UserRepo>();
Controller에서 사용
using Microsoft.AspNetCore.Mvc;
using SampleProject.Data;
using SampleProject.Models;
using System.Diagnostics;
namespace SampleProject.Controllers
{
public class HomeController : Controller
{
private readonly IUserRepo _repository;
private readonly ILogger<HomeController> _logger;
public HomeController(IUserRepo repository, ILogger<HomeController> logger)
{
_repository = repository;
_logger = logger;
}
public IActionResult Index()
{
var users = _repository.GetAllUsers();
return View(users);
}
}
}
'Software design pattern' 카테고리의 다른 글
C#] Observer Design Pattern(관찰자 디자인 패턴) (1) | 2024.01.10 |
---|---|
C#] Pipes and Filter Architectural Pattern (0) | 2024.01.09 |
C#] Strangler Fig Pattern 스트랭글러 패턴 설명과 데모 (0) | 2023.11.02 |
댓글