На этой неделе была выпущена новая версия 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.