Запрос большого внешнего списка с помощью CAML - PullRequest
7 голосов
/ 25 августа 2011

У меня есть внешний список SharePoint, который указывает на таблицу SQL записей на 100 000 записей. Я должен установить фильтр на операцию чтения списка, в противном случае список не работает. Время ожидания истекает при попытке вернуть полный список. Поэтому я добавил к операции фильтр Limit размера 200.

Проблема, с которой это связано, заключается в том, что когда я запрашиваю внешний список с использованием CAML, он ищет только 200 возвращенных записей, а не полный список.

Я бы хотел выполнить поиск по всему списку, но вернуть только максимум 200 подходящих записей.

Как мне лучше всего этого добиться?

Ответы [ 6 ]

2 голосов
/ 04 апреля 2012

Исходя из структуры вашего запроса и представленной здесь информации, в отчетах указывается, что <RowLimit> реализует желаемую функциональность:

Элемент RowLimit устанавливает предел строки для представления.

Синтаксис

Атрибуты

  • Paged: необязательный логический. ИСТИНА, если список поддерживает отображение большего количества элементов страница за страницей. Если ЛОЖЬ или не указан, то предел строки является абсолютным и нет ссылки, чтобы увидеть больше элементов.

Предостережения: обратите внимание на замечания в документации .

Вы, вероятно, уже проверили это для своих целей (ссылаясь на ваш вопрос: "Итак, я добавил в операцию фильтр ограничения размера 200". ). Итак, к следующему вопросу:

Проблема, которую это вызывает, заключается в том, что когда я запрашиваю внешний список, используя CAML выполняет поиск только по 200 возвращенным записям, а не по всему списку.

Это кажется странным. Если вы действительно используете <RowLimit> и документация верна:

Элемент RowLimit устанавливает предел строки для представления.

И

Тег <RowLimit> находится в определении схемы представления (прямого потомка) и поэтому не может быть вложен в тег <Query>.

Тогда должно быть верно, что ваш вложенный запрос выполняется перед вашим компонентом View , чтобы удовлетворить гарантию вашего оператора ограничения. Как следствие этого, это должно позволить вам выполнять подкачку результатов по остальной части набора, определенного вашим запросом.

Основываясь на этих принципах, мы могли бы построить постраничный запрос следующим образом:

<View>
    <RowLimit Paged='True'>200</RowLimit>
    <Method Name='ReadList'/>
    <Query>
        <Where>
            <Contains>
                    <FieldRef Name='Name'/>
                    <Value Type='Text'>{0}</Value>
            </Contains>
        </Where>
    </Query>
    <ViewFields>
    <FieldRef Name='Name'/>
    <FieldRef Name='Id'/>
    <FieldRef Name='BdcIdentity'/>                        
    </ViewFields>
</View>

Отмечая, как указано в документации, мы должны реализовать <PagedRowset>. Если это нежелательно, мы устанавливаем Paged='FALSE' выше.

Я, наверное, совершенно не в курсе, потому что это похоже на то, что вы уже пробовали. Но в интересах исчерпывающего планирования пространства, не повредит предложить это.

2 голосов
/ 03 апреля 2012

Может быть, этот ответ в SharePoint-Exchange может вам помочь.https://sharepoint.stackexchange.com/questions/31566/caml-and-external-list-pass-parameter-to-readlist-finder-method

Моя идея состоит в том, что вам, вероятно, потребуется изменить ваш метод readlist, чтобы убедиться, что он читает всю SQL-таблицу, но с параметром Where, указанным параметром filter в методе readlist,Что-то вроде

Псевдокод:

public static IEnumerable<YourEntity> ReadList(string param)
{
    if(string.IsNullOrEmpty(param) == true)
    {
        //Your original code thata only fetches the first 200 items
    }
    else
    {
        //Read your SQL-table with a Where ParamName = 'param' - clause
    }
}

Удачи

0 голосов
/ 08 апреля 2012

Если вы не можете вытащить всю таблицу SQL к своему внешнему списку, то у вас не будет возможности запросить этот набор данных так же, как и список SharePoint.

Тем не менее, я могу предложить решение, которое мы использовали для сценариев, практически идентичных этому, которое очень хорошо сработало для нас. В нашем сценарии мы запрашиваем базу данных Oracle, которая всегда возвращает большие наборы данных.

Подход, который мы выбрали, заключался в том, чтобы использовать шаблон «Фабрика», чтобы определить, каким образом следует запрашивать источник данных (список SharePoint, внешняя база данных и т. Д.).

Приведенные ниже примеры немного банальны, но они хорошо иллюстрируют концепцию.

Итак, начнем с интерфейса, который определяет, как будет запрашиваться набор данных и какие поля будут возвращены:

public interface IQueryData
{
    string ListToQuery { get; set; }
    List<MyResultObject> ExecuteQuery();
}

У вас будет пользовательский объект, представляющий одну запись, возвращаемую запросом

public class MyResultObject
{
    public string FileRef { get; }
    public string Title { get; set; }
    // any other fields you'd like to see potentially returned...
}

Тогда у вас будет поставщик данных, который реализует этот интерфейс для источника данных SQL

public class SqlDataProvider : IQueryData
{
    public string ListToQuery { get { return "BigSqlTable"; } }
    public List<MyResultObject> ExecuteQuery()
    {
        // query your external data source here...
        // populate a list of MyResultObject's from the result set and return it to the consumer
    }
}

У вас также есть поставщик данных, который реализует интерфейс для источника данных SharePoint

public class SharePointDataProvider : IQueryData
{
    public string ListToQuery { get { return "MySharePointList"; } }
    public List<MyResultObject> ExecuteQuery()
    {
        // query your SharePoint list here, using CAML, SharePoint object model, etc...
        // populate a list of MyResultObject's from the result set and return it to the consumer
    }
}

В этой реализации вы инкапсулировали логику и детали запроса в соответствующих поставщиках данных.

Теперь у вас есть фабрика, которая создает соответствующий поставщик данных (на основе указанного параметра ListToQuery):

public static class QueryDataProviderFactory
{
    public static IQueryData Build(string listToQuery)
    {
        switch(listToQuery)
        {
            case "BigSqlTable": return new SqlDataProvider(); break;
            case "MySharePointList": return new SharePointDataProvider(); break;
            // you can have many other implementations here that query your data sources in different manners
        }
    }
}

Наконец, вы будете использовать свою фабрику для инициирования запроса, передавая имя источника данных, который вы хотите запросить:

public List<MyResultObject> RunQuery()
{
    return QueryDataProviderFactory.Build("BigSqlTable").ExecuteQuery();
}

Этот шаблон сохраняет вашу внешнюю реализацию инкапсулированной в своем собственном поставщике данных и абстрагирует детали запроса от потребителя. Все, что нужно сделать потребителю, это указать имя списка, который он хочет запросить, и Factory решит, какую реализацию инициировать.

Вы даже можете сделать так, чтобы ваш интерфейс IQueryData реализовал обобщенные значения для дальнейшей расширяемости:

public interface IQueryData<T>
{
    string ListToQuery { get; set; }
    List<T> ExecuteQuery();
}

Это даст потребителю возможность указать тип объекта, который он ожидает вернуть.

Наш интерфейс данных запросов на самом деле имеет гораздо больше членов, которые добавляют еще больше точек расширения к нашим поставщикам запросов, но я подумал, что этот пример иллюстрирует эту точку в краткой и простой для понимания форме.

Просто хотел предложить это предложение, так как похоже на тот же сценарий, с которым мы столкнулись год или около того назад, и эта стратегия работает очень хорошо для нас.

0 голосов
/ 08 апреля 2012

Это один из сценариев, когда БКС без кода сам по себе не сокращает его.Либо реализуйте это как хранимую процедуру на сервере базы данных, либо используйте пользовательский соединитель BDC, встроенный в Visual Studio.

0 голосов
/ 06 апреля 2012

К сожалению, это известная проблема с запросом внешнего списка. Однако в веб-частях OOB подкачка страниц поддерживается с помощью XSLT. RowLimit работает только в XSLT, а не в CAML-запросе. Во внешнем списке нет разбиения на страницы на стороне сервера, а на стороне клиента, что означает, что SharePoint извлекает все данные, а затем устанавливает ограничение фильтра в представлении.

0 голосов
/ 25 августа 2011

Использовать свойство ListItemCollectionPosition из SPQuery и SPListItemCollection , например,

using (var web = site.OpenWeb("bla-bla"))
{
  var list = web.Lists["your_list"];
  var query = new SPQuery();
  query.Query = "your query";
  do
  {
    var items = list.GetItems(query);
    foreach(SPListItem item in items)
    {
      //your code
    }
    query.ListItemCollectionPosition = items.ListItemCollectionPosition;
  } while(query.ListItemCollectionPosition != null);
}
...