сложный запрос с несколькими поисками - PullRequest
1 голос
/ 21 февраля 2011

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

Ситуация такова: я создаю веб-часть, с помощью которой пользователи могут создавать отчеты («объединение»), используя набор списков sharepoint (Foundation 2010) для пяти раскрывающихся списков свойств. Свойства связаны через поиск в списках. Каждый раз при изменении выпадающего списка происходит обратная передача, и следующие выпадающие списки повторно заполняются.

Проблема в том, что связи между правами собственности не совсем соответствуют выпадающим спискам. Это связано с тем, что выпадающие входы выбраны для интуитивно понятного ввода отчетов, а модель данных предназначена для простого и интуитивного ввода системных данных, а не для эффективного и легкого программирования ...

Соответствующая часть модели данных:
-Локации (места) это список
-Contracten (контракты) - это список, каждый контракт имеет одну или несколько локаций (multi-lookup)
-Ургентность (срочность) - список, у каждого срочности есть один контракт (поиск)
-Meldingtypes (тип отчета) представляет собой список
-Categorieën (категории) - это список, каждая категория имеет один тип объединения (поиск), каждая категория имеет один или несколько контрактов (многократный поиск)

Входные данные отчета следующие:
Пользователь сначала выбирает Locatie
Пользователь выбирает второй тип Melding
Пользователь выбирает категорию третье
Пользователь выбирает Контракт четвертый
В итоге пользователь выбирает Urgentie

Конечно, каждый раз, когда выпадающий список должен заполняться только допустимыми параметрами. Поэтому, когда выбрано местоположение, в раскрывающемся списке должны отображаться только те типы объединения, в которых есть категории, в которых есть контракт и выбранное местоположение ... да, я знаю;)

У меня проблемы с созданием запросов для заполнения выпадающих списков. Я пробовал несколько методов, включая несколько запросов, конструкции с селектором Contains, и ни один из них не работал. В последней итерации я создал запрос, который использует свойство элемента, когда на него ссылается multilookup. Вот пример раскрывающегося списка типа объединения:

    private void fillMeldingtypeDropdown(Intermediair.IntermediairDataContext idctx)
    {
        var meldingtypeData = (from l in idctx.Locaties
                               from co in l.ContractenItem
                               from ca in co.CategorieënItem
                               where l.Id == selectedLocatieId
                               select ca.Meldingtype
                              ).Distinct<Intermediair.Item>();
        foreach (Intermediair.Item meldingtype in meldingtypeData)
        {
            ctrl_Meldingtype.Items.Add(new ListItem(meldingtype.Titel, meldingtype.Id.ToString()));
        }
    }

selectedLocatieId - это свойство, которое получает значение из раскрывающегося списка Locatie.

Приведенный выше код вызывает исключение System.InvalidOperationException. Описание ошибки на голландском языке, в переводе это будет выглядеть примерно так: «В запросе используются неподдерживаемые элементы, такие как ссылки на несколько списков или проекция полной сущности с EntityRef / EntitySet»

Я получаю ту же ошибку, если использую EntitySet.Contains:

    private void fillCategorieDropdown(Intermediair.IntermediairDataContext idctx)
    {
        var contractenData = from c in idctx.Contracten
                             where c.LocatieS.Contains( 
                                 (  from l in idctx.Locaties 
                                    where l.Id == selectedLocatieId 
                                    select l
                                 ).First<Intermediair.LocatiesItem>() 
                             )
                             select c;
        var categorieenData = ( from ca in idctx.Categorieën
                                from co in contractenData
                                where ca.Contract.Contains(co) && ca.Meldingtype.Id == selectedMeldingtypeId
                                select ca
                              ).Distinct<Intermediair.CategorieënItem>();
        foreach (var categorie in categorieenData)
        {
            ctrl_Categorie.Items.Add(new ListItem(categorie.Titel, categorie.Id.ToString()));
        }
    }

Я пробовал несколько перестановок, но, похоже, не могу найти правильную. Я не могу найти хороших примеров для запросов linq-to-sharepoint с полями с множественным поиском, и я еще недостаточно хорошо разбираюсь в linq, поэтому я, вероятно, делаю некоторые ошибки мэра. Пока я в этом разбираюсь, буду очень признателен за любую полезную идею.

[Редактировать: другая попытка не удалась] Я пытался сделать отдельные запросы всех шагов, чтобы проверить промежуточные результаты. Я также опробовал комбинацию Any-Contains, чтобы сопоставить многократные контракты категории с множественными контрактами, которые я получил от местоположения.

        var locatieItem = (from l in idctx.Locaties
                           where l.Id == selectedLocatieId
                           select l
                          ).First();
        var contractenData = from c in locatieItem.ContractenItem
                             select c;
        var categorieenData = from c in idctx.Categorieën
                              where c.Contract.Any(co => contractenData.Contains(co))
                              select c;
        var meldingtypeData = (from c in categorieenData
                               select c.Meldingtype
                              ).Distinct();
        foreach (var meldingtype in meldingtypeData)
        {
            ctrl_Meldingtype.Items.Add(new ListItem(meldingtype.Titel, meldingtype.Id.ToString()));
        }

locatieItem и contractenData заполнены, как и ожидалось, но categoryorenData снова генерирует ту же ошибку. [/ Edit]

P.S. Поскольку голландские имена в коде очень удобочитаемы на английском языке, я не переводил имена. Извините за путаницу.

Ответы [ 2 ]

0 голосов
/ 01 марта 2011

Я решил проблему, sortof.Это дает некоторые накладные расходы: слишком много записей извлекается из базы данных.Но только дубликаты, поэтому, надеюсь, кэширование решит большую часть этих накладных расходов.

Запрос, который я сейчас использую, обманчиво прост.

        var categorieenContractenData = from c in contractenData
                                        select c.CategorieënItem;

Это не дает мне один набор КатегорийItems, но набор множеств КатегорийItems, некоторые из которых могут быть дубликатами.Затем я перебираю каждую запись с помощью двойного цикла foreach и помещаю элементы в три структуры данных для облегчения поиска.Это означает, что для заполнения каждого из трех выпадающих списков мне нужно выполнить только один запрос linq.

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

Полный код:

    private void ensureLoadData(Intermediair.IntermediairDataContext idctx)
    {
        if (dataLoaded) return;

        meldingtypes = new SortedList<string, int?>();
        categorieen = new SortedList<int?,SortedList<string,int?>>();
        contracten = new SortedList<int?, SortedList<int?, SortedList<string, int?>>>();
        IQueryable<Intermediair.ContractenItem> contractenData = from c in
                                                                     (from l in idctx.Locaties
                                                                      where l.Id == selectedLocatieId
                                                                      select l
                                                                     ).SingleOrDefault().ContractenItem
                                                                 select c;
        var categorieenContractenData = from c in contractenData
                                        select c.CategorieënItem;
        foreach (EntitySet<Intermediair.CategorieënItem> categorieenPerContract in categorieenContractenData)
        {
            foreach (Intermediair.CategorieënItem categorie in categorieenPerContract)
            {
                if (!meldingtypes.ContainsKey(categorie.Meldingtype.Titel))
                {
                    meldingtypes.Add(categorie.Meldingtype.Titel, categorie.Meldingtype.Id);
                    categorieen.Add(categorie.Meldingtype.Id, new SortedList<string,int?>());
                    contracten.Add(categorie.Meldingtype.Id, new SortedList<int?, SortedList<string, int?>>());
                }
                if (!categorieen[categorie.Meldingtype.Id].ContainsKey(categorie.Titel))
                {
                    categorieen[categorie.Meldingtype.Id].Add(categorie.Titel, categorie.Id);
                    contracten[categorie.Meldingtype.Id].Add(categorie.Id, new SortedList<string,int?>());
                    foreach (Intermediair.ContractenItem contract in categorie.Contract)
                    {
                        contracten[categorie.Meldingtype.Id][categorie.Id].Add(contract.Titel, contract.Id);
                    }
                }
            }
        }
        dataLoaded = true;
    }
0 голосов
/ 21 февраля 2011

Существуют некоторые ограничения для linq в SharePoint 2010. Возможно, эта статья поможет вам выбрать правильный путь: http://www.chaholl.com/archive/2010/03/12/joins-in-linq-to-sharepoint-2010.aspx

...