Я экспериментировал с источником Питера Монтгомери "Кэширование результатов запросов LINQ", перечисленным здесь
, который создает метод расширения для IQueryable<T>
, возвращающий IEnumerable<T>
из кэшированногоданные, если это возможно.Основной метод расширения выглядит следующим образом.
/// <summary>
/// Returns the result of the query; if possible from the cache, otherwise
/// the query is materialized and the result cached before being returned.
/// </summary>
/// <param name="query">The IQueryable for which to return the query.</param>
/// <param name="priority">The relative cache priority of the object.</param>
/// <param name="slidingExpiration">The timespan indicating the duration of the sliding expiration</param>
/// <returns>The result of the query; if possible from the cache</returns>
/// <typeparam name="T">The type of entity for which to provide the method.</typeparam>
public static IEnumerable<T> FromCache<T>(this IQueryable<T> query, CacheItemPriority priority, TimeSpan slidingExpiration)
{
string key = query.GetCacheKey();
// try to get the query result from the cache
var result = HttpRuntime.Cache.Get(key) as List<T>;
if (result == null)
{
// TODO: ... ensure that the query results do not
// hold on to resources for your particular data source
//
//////// for entity framework queries, set to NoTracking
//////var entityQuery = query as ObjectQuery<T>;
//////if (entityQuery != null)
//////{
////// entityQuery.MergeOption = MergeOption.NoTracking;
//////}
// materialize the query
result = query.ToList();
HttpRuntime.Cache.Insert(
key,
result,
null, // no cache dependency
Cache.NoAbsoluteExpiration,
slidingExpiration,
priority,
null); // no removal notification
}
return result;
}
Я использую этот метод следующим образом:
/// <summary>
/// Retrieves all instances of the specified type, if possible from the cache.
/// Objects are maintained in a <see cref="T:System.Data.EntityState.Detached">Detached</see> state and
/// are not tracked in the <see cref="T:System.Data.Objects.ObjectStateManager">ObjectStateManager</see>.
/// </summary>
/// <returns>A list of all instances of the specified type.</returns>
/// <typeparam name="T">The type of entity for which to provide the method.</typeparam>
public IQueryable<T> All<T>() where T : class, new()
{
//return new ObjectQuery<T>(GetSetName<T>(), this.context, MergeOption.NoTracking);
return new ObjectQuery<T>(GetSetName<T>(), this.context, MergeOption.NoTracking).FromCache<T>().AsQueryable<T>();
}
Затем я бы отфильтровал свои запросы следующим образом (Запрос образца базы данных AdventureWorks):
List<Product> products = new List<Product>(readonlySession.All<Product>()
.Where(x => x.Color.Equals("Black", StringComparison.InvariantCultureIgnoreCase)));
Моя проблема в том, что когда я пытаюсь запросить данные, подобные этим, я получаю NullReferenceException
, так как некоторые продукты возвращают нуль для свойства Color
.Если я запрашиваю объект без кэша, проблема не возникает.
Может кто-нибудь объяснить, почему это происходит и как я могу решить эту проблему?
Большое спасибо.
ОБНОВЛЕНИЕ: С тех пор я обнаружил, что использование == решает мою проблему, хотя я не знаю почему.Я хотел бы иметь возможность использовать Equals ().