特定のSPListに対して実行され、特定のフォルダーにスコープされ、その時点から再帰的に、すべてのListItem(基準を満たす)とフォルダーを返すCAMLクエリを作成しようとしています。
動作するはずのクエリのコードは次のとおりです(読みやすくするためにフォーマットされています)。
SPQuery query = new SPQuery();
query.Query = "
<Where>
<Or>
<Contains>
<FieldRef Name=\"FileRef\" />
<Value Type=\"Text\">foo</Value>
</Contains>
<Eq>
<FieldRef Name=\"FSObjType\" />
<Value Type=\"Lookup\">1</Value>
</Eq>
</Or>
</Where>";
query.ViewFields = "
<FieldRef Name=\"CustomField1\" Nullable=\"TRUE\" />
<FieldRef Name=\"CustomField2\" Nullable=\"TRUE\" />
<FieldRef Name=\"CustomField3\" Nullable=\"TRUE\" />
";
query.RowLimit = 500;
query.ViewAttributes = "Scope=\"RecursiveAll\"";
query.Folder = startingFolder;
DataTable dt = myList.GetItems(query).GetDataTable();
つまり、これはListItemのみを返します。フォルダは返しません。
クエリから他の条件を削除し、FSObjType=1
だけを残すと、「このアクションを完了できません。もう一度やり直してください」というCOM例外が発生します。
次に、Scope=RecursiveAll
とFSObjType=1
だけを残して、ViewFieldsを削除すると、空の結果セットが返されます。
誰もが近くにいますが、完全には正しくありません。
using (SPSite site = new SPSite("http://server/site"))
{
SPWeb web = site.RootWeb; // See disposal guidance http://blogs.msdn.com/b/rogerla/archive/2008/10/04/updated-spsite-rootweb-dispose-guidance.aspx
SPQuery query = new SPQuery();
query.Query = @"
<Where>
<BeginsWith>
<FieldRef Name='ContentTypeId' />
<Value Type='ContentTypeId'>0x0120</Value>
</BeginsWith>
</Where>";
query.ViewAttributes = "Scope='RecursiveAll'";
SPList list = web.Lists[listId];
SPListItemCollection items = list.GetItems(query);
// Do stuff with your folders
}
まず第一に、このFieldRefの使用は間違っています:
<FieldRef Name='ContentType' /><Value Type='Text'>Folder</Value>
フォルダのコンテンツタイプを継承できるためです。したがって、次のようにコンテンツタイプIDと比較する必要があります。
<Where>
<BeginsWith>
<FieldRef Name='ContentTypeId' />
<Value Type='ContentTypeId'>0x0120</Value>
</BeginsWith>
</Where>
次に、ビュー属性ScopeをRecursiveAllに設定します
<View Scope='RecursiveAll'>...</View>
これにより、コンテンツタイプがフォルダー(0x0120)から継承するアイテムが返されます。
代わりに、Camlクエリをフォルダコンテンツタイプに基づいて試すことができます。
<FieldRef Name='ContentType' /><Value Type='Text'>Folder</Value>
を維持しながら
Query.ViewAttributes = "Scope=\"RecursiveAll\"";
テストする開発イメージがないため、後で修正する必要があるかもしれません。でもやってみてもいいと思います
_query.ViewAttributes = "Scope=\"Recursive\"";
_
アイテムを取得すると、SPUtility.GetUrlDirectory(url)
を使用して特定のアイテムのフォルダーパスを取得し、そこからフォルダー階層を解析できます。
私はこのパッティングを解決しました:
<QueryOptions>
<IncludeAttachmentUrls>True</IncludeAttachmentUrls>
<Folder/> </QueryOptions>
クエリオプションとして
私はスタックオーバーフローでそれについての私の質問を見つけました:
これはまだSP 2010で問題になっているようです。Webサービスを使用する このMSDNフォーラムの投稿 に基づいて、2007または2010で機能する回避策コードを次に示します。
private static SPListItem RecurseIntoFolders(SPList list, SPFolder parentFolder, string fileReference)
{
var query = new SPQuery
{
Query = "<Where>" +
"<Eq><FieldRef Name='FSObjType'/><Value Type='Lookup'>1</Value></Eq>" +
"</Where>",
ViewFields = String.Format("<FieldRef Name='{0}' />", FileReferenceInternalFieldName),
ViewAttributes = "Scope='RecursiveAll'",
Folder = parentFolder
};
var items = list.GetItems(query);
if (items.Count == 0)
return null;
foreach (SPListItem item in items)
{
parentFolder = item.Folder;
// TODO: Any other checking that this is the item we want
return item;
}
return RecurseIntoFolders(list, parentFolder, fileReference);
}
FSObjType = 1のままにしてクエリから他の条件を削除すると、「このアクションを完了できません。再試行してください」というCOM例外が発生します。
これを行ったときに<Or>
タグを削除しましたか?そうでない場合は、正しく実行されません。
とにかく、それはあなたの問題を解決しません。クエリを空のままにしてみましたか?それは何かを返しますか?
私は似たようなことに取り組んでいて、 issue にも遭遇しました、おそらくそれはいくぶん関連しています。
static string GetParentFolder(SPListItem itemToFind, SPFolder folder)
{
SPQuery query = new SPQuery();
// query.Query = "<OrderBy><FieldRef Name='Title'/></OrderBy>";
query.Query = "<Where><Eq><FieldRef Name=\"ID\"/><Value Type=\"Integer\">"+ itemToFind.ID +"</Value></Eq></Where>";
query.Folder = folder;
query.ViewAttributes = "Scope=\"Recursive\"";
SPListItemCollection items = itemToFind.ParentList.GetItems(query);
int intpartentFolderID=0 ;
if (items.Count > 0)
{
foreach (SPListItem item in items)
{
SPFile f = item.Web.GetFile(item.Url);
string test11 = f.ParentFolder.Name;
intpartentFolderID = f.ParentFolder.Item.ID;
//string test1 = item.File.ParentFolder.Name;
return (intpartentFolderID.ToString());
}
}
return (intpartentFolderID.ToString());
}