모델을 캐시하는 더 나은 방법

asp.net asp.net-mvc asp.net-mvc-5 dapper

문제

내 간단한 저장소의 getAll 메소드 :

    public List<ListModel> GetAllLists()
    {
            using (MySqlConnection connection = new MySqlConnection(this.connectionString))
            {
                return connection.Query<ListModel>("SELECT * FROM projectx.lists").AsList();
            }

    }

캐싱을 처리하기 위해 여기에서 찾은 클래스를 사용하고 있습니다.

    public class CacheUtils : ICacheService
    {    
        public TValue Get<TValue>(string cacheKey, Func<TValue> getItemCallback, double durationInMinutes = 120) where TValue : class
        {

            TValue item = MemoryCache.Default.Get(cacheKey) as TValue;
            if (item == null)
            {
                Debug.WriteLine("Not cached");
                item = getItemCallback();
                MemoryCache.Default.Add(cacheKey, item, DateTime.Now.AddMinutes(durationInMinutes));
            }
            else
                Debug.WriteLine("Cached!");
            return item;
        }

        public TValue Get<TValue, TId>(string cacheKeyFormat, TId id, Func<TId, TValue> getItemCallback, double durationInMinutes = 120) where TValue : class
        {

            string cacheKey = string.Format(cacheKeyFormat, id);
            TValue item = MemoryCache.Default.Get(cacheKey) as TValue;
            if (item == null)
            {

                item = getItemCallback(id);
                MemoryCache.Default.Add(cacheKey, item, DateTime.Now.AddMinutes(durationInMinutes));
            }


            return item;
        }
    }

홈 컨트롤러 :

    public ActionResult Index()
    {
        ListRepository listRep = new ListRepository();
        CacheUtils cache = new CacheUtils();
        return View(cache.Get("lists", listRep.GetAllLists));
    }

질문, 컨트롤러에서 도우미를 호출하는 것보다 캐시를 ​​처리하는 더 좋은 방법이 있습니까? 이상적으로는 저장소 메소드 내부에 있어야합니다. 하지만 저장소의 모든 단일 메소드에서 기존 캐시 데이터에 대한 점검을 반복해야합니까? 즉 :

    public List<ListModel> GetAllLists()
    {
        var lists = Cache["lists"];
        if(lists == null)
        {
            using (MySqlConnection connection = new MySqlConnection(this.connectionString))
            {
                lists = connection.Query<ListModel>("SELECT * FROM projectx.lists").AsList();
            }

            Cache["lists"] = lists;
        }
        return ((List<ListModel>)lists);
    }

수락 된 답변

데코레이터 패턴을 사용하고 캐싱 로직으로 비즈니스 또는 UI를 분류하지 마십시오. 당신이 DI를 추가하고 싶지 않으면 ninject (또는 불쌍한 나쁜 놈들)와 같은 것을 연결하십시오. 나는 그것을 하나의 인스턴스로 표시 할 것을 권한다.

이점은 다음과 같습니다.

  • void Save (ListModel)와 같은 무효화 메소드를 추가하면 캐시를 무효화하기 쉽습니다.
  • 상위 레이어와 하위 레이어는 캐시 된 사실에 대해 아무 것도 모릅니다.
  • 로깅, 프로파일 링 등을 추가하기 위해 다시 장식 할 수도 있습니다.
  • 캐싱 수명주기를 제어 할 수도 있습니다.
  • 당신은 캐싱 로직으로 컨트롤러 레벨을 폴 루팅하지 않는다.
  • 제거하기 쉽다.

그래서 아래처럼 뭔가 작동합니다. ninject에 데코레이터를 추가하는 방법은 https://stackoverflow.com/a/8910599/1073280을 참조 하십시오.

public class MyHomeController
{
    private readonly IListCrud _listcrud;

    public MyHomeController(IListCrud listcrud)
    {
        _listcrud = listcrud;
    }

    public ActionResult Index()
    {
        return View(_listcrud.GetAllLists());
    }
}

public interface IListCrud
{
    List<ListModel> GetAllLists();
}

public class ListCrud : IListCrud
{
    public List<ListModel> GetAllLists()
    {
        using (MySqlConnection connection = new MySqlConnection(this.connectionString))
        {
            return connection.Query<ListModel>("SELECT * FROM projectx.lists").AsList();
        }
    }
}

public class ListCrudCache : IListCrud
{
    private readonly ICacheService _cache;
    private readonly IListCrud _inner;

    public ListCrudCache(ICacheService cache, IListCrud inner)
    {
        _cache = cache;
        _inner = inner;
    }

    public List<ListModel> GetAllLists()
    {
        return _cache.Get("lists", _inner.GetAllLists);
    }
}

오피니언 : 코드를 작게 유지하면서 ORM과 함께 select *를 사용할 때는주의해야합니다. 누군가 열의 이름을 변경하거나 제거하면 단위 테스트 / 결함 감지 메커니즘이 쉽지 않습니다.


인기 답변

제 의견으로는 저에게 저장소 나 SRP와 같은 냄새가 있어서는 안됩니다. 캐싱은 저장소보다 상위 수준의 서비스 여야합니다.

실제로 캐싱의 이점이 필요한 것이 무엇인지 생각해야합니다. 캐싱이 WEB API 인터페이스 속도를 높이기위한 것이라면, 컨트롤러에서 사용하는 것이 가장 좋은 방법입니다. 어딘가에 캐싱이 필요한 경우 중간 계층 서비스 클래스를 도입하고 캐싱을 고려해보십시오. 그러나 나는 항상 어떤 방식 으로든 선택적으로 만들 것입니다.



아래 라이선스: CC-BY-SA with attribution
와 제휴하지 않음 Stack Overflow
이 KB는 합법적입니까? 예, 이유를 알아보십시오.
아래 라이선스: CC-BY-SA with attribution
와 제휴하지 않음 Stack Overflow
이 KB는 합법적입니까? 예, 이유를 알아보십시오.