ADO.NET Data Services 1.5: проекции

Недавно я начал тему, посвященную ADO.NET Data Services 1.5. Ранее я рассказал о общих тенденциях в этом проекте. Настало время поделиться некоторыми деталями. Здесь мы рассмотрим возможность создания проекций с помощью нового функционала, который появится в версии 1.5.

Необходимость создания проекций присутствовала еще в первой версии Astoria. Однако, как мы знаем, время и ресурсы ограничены, поэтому такая возможность появилась только в версии 1.5. Возможность создания проекций необходима в тех ситуациях, когда сущности, содержащиеся в коллекциях на сервисе содержат большое количество полей, а клиенту нужны только некоторые поля. В этом случае клиент вынужден загружать все поля этих объектов и тем самым генерировать лишний трафик и увеличивая время выполнения запросов.

В версии 1.0 предлагалось решить проблему путем разделения большой сущности на несколько маленьких и работать с ними отдельно. В этом случае, если необходимо все-таки получить доступ ко всем полям объекта создавалось представление (View), которое существовало в рамках сервиса в виде отдельной коллекции или сервисной операции. Безусловно, такой подход создает массу проблем. Например, в такой ситуации требуется приложить дополнительные усилия в случае редактирования таких коллекций. Кроме того, количество коллекций данных на сервисе может существенно увеличиться. В этом случае напрашивается логичное решение - "попросить" у сервиса вернуть не все поля объектов, а только те, которые необходимо прямо в URI.

В этом и заключается сущность работы механизма проекций в ADO.NET Data Services 1.5. Всякий раз, когда необходимо вернуть специфичный набор полей, мы задаем его явно в URI. При этом остальные поля игнорируются и не передаются клиенту.

Для выполнения подобного запроса появилось новое ключевое слово select. Например, если необходимо выбрать два поля ProductName и UnitPrice, то необходимо выполнить следующий запрос:

http://../WebDataService.svc/Products()?$select=ProductName,UnitPrice

Аналогично, если необходимо выбрать все поля, проигнорировав этот оператор или указав в качестве значения *:

http://../WebDataService.svc/Products()?$select=*

В некоторых ситуациях возможность получения проекций может быть нежелательна. В этом случае её можно отключить, используя дополнительные параметры конфигурирования сервиса. Для этого в классе DataServiceConfiguration появилось свойство DataServiceBehavior, которое позволяет настраивать поведение сервиса. В данном случае нас интересует свойство AcceptProjectionRequests.

public class WebDataService : DataService<NorthwindEntities>
{
    public static void InitializeService(DataServiceConfiguration config)
    {
        config.SetEntitySetAccessRule("*", EntitySetRights.All);

        config.DataServiceBehavior.AcceptProjectionRequests = true;
        config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;
    }
}

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

var client = new NorthwindEntities(new Uri(@"http://.../WebDataService.svc/"));
var q = from c in client.Categories
        select new { c.CategoryName, c.Description };

В этом случае также будет генерироваться запрос с оператором select в URI.

Кроме того, Astoria 1.5 решает еще одну проблему. Если клиенту необходимо обратиться к сервису для получения количества объектов в коллекции, то в ранних версиях было необходимо обратиться к сервису, получить сущности и посчитать их. Это могло существенно увеличивать трафик и время загрузки. В Astoria 1.5 появился дополнительный оператор count, который позволяет вычислить количество сущностей в рамках данного запроса на стороне сервиса. Для этого необходимо выполнить следующий запрос:

http://.../WebDataService.svc/Products()/$count

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

http://.../WebDataService.svc/Products()/$count?$filter=CategoryId gt 5

С точки зрения клиентского прокси, подобные URI будут генерироваться при вызове метода-расширения Count().

var client = new NorthwindEntities(new Uri(@"http://localhost:1076/WebDataService.svc/"));
var с = (from c in client.Categories
         where c.CategoryID > 5
         select c).Count();

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

public class WebDataService : DataService<NorthwindEntities>
{
    public static void InitializeService(DataServiceConfiguration config)
    {
        config.SetEntitySetAccessRule("*", EntitySetRights.All);

         config.DataServiceBehavior.AcceptCountRequests = true;
        config.DataServiceBehavior.AcceptProjectionRequests = true;
        config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;
    }
}

Подобной функциональности очень нехватало в первой версии ADO.NET Data Services и сейчас она была добавлена. И теперь мы можем использовать сервисы еще более эффективно.