Запрос IQuery из кэшированного списка возвращает нулевое исключение - PullRequest
2 голосов
/ 30 января 2011

Я экспериментировал с источником Питера Монтгомери "Кэширование результатов запросов 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 ().

Ответы [ 2 ]

2 голосов
/ 30 января 2011

Это зависит от поставщика LINQ для конкретной технологии ORM, которую вы используете для перевода ваших запросов в соответствующий SQL.Поставщик EF (или L2S) знает, как перевести x.Color.Equals("Black", ...) в соответствующий SQL.Однако, когда вы кэшируете результаты (вызывая ToList()), вы переключаетесь на LINQ to Objects, а затем начинают применяться все правила C #: вы не можете вызвать метод экземпляра для нулевого экземпляра объекта.*

Вы могли бы попробовать переключить это: x=>"Black".Equals(x.Color) (надеюсь, поставщик LINQ to EF также поймет это, хотя я не могу проверить это прямо сейчас, поэтому вам придется попробовать это самостоятельно)

2 голосов
/ 30 января 2011

когда вы делаете x.Color.Equals("Black", StringComparison.InvariantCultureIgnoreCase) и цвет равен null , вы получите исключение NULL, лучше использовать метод статической строки, который будет работать, даже если параметры NULL вот так:

String.Equals(x.Color, "Black", StringComparison.InvariantCultureIgnoreCase)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...