我有一个列表,看起来像这样:
Movie Year
----- ----
Fight Club 1999
The Matrix 1999
Pulp Fiction 1994
使用 CAML 和 SPQuery 对象,我需要从 Year 列中获取一个不同的项目列表,以填充下拉控件。
搜索周围似乎没有在 CAML 查询内完成此操作的方法。我想知道人们是如何实现这一点的?
我有一个列表,看起来像这样:
Movie Year
----- ----
Fight Club 1999
The Matrix 1999
Pulp Fiction 1994
使用 CAML 和 SPQuery 对象,我需要从 Year 列中获取一个不同的项目列表,以填充下拉控件。
搜索周围似乎没有在 CAML 查询内完成此操作的方法。我想知道人们是如何实现这一点的?
SPList movies = SPContext.Current.Web.Lists["Movies"];
SPQuery query = new SPQuery();
query.Query = "<OrderBy><FieldRef Name='Year' /></OrderBy>";
DataTable tempTbl = movies.GetItems(query).GetDataTable();
DataView v = new DataView(tempTbl);
String[] columns = {"Year"};
DataTable tbl = v.ToTable(true, columns);
您可以使用 DataTable tbl 继续进行操作。如果您想将不同的结果绑定到例如Repeater的DataSource,并通过ItemDataBound事件的e.Item.DataItem方法保留实际项,则DataTable方式将无法工作。相反,即使不想将其绑定到DataSource,您也可以使用Linq定义不同的值。
// Retrieve the list. NEVER use the Web.Lists["Movies"] option as in the other examples as this will enumerate every list in your SPWeb and may cause serious performance issues
var list = SPContext.Current.Web.Lists.TryGetList("Movies");
// Make sure the list was successfully retrieved
if(list == null) return;
// Retrieve all items in the list
var items = list.GetItems();
// Filter the items in the results to only retain distinct items in an 2D array
var distinctItems = (from SPListItem item in items select item["Year"]).Distinct().ToArray()
// Bind results to the repeater
Repeater.DataSource = distinctItems;
Repeater.DataBind();
请记住,由于没有CAML对不同查询的支持,本页面提供的每个示例都将检索SPList中的所有项。这对于较小的列表可能没有问题,但对于具有数千个列表项的列表来说,这将严重影响性能。不幸的是,目前没有更优化的方法来实现相同的功能。
在 CAML 中没有 DISTINCT 来填充下拉列表,尝试使用类似以下的内容:
foreach (SPListItem listItem in listItems)
{
if ( null == ddlYear.Items.FindByText(listItem["Year"].ToString()) )
{
ListItem ThisItem = new ListItem();
ThisItem.Text = listItem["Year"].ToString();
ThisItem.Value = listItem["Year"].ToString();
ddlYear.Items.Add(ThisItem);
}
}
在看了一遍又一遍关于这是不可能的帖子之后,我终于找到了一种方法。这在SharePoint Online中进行了测试。以下是一个函数,它将为您获取列的所有唯一值。它只需要您传递列表ID、视图ID、内部列表名称和回调函数即可。
function getUniqueColumnValues(listid, viewid, column, _callback){
var uniqueVals = [];
$.ajax({
url: _spPageContextInfo.webAbsoluteUrl + "/_layouts/15/filter.aspx?ListId={" + listid + "}&FieldInternalName=" + column + "&ViewId={" + viewid + "}&FilterOnly=1&Filter=1",
method: "GET",
headers: { "Accept": "application/json; odata=verbose" }
}).then(function(response) {
$(response).find('OPTION').each(function(a,b){
if ($(b)[0].value) {
uniqueVals.push($(b)[0].value);
}
});
_callback(true,uniqueVals);
},function(){
_callback(false,"Error retrieving unique column values");
});
}
你能从SPQuery切换到SPSiteDataQuery吗?你应该可以毫无问题地进行切换。
之后,你可以使用标准的ado.net行为:
SPSiteDataQuery query = new SPSiteDataQuery();
/// ... populate your query here. Make sure you add Year to the ViewFields.
DataTable table = SPContext.Current.Web.GetSiteData(query);
//create a new dataview for our table
DataView view = new DataView(table);
//and finally create a new datatable with unique values on the columns specified
DataTable tableUnique = view.ToTable(true, "Year");
L is a list of known values (starts populated with the static Choice options when querying fill-in options, for example)
X is approximately the number of possible options
1. Create a query that excludes the items in L
1. Use the query to fetch X items from list (ordered as randomly as possible)
2. Add unique items to L
3. Repeat 1 - 3 until number of fetched items < X
这将显著减少返回的总项目数,但会增加更多的查询成本。
X是否完全准确并不重要,但随机性非常重要。基本上,第一个查询可能包括最常见的选项,因此第二个查询将排除这些选项,并可能包括接下来最常见的选项,以此类推。
在最好的情况下,第一个查询包括所有选项,那么第二个查询将为空。(总共检索X个项目,分2个查询)
在最坏的情况下(例如,查询按我们正在查找的选项排序,并且每个选项都有超过X个项目),我们将进行与选项数量相同的查询。总共返回大约X * X个项目。