SharePointにWebパーツがあり、リスト内の特定のフィールドの一意の値または異なる値をドロップダウンコントロールに入力しようとしています。LINQで一意の値を取得する方法は簡単ですか?
残念ながら、システムの性質上、それはテキストフィールドなので、データ値を得るための他の決定的なソースはありません(つまり、選択フィールドの場合はフィールド定義を取得できますそこから値を取得する)、後でCAMLクエリでドロップダウンの値を使用しているので、の値はでなければなりません。現在のところリストにはアープロックスがあります。 4Kのアイテムが含まれていますが、ゆっくりと成長しています。
そして、それはサンドボックスソリューションの一部なので、ユーザーコードサービスの制限時間によって制限されています。タイムアウトが頻繁に発生します。私の開発環境では、私はデバッグでコードを踏んで、LINQの行のように私は実際に別の値を取得するのが最も時間がかかり、私はこのメソッドの呼び出しを完全にコメントアウトし、だから私はこれがどこに問題があるのかかなり確信している。ここで
は私のコードです:
private void AddUniqueValues(SPList list, SPField filterField, DropDownList dropDownControl)
{
SPQuery query = new SPQuery();
query.ViewFields = string.Format("<FieldRef Name='{0}' />", filterField.InternalName);
query.ViewFieldsOnly = true;
SPListItemCollection results = list.GetItems(query); // retrieves ~4K items
List<string> uniqueValues = results.Cast<SPListItem>().Select(item => item[filterField.Id].ToString()).Distinct().ToList(); // this takes too long with 4K items
uniqueValues.Sort();
dropDownControl.Items.AddRange(uniqueValues.Select(itm => new ListItem(itm)).ToArray());
}
は、私の知る限り、CAMLクエリで直接「明確な」値を取得する方法はありませんので、どのように私はより迅速にこれを行うことができますか?より速く実行するためにLINQを再構成する方法はありますか?
これをクライアント側から簡単に行う方法はありますか? (RESTが好まれますが、必要ならJSOMをやります)。
私はさらにテストをして興味深い結果を見つけたので、ここにいくつかの追加情報を追加したいと思います。
まず、Cast()
とSelect()
が必要かどうかの質問に答えるには:はい、そうです。
SPListItemCollection
はIEnumerable
ですが、IEnumerable<T>
ではなく、LINQをまったく使用できるようにキャストする必要があります。
そして、それはIEnumerable<SPListItem>
にキャストだ後、SPListItem
はかなり複雑なオブジェクトであり、そして私は、そのオブジェクトのちょうどプロパティは異なる値を見つけるために探しています。 IEnumerable<SPListItem>
に直接Distinct()
を使用すると、それらのすべてが得られます。だから私はSelect()
私は比較したい単一の値にする必要があります。
はい、Cast()
とSelect()
は絶対に必要です。
M.kazem Akhgaryさんのコメントで指摘されているように、私の元のコード行では、毎回ToString()
(4Kアイテム用)を呼び出すのに時間がかかりました。しかし、他のいくつかのバリエーションをテストするには:
// original
List<string> uniqueValues = results.Cast<SPListItem>().Select(item => item[filterField.Id].ToString()).Distinct().ToList();
// hash set alternative
HashSet<object> items = new HashSet<object>(results.Cast<SPListItem>().Select(itm => itm[filterField.Id]));
// don't call ToString(), just deal with base objects
List<object> obs = results.Cast<SPListItem>().Select(itm => itm[filterField.Id]).Distinct().ToList();
// alternate LINQ syntax from Pieter_Daems answer, seems to remove the Cast()
var things = (from SPListItem item in results select item[filterField.Id]).Distinct().ToList();
は、私はそれらのメソッドのすべてが完了するまでに秒の複数の数十を取ったことがわかりました。不思議なことに、DataTable
/DataView
私は私が欲しかった値を抽出するためにビットを追加するPieter_Daems answerからの方法であって、
DataTable dt = results2.GetDataTable();
DataView vw = new DataView(dt);
DataTable udt = vw.ToTable(true, filterField.InternalName);
List<string> rowValues = new List<string>();
foreach (DataRow row in udt.Rows)
{
rowValues.Add(row[filterField.InternalName].ToString());
}
rowValues.Sort();
はわずか1~2秒を取りました!
最後に、Thriggle's answerとします。これは、SharePointの5000アイテムリストビューのしきい値をうまく扱うためです。これは、おそらく一日で処理されますが、それはわずかに遅く(2-3秒) DataTable
方法。 LINQよりもはるかに高速です。
しかし、興味があるのは、SPListItemCollection
から特定のフィールドから異なる値を取得する最も速い方法は、DataTable
/DataView
の変換方法のようです。
私はそれが 'item [filterField.Id] .ToString()'部分のためだと思います。 'ToString'メソッドはオーバーライドされていますか?そうでなければ、基本的に同じ文字列を何度も何度も返すので、ハッシングのメリットは得られません –
検索にDistinctを追加できませんか? 'SPListItemCollection results = list.GetItems(クエリ).Distinct()'? –
'.Cast.Select.Unique()' linqを実行するのにどれくらいの時間が必要ですか? – TripleEEE