2100件以上アイテムがあるときに小分けして列挙しようとすると・・・
※WSS3.0累積的な更新プログラムについてKB961755にあるパッチ適用前です。
同一フォルダにアイテムが多数あると、SPListItemCollectionのメンバ使用するだけでも例外になってしまいます。→リストに約2100件以上のアイテムがあるとSPList.Items.Countプロパティでさえも例外発生!
一度には列挙できません。
回避策として、検索結果のコレクションの要素数を小さくしようと、アイテムのIDで探索範囲を狭めて繰り返しクエリする以下のコンソールアプリケーションプログラムを作成しました。
下のPrintAllListItemIds1とPrintAllListItemIds2はどちらも指定したリスト(ドキュメントライブラリ)のすべてのアイテムのID表示するメソッドです。
一見するとどちらも同じ結果が期待できそうです。
第1引数に「1」と入力するPrintAllListItemIds1を実行、それ以外はPrintAllListItemIds2を実行します。
手持ちのあの例外確実に起こせるぞ!再現方法。で作成した同一フォルダにアイテム4024件(「すべてのサイト コンテンツ 」の表示で確認)のドキュメントライブラリ(バージョン設定のこのドキュメント ライブラリ の下書きアイテムを表示できるユーザー = 「アイテムを編集できるユーザー 」)で実際に実行してみると・・・
PrintAllListItemIds1
・・・
Number of Items : 1022
PrintAllListItemIds2
・・・
Number of Items : 4023
と違う結果になってしまいました。何度でも実行しても数字は同じです。PrintAllListItemIds1は明らかに誤った結果です。PrintAllListItemIds2はほぼ正しいようです。1件はアップロードしたばかりのバージョン0.1チェックアウトファイルと思われます。(またSharePointに苦戦した件。)
どうやらSPWebオブジェクトを生成しなおさないと、クエリを使用するだけでオブジェクトが何かおかしくなってしまうようです。
using System; using Microsoft.SharePoint; namespace TestSPQuery { class Program { const string QUERY_BY_ID_RANGE = @"<Where> <And> <Geq> <FieldRef Name = ""ID""/> <Value Type = ""Counter"">{0}</Value> </Geq> <Lt> <FieldRef Name = ""ID""/> <Value Type = ""Counter"">{1}</Value> </Lt> </And> </Where>"; const int MaxItemID = 4500;//取得する最大のID const int DEFAULT_ID_RANGE = 100;//1回のクエリ対象にするIDの範囲 /// <summary> /// start<=ID<endというクエリ /// </summary> public static string GetIDRangeQery(int start, int end) { return string.Format(QUERY_BY_ID_RANGE, start, end); } static void Main(string[] args) { String scUrl = "(サイトコレクションURL)"; String siteName = "サイト名"; String listName = "リスト名"; //第1引数に「1」と入力するPrintAllListItemIds1を実行、それ以外はPrintAllListItemIds2を実行 if (args.Length > 0 && args[0] == "1") { PrintAllListItemIds1(scUrl, siteName, listName, DEFAULT_ID_RANGE); } else { PrintAllListItemIds2(scUrl, siteName, listName, DEFAULT_ID_RANGE); } } /// <summary> /// 指定したリスト(ドキュメントライブラリ)のすべてのアイテムのID表示する。 /// </summary> /// <param name="scUrl">サイトコレクションURL</param> /// <param name="siteName">サイト名</param> /// <param name="listName">リスト名</param> /// <param name="rangesize">1回のクエリ対象にするIDの範囲</param> private static void PrintAllListItemIds1(String scUrl, String siteName, String listName, int rangesize) { using (SPSite site = new SPSite(scUrl)) { using (SPWeb web = site.AllWebs[siteName]) { SPList list = web.Lists[listName]; Console.WriteLine("List Title :{0}, ItemCount: {1} ", list.Title, list.ItemCount); int count = 1; for (int start = 0; start <= MaxItemID; start += rangesize) { SPQuery q = new SPQuery(); q.Query = GetIDRangeQery(start, start + rangesize); Console.WriteLine(q.Query); SPListItemCollection itemColl = list.GetItems(q); foreach (SPListItem item in itemColl) { Console.WriteLine("No.:{0} ID: {1} ",count++, item.ID); } } Console.WriteLine("Number of Items : {0}",count-1); } } } /// <summary> /// 指定したリスト(ドキュメントライブラリ)のすべてのアイテムのID表示する。 /// </summary> /// <param name="scUrl">サイトコレクションURL</param> /// <param name="siteName">サイト名</param> /// <param name="listName">リスト名</param> /// <param name="rangesize">1回のクエリ対象にするIDの範囲</param> private static void PrintAllListItemIds2(String scUrl, String siteName, String listName, int rangesize) { using (SPSite site = new SPSite(scUrl)) { using (SPWeb web = site.AllWebs[siteName]) { SPList list = web.Lists[listName]; Console.WriteLine("List Title :{0}, ItemCount: {1} ", list.Title, list.ItemCount); } int count = 1; for (int start = 0; start <= MaxItemID; start += rangesize) { using (SPWeb web = site.AllWebs[siteName])//クエリの度にサイト(webオブジェクト)を生成。 { SPList list = web.Lists[listName]; SPQuery q = new SPQuery(); q.Query = GetIDRangeQery(start, start + rangesize); Console.WriteLine(q.Query); SPListItemCollection itemColl = list.GetItems(q); foreach (SPListItem item in itemColl) { Console.WriteLine("No.:{0} ID: {1} ", count++, item.ID); } } } Console.WriteLine("Number of Items : {0}", count - 1); } } } }