Linq несколько где запросы - PullRequest
10 голосов
/ 12 марта 2012

У меня проблема с созданием довольно здоровенного запроса 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 ]

8 голосов
/ 12 марта 2012

Я думаю, что вы попали в особый случай захвата переменной цикла в лямбда-выражении, используемом для фильтрации.Также известен как доступ к измененной ошибке закрытия.

Попробуйте это:

   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 с одним и тем же родительским идентификатором.

В результате компилятор создает класс для хранения делегата и локальных переменных, к которым обращается делегат.Компилятор повторно использует один и тот же экземпляр этого класса для каждого цикла;и поэтому, как только запрос выполняется, все Where s выполняются с тем же parent Guid, а именно последним, чтобы выполнить.

Объявление parent внутри области видимости цикла приводит к тому, что компилятор по существусделайте копию переменной с правильным значением для захвата.

Сначала это может быть немного трудно понять, поэтому, если это первый раз, когда он ударил вас;Я бы порекомендовал эти две статьи для справки и подробного объяснения:

0 голосов
/ 12 марта 2012

Может быть, так?

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;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...