1

我通常使用通用存储库来样板化我的 EF 查询,因此我必须编写有限的代码并使用缓存。可以在此处找到存储库的源代码。

代码中的主干查询是下面的这个。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>()方法中,然后我可以在调用时进行迭代?

4

2 回答 2

1

你的意思是...

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

回答关于收藏的额外问题。

我很晚才意识到,Property 过载了。你可以只传递一个字符串

这可能有效,但调用并不容易。嗯,我觉得很难。

   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 回答