1

私は通常、汎用リポジトリを使用してEFクエリを定型化するため、限られたコードを記述し、キャッシュも使用する必要があります。リポジトリのソースコードはここにあります。

コード内のバックボーンクエリは、以下のクエリです。FromCache<T>()は、ラムダ式の文字列化された表現をキーとして使用してクエリを格納するためにIEnumerable<T>を利用する拡張メソッドです。HttpContext.Cache

    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()キャッシュするためにすでに実行されているため、クエリには影響しません。

これで、ナビゲーションプロパティの仮想プレフィックスを削除することで、Entity Frameworkにモデル内での積極的な読み込みを強制できることがわかりましたが、実行するクエリの種類を予測できないため、それを行うのは間違った場所のように感じます。私には、コントローラークラスでやっていることのように感じます。私が疑問に思っているのは、インクルードのリストをAny<T>()メソッドに渡して、呼び出しを行うときに反復できるかどうかです。

4

2 に答える 2

1

ofあなたは次のような意味でしたか...

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);

以前と同じように機能しました。

于 2013-02-18T12:18:28.147 に答える
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);
于 2013-02-19T12:12:26.157 に答える