Кэширование результатов с помощью Massive micro-ORM

Я использую Massive micro-ORM в новом проекте. Я добавил немного кэширования, и все, казалось, работало, пока я не понял, что кэшированные объекты (динамические) все еще запрашивают базу данных. Это убивает весь смысл кэширования.

Какой самый простой способ отключить результирующий набор от базы данных. Почти все вызовы доступны только для чтения.

Я использую такой код для запроса записей:

public static dynamic GetActive()
{
    return Caching.LoadFromCache("Units_GetActive", 120,
        () =>
        {
            dynamic tbl = new Units();
            return tbl.Find(Enabled: 1, orderby: "SortOrder");
        });
}

Мой код кэширования выглядит так:

public static dynamic LoadFromCache(string cacheKey, int secondsToCache, Func<object> query)
{
    object tocache = null;

    // result will always get the value here
    // tocache will only have the value when it was pulled from our method
    object result = MemoryCache.Default[cacheKey] ?? (tocache = query.Invoke());

    if (secondsToCache > 0)
    {
        if (tocache != null) // only save to cache if it wasn't there
            MemoryCache.Default.Add(cacheKey, tocache, DateTime.UtcNow.AddSeconds(secondsToCache));
    }
    else
    {
        // remove from cache only if secondsToCache was zero or less
        MemoryCache.Default.Remove(cacheKey);
    }

    return result;
}

Код кэширования работает. Проблема в том, что возвращенный динамический объект (IEnumerable<dynamic>) открывает другое соединение с базой данных.

Идеи?


person David Crowell    schedule 09.05.2014    source источник
comment
Предположение (не знакомое с этим конкретным ORM): поместите результаты перечислителя в список (вызовите ToList()), чтобы он не пересчитывался каждый раз, когда он используется.   -  person Tim Medora    schedule 09.05.2014


Ответы (1)


У Тима Медоры была правильная идея.

Я изменил свой код кэширования на это:

public static dynamic LoadFromCache(string cacheKey, int secondsToCache, Func<object> query)
{
    object tocache = null;

    // result will always get the value here
    // tocache will only have the value when it was pulled from our method
    object result = MemoryCache.Default[cacheKey] ?? (tocache = query.Invoke());

    if (secondsToCache > 0)
    {
        // If this came from Massive, we need to get the list instead of opening a 
        // database connection each time we enumerate.  I check the type, because other things
        // are stored.
        if (tocache is IEnumerable<dynamic>)
        {
            tocache = ((IEnumerable<dynamic>)tocache).ToList<dynamic>();
            result = tocache;
        }

        if (tocache != null) // only save to cache if it wasn't there
            MemoryCache.Default.Add(cacheKey, tocache, DateTime.UtcNow.AddSeconds(secondsToCache));
    }
    else
    {
        // remove from cache only if secondsToCache was zero or less
        MemoryCache.Default.Remove(cacheKey);
    }

    return result;
}

ToList<dynamic>() была ключевой частью. Кажется, теперь он работает так, как ожидалось. ToList<T> — это метод расширения в пространстве имен System.Linq.

person David Crowell    schedule 09.05.2014
comment
НЕТ ! Вы загромождаете свой объект кеша замаскированной логикой БД. Преобразуйте его в список в своем коде доступа к данным, прежде чем помещать результаты в кеш. Просто поставить .ToList() в конце лямбды? - person bbsimonbb; 06.06.2016