Camlex.Net 3.1: динамическое создание ViewFields для CAML запросов в Sharepoint

На этой неделе была выпущена новая версия 3.1 проекта Camlex.Net. В этом релизе была добавлена возможность динамически формировать ViewFields для CAML запросов. Недавно в разделе discussions на сайте проекта был задан вопрос о такой фиче. Это не первый случай, когда мы добавляем функциональность в проект на основе фидбека, который мы получаем от разработчиков, и по мере возможностей и наличия свободного времени развиваем наш open source проект. Кроме этого мы сами интенсивно используем его в работе, поэтому стараемся добавлять функциональность по мере поступления новых запросов, чтобы проект был все более полезен в разработке для Sharepoint.

В версии 3.1 были добавлены следующие новые методы:

public interface IQueryEx : IQuery
{
    ...
    string ViewFields(IEnumerable<string> titles);
    string ViewFields(IEnumerable<string> titles, bool includeViewFieldsTag);
    string ViewFields(IEnumerable<Guid> ids);
    string ViewFields(IEnumerable<Guid> ids, bool includeViewFieldsTag);
}

Таким образом, теперь вы можете динамически сформировать список имен полей или идентификаторов (типа Guid) и передать его в Camlex. На основе этого списка Camlex сформирует CAML для ViewFields. Например, используя следующий код:

var items = new [] { "Title", "FileRef" };

string caml = Camlex.Query().ViewFields(items);

вы получите следующий CAML:

<FieldRef Name=\"Title\" />
<FieldRef Name=\"FileRef\" />

В приведенном выше примере список имен полей предопределен. Но в реальном приложении вы можете сформировать его динамически на основе каких-либо условий.

Далее я бы хотел рассказать о некоторых интересных (на мой взгляд 🙂 ) деталях реализации. Можете смело пропустить оставшуюся часть статьи, если это вам не интересно.

До новой версии в интерфейсе IQueryEx были следующие методы (они остались и в новой версии):

public interface IQueryEx : IQuery
{
    string ViewFields(Expression<Func<SPListItem, object>> expr);
    string ViewFields(Expression<Func<SPListItem, object>> expr, bool includeViewFieldsTag);
    string ViewFields(Expression<Func<SPListItem, object[]>> expr);
    string ViewFields(Expression<Func<SPListItem, object[]>> expr, bool includeViewFieldsTag);
}

С их помощью ViewFields можно сформировать с помощью следующего кода:

string caml =
    Camlex.Query().ViewFields(x => new [] { x["Title"], x["FileRef"] });

Чтобы создать список динамически вам самим пришлось бы написать код, который создает выражение (NewArrayInit) на основе списка имен полей (“Title” и “FileRef” в этом примере). Это не то, чем надо заниматься при работе над бизнес задачей. Библиотека должна делать это за нас. Когда я думал над реализацией, я хотел использовать существующие методы, чтобы не писать много нового кода. Чтобы это сделать надо было ответить на вопрос: как, имея массив строк или Guid-ов (напр. {“Title”, “FileRef”}), создать лямбда выражение x => new [] { x[“Title”], x[“FileRef”] }? Решение получилось довольно элегантным:

public string ViewFields(IEnumerable<string> titles, bool includeViewFieldsTag)
{
    ...
    return this.ViewFields(this.createExpressionFromArray(titles), includeViewFieldsTag);
}

public string ViewFields(IEnumerable<Guid> ids, bool includeViewFieldsTag)
{
    ...
    return this.ViewFields(this.createExpressionFromArray(ids), includeViewFieldsTag);
}

private Expression<Func<SPListItem, object[]>>
createExpressionFromArray<T>(IEnumerable<T> items)
{
    return Expression.Lambda<Func<SPListItem, object[]>>(
        Expression.NewArrayInit(typeof(object),
        (IEnumerable<Expression>)items.Select(
            t => Expression.Call(Expression.Parameter(typeof(SPListItem), "x"),
                typeof(SPListItem).GetMethod("get_Item", new[] { typeof(T) }),
                new[] { Expression.Constant(t) })).ToArray()),
        Expression.Parameter(typeof(SPListItem), "x"));
}

Т.е. для каждого элемента элемента списка items создается выражение – доступ к индексеру x[item], которое затем добавляется в список инициализации NewArrayInit. Обратите внимание на вызов ToArray() – без него ленивое LINQ выражение не будет развернуто и инициализация NewArrayInit упадет с исключением.

Это все, что я хотел рассказать о новом релизе. В данный момент у нас уже есть достаточно внушительный todo list, но мы всегда открыты новым предложениям и идеям. Пишете о них на сайте проекта на codeplex.

Реклама

Об авторе sadomovalex

Старший инженер, team lead, консультант. Работаю в стеке .Net. Последние несколько лет занимаюсь разработкой enterprise приложений под Sharepoint, чему и будет в основном посвящена тематика этого блога. Также активно использую и интересуюсь ASP.Net MVC, DDD, TDD, Agile. Активно участвую в жизни многих профессиональных сообществ, SPb .Net UG, SPb ALT.Net, rsdn, Finland SP UG и др.
Запись опубликована в рубрике CAML, Camlex.NET, Sharepoint. Добавьте в закладки постоянную ссылку.

Добавить комментарий

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

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход / Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход / Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход / Изменить )

Google+ photo

Для комментария используется ваша учётная запись Google+. Выход / Изменить )

Connecting to %s