이 섹션에서는 앞서 정의한 IPlantRepository 인터페이스를 구현하는 과정을 배웁니다. 
Repository 패턴을 사용하여 데이터 액세스 로직을 캡슐화하고, 애플리케이션의 나머지 부분과 데이터베이스 간의 결합도를 낮춥니다.
- CRUD 메서드 구현:
Create: 비동기적으로 Plant 객체를 데이터베이스에 추가하고 변경 사항을 저장합니다.Remove: 주어진 Plant 객체를 데이터베이스에서 삭제하고 변경 사항을 저장합니다.Save: 비동기적으로 모든 변경 사항을 데이터베이스에 저장합니다.GetAll: 주어진 조건에 따라 모든 Plant 객체를 검색하거나, 조건이 없으면 모든 객체를 검색합니다. 필터링은 LINQ 표현식을 사용하여 수행됩니다.Get: 주어진 조건에 따라 단일 Plant 객체를 검색합니다.tracked매개변수를 사용하여 Entity Framework Core의 추적 기능을 활성화하거나 비활성화할 수 있습니다.
 - 조건부 필터링 및 추적 제어: 
GetAll과Get메서드에서는 LINQ 표현식을 사용하여 동적으로 데이터를 필터링할 수 있습니다. 또한,AsNoTracking메서드를 사용하여 필요에 따라 데이터 추적을 비활성화할 수 있습니다. - 비동기 프로그래밍: 모든 데이터 액세스 메서드는 비동기적으로 구현되어 있어, 데이터베이스 작업 중에 애플리케이션의 응답성을 유지할 수 있습니다.
 - Repository 등록: 
Program.cs파일에서IPlantRepository인터페이스와 그 구현체인PlantRepository클래스를 서비스 컨테이너에 등록합니다. 이를 통해 API 컨트롤러에서IPlantRepository를 주입받아 사용할 수 있게 됩니다. - Plant API 컨트롤러 수정:
ApplicationDbContext대신IPlantRepository를 주입받아 사용합니다.CRUD 작업을 위해 Repository의 메서드(CreateAsync,GetAsync,GetAllAsync,UpdateAsync,RemoveAsync)를 호출합니다.비동기 메서드를 사용하여 데이터베이스 작업을 처리합니다. 이는 애플리케이션의 응답성을 향상시키고, 리소스 사용을 최적화합니다.
 - 비동기 메서드 적용: 모든 데이터베이스 작업을 비동기적으로 수행합니다. 
await키워드를 사용하여 비동기 작업을 기다리고, 메서드 시그니처에async와Task를 추가하여 비동기 메서드로 변환합니다.Comment - 조건부 데이터 검색: 
GetAsync와GetAllAsync메서드에서는 LINQ 표현식을 사용하여 동적으로 데이터를 필터링합니다. 이를 통해 유연하게 데이터를 조회할 수 있습니다. - 추적 제어: 
GetAsync메서드에서tracked매개변수를 사용하여 Entity Framework Core의 변경 추적 기능을 제어합니다. 필요에 따라 데이터 조회 시 변경 추적을 비활성화하여 성능을 최적화할 수 있습니다.Comment - 테스트 및 검증: 수정된 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 패턴의 적용은 애플리케이션의 데이터 액세스 로직을 추상화하고, 컨트롤러와 데이터베이스 간의 결합도를 낮추어 애플리케이션의 아키텍처를 개선합니다. 비동기 프로그래밍 모델을 사용함으로써 데이터베이스 작업의 효율성과 애플리케이션의 응답성을 더욱 향상시킬 수 있습니다.