次のようなリストがあります。
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);
その後、DataTabletblを使用して続行できます。
個別の結果をたとえばリピーターのデータソースにバインドし、ItemDataBoundイベントのe.Item.DataItemメソッドを介して実際のアイテムを保持する場合、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からすべてのアイテムを取得することに注意してください。これは小さなリストには問題ないかもしれませんが、何千ものリストアイテムを含むリストの場合、これは深刻なパフォーマンスキラーになります。残念ながら、これを達成するための最適化された方法はこれ以上ありません。
ドロップダウンにデータを入力するためのDISTINCTはCAMLにはありません。次のようなものを使用してみてください。
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と呼ばれると仮定します。
これがどのように不可能であったかについて投稿を次々と見つけた後、私はついに方法を見つけました。これはSharePointOnlineでテストされています。これは、列のすべての一意の値を取得する関数です。リスト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が完全に正確であるかどうかはそれほど重要ではありませんが、ランダム性は非常に重要です。基本的に、最初のクエリには最も一般的なオプションが含まれる可能性が高いため、2番目のクエリではこれらが除外され、次の最も一般的なオプションなどが反復を通じて含まれる可能性があります。
最良の場合、最初のクエリにはすべてのオプションが含まれ、2番目のクエリは空になります。 (合計X個のアイテム、2回以上のクエリ)
最悪の場合(たとえば、クエリは探しているオプション順に並べられ、各オプションにはXを超えるアイテムがあります)、オプションと同じ数のクエリを実行します。合計で約X * X個のアイテムを返します。