我通常使用通用存储库来编写我的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()
对我的查询没有任何影响,因为它已经被运行以便进行缓存。
现在我知道我可以通过删除导航属性上的虚拟前缀来强制Entity Framework在我的模型中使用急切加载,但这对我来说感觉就像是错误的地方,因为你无法预测查询类型正在制作。对我来说,感觉就像我将在控制器类中做的事情。我想知道的是,我是否可以将包含列表传递给我的Any<T>()
方法,然后我可以在拨打电话时进行迭代?
答案 0 :(得分: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);
像以前一样工作。
答案 1 :(得分: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);