none
Linq to SharePoint - paging RRS feed

  • Вопрос

  • Здравствуйте. У меня есть подозрения, что при использовании linq to sharepoint нет возможности запрашивать данные постранично. Т.е. запрос вида 

    var zzz = ctx.XXX
      .Where(b => b.YYY != "xxx")
      .Skip(5)
      .Take(5);

    Не преобразуется в корректный CAML-запрос с разбиением на страницы, а будет выглядеть в виде условия Where и все. Skip и take - это будет linq to objects и сначала придут все записи удовлетворяющие условия, а затем уже в памяти будет выбрана нужная страница.

    Получается, что единственный способ - это по старинке писать свой CAML запрос, брать SPListItemCollectionPosition и в следующем запросе подсовывать ее снова. Вопрос: есть ли какие-нибудь способы нормального постраничного запроса к данным с помощью linq to sharepoint?

    23 апреля 2013 г. 10:28

Ответы

  • Михаил, спасибо за ссылку. То, что там написано я уже узнал и написал выше - оператор skip не переводится в CAML-запрос. Это linq to object. О чем в книге опять же и написано на странице 232 - про semi-efficent operators. И работает он так же, как и написано там: 

    "Semi-efficient means that the provider will probably additionally to the CAML query one or more
    LINQ to Object operations to fulfill the task. That means additional memory consumption and CPU
    resources. Such queries are also called two-stage queries."

    Вопрос несколько в другом - если ли вообще какой-нибудь нормальный вариант постраничной выборки с помощью linq to sharepoint?

    Я уже немного поэкспериментировал с linq - и пока что вывод неутешительный - он неэффективен в этом случае вообще никак.

    Запрос вида:

    Context.Entities.Take(10).Skip(5).OrderBy(i => i.Id);

    Преобразуется в 

    <View><Query></Query><ViewFields>...Перечисление полей...</ViewFields><RowLimit Paged="TRUE">10</RowLimit></View>

    Здесь только один вариант остается, который неэффективен, но прост.

    var entities = ctx.XXX
      .Where(b => b.Title!= "xxx")
      .Take((currentPageIndex + 1) * rowLimit) // Это будет преобразовано в CAML - RowLimit
      .Skip(currentPageIndex * rowLimit); // Это будет осуществлено с помощью linq to objects.


    • Изменено skyl1n3 23 апреля 2013 г. 12:37
    • Помечено в качестве ответа skyl1n3 26 апреля 2013 г. 11:25
    23 апреля 2013 г. 12:36
  • Ясно, значит вы уже больше чем просто подозреваете. К сожалению, судя по вашему опыту и первым ссылкам, что выдает гугл, похоже, что нормального решения с использованием LINQ нет.

    Также MSDN подтверждает, что Skip относится к Two-stage Queries.

    Если вдруг найдете что-то интересное, пожалуйста, обязательно сообщите, т.к. вопрос действительно интересный.

    • Предложено в качестве ответа daagon78 25 апреля 2013 г. 7:24
    • Помечено в качестве ответа skyl1n3 26 апреля 2013 г. 11:25
    23 апреля 2013 г. 14:11

Все ответы

  • Добрый день.

    Вы можете проверить какой CAML запрос фактически генерируется для LINQ, используя метод, предложенный Joerg Krause в его замечательной книге SharePoint 2010 as a Development Platform. Ссылка на часть книги в окрытом доступе. Интересующий участок кода на стр. 253 ("Understanding LINQ to CAML conversion"). 

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

    С уважением, Михаил (http://sp2013-blog.com)

    23 апреля 2013 г. 11:18
  • Михаил, спасибо за ссылку. То, что там написано я уже узнал и написал выше - оператор skip не переводится в CAML-запрос. Это linq to object. О чем в книге опять же и написано на странице 232 - про semi-efficent operators. И работает он так же, как и написано там: 

    "Semi-efficient means that the provider will probably additionally to the CAML query one or more
    LINQ to Object operations to fulfill the task. That means additional memory consumption and CPU
    resources. Such queries are also called two-stage queries."

    Вопрос несколько в другом - если ли вообще какой-нибудь нормальный вариант постраничной выборки с помощью linq to sharepoint?

    Я уже немного поэкспериментировал с linq - и пока что вывод неутешительный - он неэффективен в этом случае вообще никак.

    Запрос вида:

    Context.Entities.Take(10).Skip(5).OrderBy(i => i.Id);

    Преобразуется в 

    <View><Query></Query><ViewFields>...Перечисление полей...</ViewFields><RowLimit Paged="TRUE">10</RowLimit></View>

    Здесь только один вариант остается, который неэффективен, но прост.

    var entities = ctx.XXX
      .Where(b => b.Title!= "xxx")
      .Take((currentPageIndex + 1) * rowLimit) // Это будет преобразовано в CAML - RowLimit
      .Skip(currentPageIndex * rowLimit); // Это будет осуществлено с помощью linq to objects.


    • Изменено skyl1n3 23 апреля 2013 г. 12:37
    • Помечено в качестве ответа skyl1n3 26 апреля 2013 г. 11:25
    23 апреля 2013 г. 12:36
  • Ясно, значит вы уже больше чем просто подозреваете. К сожалению, судя по вашему опыту и первым ссылкам, что выдает гугл, похоже, что нормального решения с использованием LINQ нет.

    Также MSDN подтверждает, что Skip относится к Two-stage Queries.

    Если вдруг найдете что-то интересное, пожалуйста, обязательно сообщите, т.к. вопрос действительно интересный.

    • Предложено в качестве ответа daagon78 25 апреля 2013 г. 7:24
    • Помечено в качестве ответа skyl1n3 26 апреля 2013 г. 11:25
    23 апреля 2013 г. 14:11