5. DTO와 AutoMapper 그리고 Repository

5-5. Plant 저장소 구현

이 섹션에서는 앞서 정의한 IPlantRepository 인터페이스를 구현하는 과정을 배웁니다.

Repository 패턴을 사용하여 데이터 액세스 로직을 캡슐화하고, 애플리케이션의 나머지 부분과 데이터베이스 간의 결합도를 낮춥니다.

  1. CRUD 메서드 구현:
    • Create: 비동기적으로 Plant 객체를 데이터베이스에 추가하고 변경 사항을 저장합니다.Remove: 주어진 Plant 객체를 데이터베이스에서 삭제하고 변경 사항을 저장합니다.Save: 비동기적으로 모든 변경 사항을 데이터베이스에 저장합니다.GetAll: 주어진 조건에 따라 모든 Plant 객체를 검색하거나, 조건이 없으면 모든 객체를 검색합니다. 필터링은 LINQ 표현식을 사용하여 수행됩니다.Get: 주어진 조건에 따라 단일 Plant 객체를 검색합니다. tracked 매개변수를 사용하여 Entity Framework Core의 추적 기능을 활성화하거나 비활성화할 수 있습니다.
  2. 조건부 필터링 및 추적 제어: GetAllGet 메서드에서는 LINQ 표현식을 사용하여 동적으로 데이터를 필터링할 수 있습니다. 또한, AsNoTracking 메서드를 사용하여 필요에 따라 데이터 추적을 비활성화할 수 있습니다.
  3. 비동기 프로그래밍: 모든 데이터 액세스 메서드는 비동기적으로 구현되어 있어, 데이터베이스 작업 중에 애플리케이션의 응답성을 유지할 수 있습니다.
  4. Repository 등록: Program.cs 파일에서 IPlantRepository 인터페이스와 그 구현체인 PlantRepository 클래스를 서비스 컨테이너에 등록합니다. 이를 통해 API 컨트롤러에서 IPlantRepository를 주입받아 사용할 수 있게 됩니다.
  5. Plant API 컨트롤러 수정:
    • ApplicationDbContext 대신 IPlantRepository를 주입받아 사용합니다.CRUD 작업을 위해 Repository의 메서드(CreateAsync, GetAsync, GetAllAsync, UpdateAsync, RemoveAsync)를 호출합니다.비동기 메서드를 사용하여 데이터베이스 작업을 처리합니다. 이는 애플리케이션의 응답성을 향상시키고, 리소스 사용을 최적화합니다.
  6. 비동기 메서드 적용: 모든 데이터베이스 작업을 비동기적으로 수행합니다. await 키워드를 사용하여 비동기 작업을 기다리고, 메서드 시그니처에 asyncTask를 추가하여 비동기 메서드로 변환합니다.Comment
  7. 조건부 데이터 검색: GetAsyncGetAllAsync 메서드에서는 LINQ 표현식을 사용하여 동적으로 데이터를 필터링합니다. 이를 통해 유연하게 데이터를 조회할 수 있습니다.
  8. 추적 제어: GetAsync 메서드에서 tracked 매개변수를 사용하여 Entity Framework Core변경 추적 기능을 제어합니다. 필요에 따라 데이터 조회 시 변경 추적을 비활성화하여 성능을 최적화할 수 있습니다.Comment
  9. 테스트 및 검증: 수정된 API 컨트롤러의 모든 CRUD 작업을 테스트하여 Repository 패턴의 적용이 정상적으로 이루어졌는지 확인합니다.
// PlantRepository.cs
public class PlantRepository : IPlantRepository
{
    private readonly ApplicationDbContext _db;
    public PlantRepository(ApplicationDbContext db)
    {
        _db = db;
    }
​
    public async Task Create(Plant entity)
    {
        await _db.Plants.AddAsync(entity);
        await Save();
    }
​
    public async Task<Plant> Get(Expression<Func<Plant, bool>> filter = null, bool tracked = true)
    {
        IQueryable<Plant> query = _db.Plants;
        if (!tracked)
        {
            query = query.AsNoTracking();
        }
        if (filter != null)
        {
            query = query.Where(filter);
        }
        return await query.FirstOrDefaultAsync();
    }
​
    public async Task<List<Plant>> GetAll(Expression<Func<Plant, bool>> filter = null)
    {
        IQueryable<Plant> query = _db.Plants;
​
        if (filter != null)
        {
            query = query.Where(filter);
        }
        return await query.ToListAsync();
    }
​
    public async Task Remove(Plant entity)
    {
        _db.Plants.Remove(entity);
        await Save();
    }
​
    public async Task Save()
    {
        await _db.SaveChangesAsync();
    }
}

// Program.cs
builder.Services.AddScoped<IPlantRepository, PlantRepository>();

Repository 패턴의 적용은 애플리케이션의 데이터 액세스 로직을 추상화하고, 컨트롤러와 데이터베이스 간의 결합도를 낮추어 애플리케이션의 아키텍처를 개선합니다. 비동기 프로그래밍 모델을 사용함으로써 데이터베이스 작업의 효율성과 애플리케이션의 응답성을 더욱 향상시킬 수 있습니다.