如何在SharePoint列表中查询不同的ContentTypes?

时间:2015-09-11 10:26:21

标签: c# sharepoint sharepoint-2013

我正在开发一个控制台应用程序,使用.NET client object modelSharePoint Server 2013 Client Components SDK从SharePoint 2013服务器中提取数据:

using (var clientContext = new ClientContext(SharePointUrl))
{
    var list = clientContext.Web.Lists.GetByTitle(listName);
    var camlQuery = CamlQuery.CreateAllItemsQuery();
    var listItems = list.GetItems(camlQuery);
    clientContext.Load(listItems, GetFields(fields));
    clientContext.ExecuteQuery();
    return listItems.ToList();
}

这是我调用构建我请求的字段列表的GetFields()方法:

private Expression<Func<ListItemCollection, object>>[] GetFields(IEnumerable<string> fields)
{
    return fields
        .Select(field => (Expression<Func<ListItemCollection, object>>)(items => items.Include(item => item[field])))
        .ToArray();
}

有一个大的列表 - "Demands" - 这给了我一些用户类型字段的麻烦:每当我将这些字段包含为需要检索的字段时,通过GetFields()方法(见上文),我得到the infamous "Value does not fall within the expected range." error 。例如,可以检索"DTBusinessResponsible",但"DTSupplyLeadResponsible"不能。{/ p>

我们被告知"Demands"包含两个ContentTypes"Demand""I-Demand"。给我提出问题的字段仅供"I-Demand"使用。

我无法弄清楚如何检索这些有问题的字段。我已尝试检索ContentType"Demand"的{​​{1}}并将其添加到"I-Demand"

list

但这没用,我收到一个错误,告诉我两个var demandContentType = clientContext.Web.ContentTypes.GetById(contentTypeByName["Demand"]); var iDemandContentType = clientContext.Web.ContentTypes.GetById(contentTypeByName["I-Demand"]); list.ContentTypesEnabled = true; list.ContentTypes.AddExistingContentType(demandContentType); list.ContentTypes.AddExistingContentType(iDemandContentType); 已经存在。

(请注意I have already asked this over at the SharePoint SE,但我在那里没有得到任何有用的回复。)

编辑:让我们简化一下问题。

我需要从名为ContentType的SharePoint列表中检索许多字段。为此,我将我需要的字段添加为Expression<Func<T, object>>[]

但是,我需要检索的某些字段是"Demands"独有的,"I-Demand"ContentTypes列表的"Demands"之一。每当我添加这些字段时,查询都会崩溃并生成the infamous "Value does not fall within the expected range." error。我可以轻松检索许多其他字段,这些字段都是"Demand"内容类型的一部分。

如何检索"I-Demand"内容类型专用的字段?

编辑:这里有什么不起作用......

var fields = new List<string>
{
    "DTBusinessRequestor",
    "DTBusinessResponsible",
    "DTBusinessSponsor",
    "DTDemandAccountable",
    "DTIICTBusinessAnalyst",
    "DTSupplyAccountable",
    "DTSupplyLeadResponsible",
    "Title",
    "Author",
    "Created",
    "Editor",
    "Modified",
    "ID"
};

var viewXml = new StringBuilder();

viewXml.AppendLine("<ViewFields>");
foreach (var field in fields)
{
    viewXml.AppendFormat("<FieldRef Name=\"{0}\" />", field).AppendLine();
}
viewXml.AppendLine("</ViewFields>");

var camlQuery = new CamlQuery { ViewXml = string.Format("<View>{0}</View>", viewXml) };

List<ListItem> results;

using (var clientContext = GetClientContext())
{
    var list = clientContext.Web.Lists.GetByTitle("Demands");
    var listItems = list.GetItems(camlQuery);
    clientContext.Load(listItems);
    clientContext.ExecuteQuery();
    results = listItems.ToList();
}

var validNames = new HashSet<string>();

foreach (var listItem in results)
{
    foreach (var field in fields)
    {
        object value;
        if (!listItem.FieldValues.TryGetValue(field, out value))
            continue;

        if (value != null)
        {
            validNames.Add(field);
        }
    }
}

当我执行上面的代码时:

  • results包含10(10)个项目,而SharePoint中有160个条目;
  • validNames包含六个字段:&#34;标题&#34;,&#34;作者&#34;,&#34;创建&#34;,&#34;编辑&#34;,&# 34;修改&#34;,&#34; ID&#34;。

这比我的结果略胜一筹,因为&#34;作者&#34;和&#34;编辑&#34;是有问题的。其余字段返回null,但这可能是因为十个结果没有值。但是,我无法与SharePoint中的值进行比较,因为返回的十个标题是 在Demands表中找到的标题...

我尝试通过在viewXml.AppendLine("</ViewFields>");之后添加此行来过滤ContentType:

viewXml.AppendLine("<Query><Where><Eq><FieldRef Name='ContentType' /><Value Type='Computed'>I-Demand</Value></Eq></Where></Query>");

结果:results不包含任何条目。

我按ContentType删除过滤器并更改:

var camlQuery = new CamlQuery { ViewXml = string.Format("<View>{0}</View>", viewXml) };

到此:

var camlQuery = CamlQuery.CreateAllItemsQuery();
camlQuery.ViewXml = string.Format("<View>{0}</View>", viewXml);

与原来相同的结果:十个项目,相同的字段。

然后我删除了这一行:

camlQuery.ViewXml = string.Format("<View>{0}</View>", viewXml);

结果:1​​60项,&#34; DTBusinessRequestor&#34;,&#34; DTBusinessResponsible&#34;,&#34; DTBusinessSponsor&#34;和&#34; DTIICTBusinessAnalyst&#34; 但是 没有结果&#34;作者&#34;和&#34;编辑&#34; - 所以我回到了我开始的地方。

我还没有找到一个单独的解决方案,它返回了需求列表中所有160个条目的值以及&#34;作者&#34;的值。和&#34;编辑&#34;还有&#34; DTDemandAccountable&#34;,&#34; DTSupplyAccountable&#34;和&#34; DTSupplyLeadResponsible&#34; (适用时)。

每当我添加<Query><Where><Eq><FieldRef Name='ContentType' /><Value Type='Computed'>I-Demand</Value></Eq></Where></Query>时,我都会得到零结果。

2 个答案:

答案 0 :(得分:0)

通过大量试验和错误,我设法让这个工作:

var fields = new List<string>
{
    "DTSupplyAccountable",
    "DTSupplyLeadResponsible",
    "Author",
    "Editor",
    "ID"
};

var viewXml = new StringBuilder();

viewXml.AppendLine("<ViewFields>");
foreach (var field in fields)
{
    viewXml.AppendFormat("<FieldRef Name=\"{0}\" />", field).AppendLine();
}
viewXml.AppendLine("</ViewFields>");

viewXml.AppendLine("<Query><Where><Eq><FieldRef Name=\"ContentType\" /><Value Type=\"Computed\">I-Demand</Value></Eq></Where></Query>");

var camlQuery = new CamlQuery {ViewXml = string.Format("<View Scope=\"RecursiveAll\">{0}</View>", viewXml)};

List<ListItem> results;

using (var clientContext = GetClientContext())
{
    var list = clientContext.Web.Lists.GetByTitle("Demands");
    var listItems = list.GetItems(camlQuery);
    clientContext.Load(listItems);
    clientContext.ExecuteQuery();
    results = listItems.ToList();
}

这是至关重要的细节(除了显而易见的<Where><Eq><FieldRef Name=\"ContentType\" /><Value Type=\"Computed\">I-Demand</Value></Eq></Where>):

ViewXml = string.Format("<View Scope=\"RecursiveAll\">{0}</View>", viewXml)

事实上,Scope=\"RecursiveAll\"是重要的一部分。我在使用Fiddler查看发送到服务器的各种请求并注意到所有工作调用都包含此内容时遇到了它:

<Property Name="ViewXml" Type="String">&lt;View Scope="RecursiveAll"&gt;&#xD;
    &lt;Query&gt;&#xD;
    &lt;/Query&gt;&#xD;
&lt;/View&gt;</Property>

我一时兴起决定将Scope="RecursiveAll"添加到我的代码中,并且它有效。

答案 1 :(得分:0)

构造两个单独的caml查询,每个查询指定一个或另一个内容类型。然后,获取结果,并将它们读入您自己的数据对象(例如POCO对象 - Plain Old C#Objects)。一旦它们进入您的Poco数据对象,您就可以使用Linq合并数据集,然后您可以使用这些数据集。

您可以编写通用方法将ListItem数据读入POCO对象,因此无论何时遇到此问题,这都是可重用的方法。