2013-02-18 123 views
1

我通常使用通用資源庫對我的EF查詢進行樣板化,因此我必須編寫有限的代碼並使用緩存。存儲庫的源代碼可以在here找到。組合包含實體框架

代碼中的骨幹查詢是下面這個。 FromCache<T>()是一個IEnumerable<T>擴展方法,它利用HttpContext.Cache以lambda表達式的字符串化表示形式作爲關鍵字來存儲查詢。

public IQueryable<T> Any<T>(Expression<Func<T, bool>> expression = null) 
    where T : class, new() 
    { 
     // Check for a filtering expression and pull all if not. 
     if (expression == null) 
     { 
      return this.context.Set<T>() 
         .AsNoTracking() 
         .FromCache<T>(null) 
         .AsQueryable(); 
     } 

     return this.context.Set<T>() 
          .AsNoTracking<T>() 
          .Where<T>(expression) 
          .FromCache<T>(expression) 
          .AsQueryable<T>(); 
    } 

雖然這一切工作是受N + 1問題的相關表,因爲如果我是寫像這樣的查詢:

var posts = this.ReadOnlySession.Any<Post>(p => p.IsDeleted == false) 
           .Include(p => p.Author); 

Include()會對我的查詢無影響因爲它已經被運行以便被緩存。

現在我知道我可以強制實體框架使用我的模型中的加載加載,通過刪除我的導航屬性上的虛擬前綴,但對我來說,感覺就像錯誤的地方去做,因爲你無法預測你的查詢類型將會製作。對我來說,感覺就像我會在控制器課上做的一樣。我想知道的是,我是否可以將我的Any<T>()方法中的包含列表傳遞給我,然後我可以在我撥打電話時進行迭代?

回答

1

ofDid你的意思是這樣......

IQueryable<T> AnyWithInclude<T,I>(Expression<Func<T,bool>> predicate, 
            Expression<Func<T,I>> includeInfo) 
{ 
    return DbSet<T>.where(predicate).include(includeInfo); 
} 

通話

Context.YourDbSetReference.AnyWithInclude(t => t.Id==someId, i => i.someNavProp); 

在回答問題外作爲收藏。

我意識到很晚,物業上出現了超負荷現象。你可以通過一個字符串

這可能會工作,但呼叫並不容易。好吧,我覺得很難。

IQueryable<T> GetListWithInclude<I>(Expression<Func<T, bool>> predicate, 
             params Expression<Func<T, I>>[] IncludeCollection); 

所以我嘗試

public virtual IQueryable<T> GetListWithInclude(Expression<Func<T, bool>> predicate, 
               List<string> includeCollection) 
    { var result = EntityDbSet.Where(predicate); 
     foreach (var incl in includeCollection) 
     { 
      result = result.Include(incl); 
     } 
     return result; 
    } 

,並呼籲與

var ic = new List<string>(); 
ic.Add("Membership"); 
var res = context.DbSte<T>.GetListWithInclude(t=>t.UserName =="fred", ic); 

像以前一樣工作。

+0

太棒了!這看起來就像我正在尋找的那樣。謝謝! – 2013-02-18 12:32:08

+0

順便說一句我用類似的投影;-) – 2013-02-18 12:36:00

+0

你可能擴大你的答案更接近我目前使用的方法?我迷失了一些翻譯。也可以通過一系列包含作爲參數嗎? – 2013-02-18 13:07:55

0

爲了清晰起見,我添加了基於@ soadyp的答案的解決方案。

public IQueryable<T> Any<T>(Expression<Func<T, bool>> expression = null, 
         params Expression<Func<T, object>>[] includeCollection) 
    where T : class, new() 
{ 
    IQueryable<T> query = this.context.Set<T>().AsNoTracking().AsQueryable<T>(); 

    if (includeCollection.Any()) 
    { 
     query = includeCollection.Aggregate(query, 
        (current, include) => current.Include(include)); 
    } 

    // Check for a filtering expression and pull all if not. 
    if (expression != null) 
    { 
     query = query.Where<T>(expression); 
    } 

    return query.FromCache<T>(expression, includeCollection) 
       .AsQueryable<T>(); 
} 

用法:

// The second, third, fourth etc parameters are the strongly typed includes. 
var posts = this.ReadOnlySession.Any<Post>(p => p.IsDeleted == false, 
              p => p.Author);