воскресенье, 9 декабря 2012 г.

CAML-запросы с расширенной фильтрацией по пользователям и группам

Давно забытое старое!
Речь сегодня пойдёт об использовании тега Membership в CAML-запросах.
Этого тега нет ни в CAML Builder ни в CAML Designer, поэтому не все знают о его существовании.
Тем не менее, на MSDN присутствует описание этого тега, хоть и без примеров.
Итак, запрос с использованием этого тега может выглядеть так:
<Where>
  <Membership Type='CurrentUserGroups'>
    <FieldRef Name='Person' />
  </Membership>
</Where>

Тег Membership содержит атрибут Type, указывающий тип фильтрации:
  • SPWeb.AllUsers – Выбор элементов, содержащих в указанном поле пользователя
  • SPWeb.Groups - Выбор элементов, содержащих в указанном поле группу
  • SPWeb.Users - Выбор элементов, содержащих в указанном поле пользователя, не содержащегося в группе 
  • CurrentUserGroups - Выбор элементов, содержащих в указанном поле группу, в которую входит текущий пользователь
  • SPGroup - Выбор элементов, содержащих в указанном поле указанную группу; группа (ID) указывается отдельным атрибутом тега Membership: ID=’1’

Пример.
Допустим имеем такой список:
image

Тестовое (консольное) приложение:
static void Main(string[] args)
{
    var values = new Dictionary<string, int>
        {
            {"SPWeb.AllUsers", 7},
            {"SPWeb.Groups", 7},
            {"SPWeb.Users", 7},
            {"CurrentUserGroups", 7},
            {"SPGroup", 1073741823}
        };

    foreach (var value in values)
        RunQuery(value.Key, value.Value);

    Console.WriteLine();
    Console.WriteLine("Completed!");
    Console.ReadKey(true);
}

static void RunQuery(string membership, int userId)
{
    using (var site = new SPSite("http://x33/", GetUserToken(userId)))
    {
        using (var web = site.OpenWeb())
        {
            var list = web.Lists["CAMLTest"];

            var query = new SPQuery {Query = string.Format("<Where><Membership Type='{0}' ID='4'><FieldRef Name='Person' /></Membership></Where>", membership)};
            var items = list.GetItems(query);

            Console.WriteLine("Current user: {0}; Membership type: {1}; Items count: {2}", web.CurrentUser.Name, membership, items.Count);
            items.Cast<SPListItem>().ToList().ForEach(li => Console.WriteLine("ID - {0}; Title - {1}; Person - {2}", li.ID, li.Title, li["Person"]));
            Console.WriteLine("----------");
            Console.WriteLine();
        }
    }
}

static SPUserToken GetUserToken(int userId)
{
    using (var site = new SPSite("http://x33/"))
    {
        using (var web = site.OpenWeb())
        {
            return web.SiteUsers.GetByID(userId).UserToken;
        }
    }
}

Результат работы приложения:
image

Наиболее интересный тип фильтрации: CurrentUserGroups.
Допустим в списке у нас проставлены группы. С помощью данного запроса мы можем выбрать все элементы, которые содержат группу текущего пользователя, т.е. элементы, доступные участником тех же групп, что и для текущего пользователя! (аналог фильтрации по аудиториям)

2 комментария:

  1. Круть! Ещё мало кто знает, что в SharePoint 2010 появился предикат IN, INCLUDES и NOTINCLUDES (http://msdn.microsoft.com/en-us/library/ms467521.aspx)

    ОтветитьУдалить