CAML-запрос, включающий папки в наборе результатов - PullRequest
11 голосов
/ 13 октября 2009

Я пытаюсь написать CAML-запрос, который выполняется к определенному SPList, ограничивается определенной папкой, рекурсивен с этой точки и возвращает все ListItems (которые соответствуют критерию) и папки.

Вот код запроса, который, похоже, должен работать (отформатирован для удобства чтения):

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();

Итак - это возвращает только ListItems - без папок.

Если я удаляю другие условия из запроса, оставляя только FSObjType=1, я получаю исключение COM «Не удается выполнить это действие. Пожалуйста, попробуйте еще раз».

Если я затем удалю ViewFields, оставив только Scope=RecursiveAll и FSObjType=1, я получу пустой набор результатов обратно.

Ответы [ 7 ]

14 голосов
/ 20 декабря 2011

Все близки, но не совсем правы.

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>

потому что тип содержимого папки может быть унаследован. Поэтому вам нужно сравнить с идентификатором типа контента, например:

<Where>
  <BeginsWith>
    <FieldRef Name='ContentTypeId' />
    <Value Type='ContentTypeId'>0x0120</Value>
  </BeginsWith>
</Where>

А затем установите атрибут представления Scope на RecursiveAll

<View Scope='RecursiveAll'>...</View>

Это должно вернуть любой элемент, тип содержимого которого наследуется от папки (0x0120)

5 голосов
/ 03 ноября 2009

Вместо этого вы можете попытаться основать свой запрос caml на типе содержимого папки,

<FieldRef Name='ContentType' /><Value Type='Text'>Folder</Value>

при сохранении

Query.ViewAttributes = "Scope=\"RecursiveAll\""; 
5 голосов
/ 13 октября 2009

У меня нет изображения dev для тестирования, поэтому мне, возможно, придется пересмотреть это позже;но я думаю, что вы можете попробовать

query.ViewAttributes = "Scope=\"Recursive\""; 

Получение элементов позволит вам использовать SPUtility.GetUrlDirectory(url), чтобы получить путь к папке для данного элемента, и проанализировать иерархию папок оттуда.

3 голосов
/ 10 ноября 2009

Я решил это положить:

<QueryOptions>
<IncludeAttachmentUrls>True</IncludeAttachmentUrls>
<Folder/> </QueryOptions>

Как вариант запроса

Я нашел свой вопрос об этом при переполнении стека:

Как я могу рекурсивно выполнять итерацию через список общих точек с помощью веб-сервисов?

1 голос
/ 07 июля 2011

Это все еще кажется проблемой в SP 2010. Вот обходной код, который будет работать для 2007 или 2010, на основе этого сообщения на форуме MSDN , использующего веб-сервисы:

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);
}
1 голос
/ 01 ноября 2009

Если я удаляю другие условия из запроса, оставляя только FSObjType = 1, я получаю исключение COM "Не удается выполнить это действие. Пожалуйста, попробуйте снова."

Вы удалили теги <Or>, когда сделали это? Если нет, он не будет работать правильно.

В любом случае, это не решит вашу проблему. Вы пытались оставить запрос пустым? Это что-нибудь возвращает?

Я работал над чем-то похожим и столкнулся с проблемой , возможно, это несколько связано.

0 голосов
/ 07 января 2015
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());     
    }  
...