具有多重查找功能的复杂查询

时间:2011-02-21 12:52:32

标签: sharepoint sharepoint-2010 sharepointfoundation2010 linq-to-sharepoint

我正在尝试获取一个列表的项目,其中任何多个查找值都包含在另一个查询的结果中。

情况是这样的:我正在构建一个webpart,用户可以使用一组sharepoint(foundation 2010)列表为五个属性下拉列表生成报告(“融合”)。属性通过列表中的查找进行连接。每次更改下拉列表选择时,都会发生回发并重新填充以下下拉列表。

问题在于,属性之间的联系并不是下拉列表的直接匹配。这是因为选择下拉输入是为了直观输入报告,而数据模型的设计是为了方便直观地输入系统数据,而不是为了高效和简单的编程......

数据模型的相关部分:
-Locaties(位置)是一个列表
-Contracten(合同)是一个列表,每个合同都有一个或多个locaties(多次查找)
-Urgentie(紧急)是一个列表,每个紧急有一个合同(查找)
-Meldingtypes(reporttype)是一个列表
-Categorieën(类别)是一个列表,每个类别都有一个meldingtype(查找),每个类别有一个或多个契约(多重查找)

报告输入如下:
用户首先选择Locatie 用户选择Meldingtype second 用户选择分类第三 用户选择合同第四 最后用户选择了Urgentie

当然,每次下拉列表只应填充有效选项。因此,当选择一个位置时,下拉列表中显示的唯一融合类型应该是具有合同的类别,这些类别具有所选位置......是的,我知道;)

我在创建查询以填充下拉列表时遇到问题。我一直在尝试几种方法,包括多个查询,使用Contains选择器的构造,但没有一个工作。在最后一次迭代中,我创建了一个查询,该查询使用了一个项目在multilookup引用时具有的属性。这里是meldingtype下拉列表的示例:

    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按预期填充,但categorieenData再次生成相同的错误。 [/编辑]

P.S。因为代码中的荷兰语名称在英语中非常易读,所以我没有翻译名称。对不起,感到困惑。

2 个答案:

答案 0 :(得分:0)

SharePoint 2010中的linq存在一些限制。也许这篇文章可以让您走上正确的轨道:http://www.chaholl.com/archive/2010/03/12/joins-in-linq-to-sharepoint-2010.aspx

答案 1 :(得分:0)

我已经解决了这个问题。它确实带来了一些开销:从数据库中检索的记录太多。但只有重复,所以希望缓存可以解决大部分开销。

我现在使用的查询非常简单。

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

这不会给我一组CategorieItems,而是一组CategorieItems,其中一些可能是重复的。然后我使用双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;
    }