Как лучше всего получить отдельные/уникальные значения с помощью SPQuery?
-
05-09-2019 - |
Вопрос
У меня есть список, который выглядит так:
Movie Year
----- ----
Fight Club 1999
The Matrix 1999
Pulp Fiction 1994
Используя CAML и объект SPQuery, мне нужно получить отдельный список элементов из столбца «Год», который будет заполнять раскрывающийся список.
Похоже, что поиск там не позволяет сделать это в запросе CAML.Мне интересно, как люди добились этого?
Решение
Другой способ сделать это — использовать DataView.ToTable-Method — его первый параметр — это тот, который делает список отличным.
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.
Другие советы
Если вы хотите связать отдельные результаты с источником данных, например, с повторителем, и сохранить фактический элемент с помощью метода e.Item.DataItem событий ItemDataBound, способ DataTable не будет работать.Вместо этого, а также в тех случаях, когда вы не хотите привязывать его к источнику данных, вы также можете использовать 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);
}
}
Предполагается, что ваш раскрывающийся список называется ddlYear.
Можете ли вы переключиться с 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");
Прочитав сообщение за сообщением о том, что это невозможно, я наконец нашел способ.Это было протестировано в SharePoint Online.Вот функция, которая предоставит вам все уникальные значения для столбца.Вам просто требуется передать идентификатор списка, идентификатор представления, внутреннее имя списка и функцию обратного вызова.
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");
});
}
Я рассматривал эту проблему ранее сегодня, и лучшее решение, которое я мог придумать, использует следующий алгоритм (извините, на данный момент кода нет):
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 элементов.