kh2*_*h25 10 .net c# linq entity-framework-4
我有一个问题,建立一个相当沉重的linq查询.基本上我有一种情况,我需要在循环中执行子查询以过滤从数据库返回的匹配数.示例代码在以下循环中:
foreach (Guid parent in parentAttributes)
{
var subQuery = from sc in db.tSearchIndexes
join a in db.tAttributes on sc.AttributeGUID equals a.GUID
join pc in db.tPeopleIndexes on a.GUID equals pc.AttributeGUID
where a.RelatedGUID == parent && userId == pc.CPSGUID
select sc.CPSGUID;
query = query.Where(x => subQuery.Contains(x.Id));
}
Run Code Online (Sandbox Code Playgroud)
当我随后在查询变量上调用ToList()时,似乎只执行了一个子查询,并且我留下了一大堆我不需要的数据.但是这种方法有效:
IList<Guid> temp = query.Select(x => x.Id).ToList();
foreach (Guid parent in parentAttributes)
{
var subQuery = from sc in db.tSearchIndexes
join a in db.tAttributes on sc.AttributeGUID equals a.GUID
join pc in db.tPeopleIndexes on a.GUID equals pc.AttributeGUID
where a.RelatedGUID == parent && userId == pc.CPSGUID
select sc.CPSGUID;
temp = temp.Intersect(subQuery).ToList();
}
query = query.Where(x => temp.Contains(x.Id));
Run Code Online (Sandbox Code Playgroud)
不幸的是,这种方法很糟糕,因为它导致对远程数据库的多个查询,如果我能使它工作的初始方法只会导致单次命中.有任何想法吗?
我认为你正在尝试捕获用于过滤的lambda表达式中的循环变量.也称为访问修改后的闭包错误.
试试这个:
foreach (Guid parentLoop in parentAttributes)
{
var parent = parentLoop;
var subQuery = from sc in db.tSearchIndexes
join a in db.tAttributes on sc.AttributeGUID equals a.GUID
join pc in db.tPeopleIndexes on a.GUID equals pc.AttributeGUID
where a.RelatedGUID == parent && userId == pc.CPSGUID
select sc.CPSGUID;
query = query.Where(x => subQuery.Contains(x.Id));
}
Run Code Online (Sandbox Code Playgroud)
问题是捕获parent闭包中的变量(将LINQ语法转换为),这会导致所有subQueryes以相同的父ID运行.
发生的事情是编译器生成一个类来保存委托和委托访问的局部变量.编译器为每个循环重用该类的相同实例; 因此,一旦查询执行,所有的Wheres都使用相同的parentGuid 执行,即最后执行.
声明parent循环范围内部会导致编译器基本上复制具有正确值的变量.
起初这可能有点难以掌握,所以如果这是第一次击中你; 我推荐这两篇文章作为背景和详尽的解释: