2011-01-30 34 views
2

我一直在與彼得蒙哥馬利的試驗「緩存LINQ查詢的結果」源上市here從緩存列表查詢的IQUERY返回null例外

這創造了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,因爲一些產品返回null爲屬性Color。如果我查詢沒有緩存的實體,那就沒有問題了。

任何人都可以解釋爲什麼發生這種情況,我該如何解決這個問題?

非常感謝。

更新:自從我發現使用==解決了我的問題,但我不知道爲什麼。我希望能夠使用Equals()。

回答

2

當你x.Color.Equals("Black", StringComparison.InvariantCultureIgnoreCase)和顏色是你會得到空例外,更好的辦法是使用靜態字符串的方法,將工作,即使參數是,這樣的:

String.Equals(x.Color, "Black", StringComparison.InvariantCultureIgnoreCase) 
+0

@ķ伊萬諾夫:謝謝你的解釋。我不能接受你的答案的唯一原因是你被打了一段時間。儘管我已經投了票。 – 2011-01-30 19:00:34

+0

thx,雖然我的回答是在你選擇的那個之前4分鐘,但這不是什麼大問題 – 2011-01-30 19:04:35

2

您需要使用特定ORM技術的LINQ提供程序來將您的查詢轉換爲適當的SQL。 EF(或L2S)提供程序知道如何將x.Color.Equals("Black", ...)轉換爲適當的SQL。但是,當您緩存這些摘要時(通過調用ToList()),您切換到LINQ to Objects,然後開始應用C#的所有規則:您無法在對象的null實例上調用實例方法。

你可以嘗試切換左右吧:x=>"Black".Equals(x.Color)(希望的LINQ到EF供應商將明白爲好,雖然我現在不能測試它,所以你必須自己嘗試一下)