Linq多个查询位置

时间:2012-03-12 18:51:34

标签: c# .net 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));
         }

当我随后在查询变量上调用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));

不幸的是,这种方法很糟糕,因为它会导致对远程数据库的多次查询,如果我能让它工作的初始方法只会导致单次命中。有什么想法吗?

2 个答案:

答案 0 :(得分:8)

我认为你正在尝试捕获用于过滤的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));
     }

问题是捕获闭包中的parent变量(LINQ语法转换为),这会导致所有subQuery es以相同的父ID运行。

编译器生成一个类来保存委托和委托访问的局部变量。编译器为每个循环重用该类的相同实例;因此,一旦查询执行,所有Where s都使用相同的parent Guid执行,即最后执行。

在循环范围内声明parent会导致编译器基本上复制具有正确值的变量。

一开始可能有点难以理解,所以如果这是第一次击中你;我推荐这两篇文章作为背景和详尽的解释:

答案 1 :(得分:0)

也许这样?

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 parentAttributes.Contains(a.RelatedGUID) && userId == pc.CPSGUID                             
               select sc.CPSGUID;