如何为不同的 ContentTypes 查询 SharePoint 列表?
How can I query a SharePoint List for different ContentTypes?
我正在开发一个控制台应用程序以使用 .NET client object model of the SharePoint 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"
- 给我一些 User-type 字段带来麻烦:每当我将这些作为需要检索的字段时 通过 GetFields()
方法(见上文), 我得到 the infamous "Value does not fall within the expected range." error。例如,"DTBusinessResponsible"
可以检索,但"DTSupplyLeadResponsible"
不能检索。
我被告知 "Demands"
包含两个 ContentTypes
:"Demand"
和 "I-Demand"
。给我问题的字段是 "I-Demand"
.
独有的
我不知道如何检索这些有问题的字段。我尝试检索 "Demand"
和 "I-Demand"
的 ContentType
并将它们添加到 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);
但这没有用,我收到一条错误消息,告诉我两个 ContentType
都已经存在。
(请注意 I have already asked this over at the SharePoint SE,但我在那里没有得到任何有用的回复。)
编辑:让我们简化问题。
我需要从名为 "Demands"
的 SharePoint 列表中检索多个字段。为此,我将需要的字段添加为 Expression<Func<T, object>>[]
.
但是,我需要检索的一些字段是 "I-Demand"
独有的,它是 "Demands"
列表的 ContentTypes
之一。每当我添加这些字段时,查询都会崩溃并生成 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(十)个项目,而 SharePoint 中有 160 个条目;
validNames
包含六个字段:"Title"、"Author"、"Created"、"Editor"、"Modified"、"ID"。
这比我得到的结果稍微好一点,因为 "Author" 和 "Editor" 有问题。其余字段 return 为空,但这可能是因为十个结果没有值。但是,我无法与 SharePoint 中的值进行比较,因为 returned 的十个标题是 而不是 要求 table...
我尝试通过在 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);
结果:160 项,"DTBusinessRequestor"、"DTBusinessResponsible"、"DTBusinessSponsor" 和 "DTIICTBusinessAnalyst" BUT[=121= 的值] "Author" 和 "Editor" 没有结果——所以我回到了起点。
我还没有找到一个单一的解决方案,它 return 为需求列表中的所有 160 个条目加上 "Author" 和 "Editor" 以及 [=141] 的值=]、"DTSupplyAccountable" 和 "DTSupplyLeadResponsible"(如适用)。
每当我添加 <Query><Where><Eq><FieldRef Name='ContentType' /><Value Type='Computed'>I-Demand</Value></Eq></Where></Query>
我得到零结果。
经过多次试验和错误,我设法让它工作:
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"><View Scope="RecursiveAll">
<Query>
</Query>
</View></Property>
一时兴起,我决定将 Scope="RecursiveAll"
添加到我的代码中,结果成功了。
构造两个单独的 caml 查询,每个查询指定一种或另一种内容类型。然后,获取结果,并将它们读入您自己的数据对象(例如 POCO 对象——普通旧 C# 对象)。一旦它们在您的 Poco 数据对象中,您就可以使用 Linq 合并数据集,然后您可以使用这些数据集。
您可以编写通用方法将 ListItem 数据读取到 POCO 对象中,因此这是一种可重用的方法,可在您遇到此问题时使用。
我正在开发一个控制台应用程序以使用 .NET client object model of the SharePoint 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"
- 给我一些 User-type 字段带来麻烦:每当我将这些作为需要检索的字段时 通过 GetFields()
方法(见上文), 我得到 the infamous "Value does not fall within the expected range." error。例如,"DTBusinessResponsible"
可以检索,但"DTSupplyLeadResponsible"
不能检索。
我被告知 "Demands"
包含两个 ContentTypes
:"Demand"
和 "I-Demand"
。给我问题的字段是 "I-Demand"
.
我不知道如何检索这些有问题的字段。我尝试检索 "Demand"
和 "I-Demand"
的 ContentType
并将它们添加到 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);
但这没有用,我收到一条错误消息,告诉我两个 ContentType
都已经存在。
(请注意 I have already asked this over at the SharePoint SE,但我在那里没有得到任何有用的回复。)
编辑:让我们简化问题。
我需要从名为 "Demands"
的 SharePoint 列表中检索多个字段。为此,我将需要的字段添加为 Expression<Func<T, object>>[]
.
但是,我需要检索的一些字段是 "I-Demand"
独有的,它是 "Demands"
列表的 ContentTypes
之一。每当我添加这些字段时,查询都会崩溃并生成 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(十)个项目,而 SharePoint 中有 160 个条目;validNames
包含六个字段:"Title"、"Author"、"Created"、"Editor"、"Modified"、"ID"。
这比我得到的结果稍微好一点,因为 "Author" 和 "Editor" 有问题。其余字段 return 为空,但这可能是因为十个结果没有值。但是,我无法与 SharePoint 中的值进行比较,因为 returned 的十个标题是 而不是 要求 table...
我尝试通过在 viewXml.AppendLine("</ViewFields>");
:
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);
结果:160 项,"DTBusinessRequestor"、"DTBusinessResponsible"、"DTBusinessSponsor" 和 "DTIICTBusinessAnalyst" BUT[=121= 的值] "Author" 和 "Editor" 没有结果——所以我回到了起点。
我还没有找到一个单一的解决方案,它 return 为需求列表中的所有 160 个条目加上 "Author" 和 "Editor" 以及 [=141] 的值=]、"DTSupplyAccountable" 和 "DTSupplyLeadResponsible"(如适用)。
每当我添加 <Query><Where><Eq><FieldRef Name='ContentType' /><Value Type='Computed'>I-Demand</Value></Eq></Where></Query>
我得到零结果。
经过多次试验和错误,我设法让它工作:
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"><View Scope="RecursiveAll">
<Query>
</Query>
</View></Property>
一时兴起,我决定将 Scope="RecursiveAll"
添加到我的代码中,结果成功了。
构造两个单独的 caml 查询,每个查询指定一种或另一种内容类型。然后,获取结果,并将它们读入您自己的数据对象(例如 POCO 对象——普通旧 C# 对象)。一旦它们在您的 Poco 数据对象中,您就可以使用 Linq 合并数据集,然后您可以使用这些数据集。
您可以编写通用方法将 ListItem 数据读取到 POCO 对象中,因此这是一种可重用的方法,可在您遇到此问题时使用。