Visual Studio

Entity Framework 4.0 и WCF Data Services 4.0 в Visual Studio 2010

Элиза Фласко

Загрузка образца кода

Среди множества новинок и усовершенствований в Visual Studio 2010 появились давно ожидаемые Entity Framework 4.0 и WCF Data Services 4.0 (ранее ADO.NET Data Services), которые совместно упрощают моделирование, использование и создание данных.

Главное предназначение Entity Framework 4.0 (EF 4.0) — поддержка и упрощение двух сценариев: разработки приложений, ориентированных на конкретные предметные области, и традиционной разработки, ориентированной на данные. В нем появились такие возможности, как разработка с модели (model first development), при которой вы сначала создаете модель, а потом генерируете адаптированный под нее код на T-SQL, поддержка внешних ключей (foreign keys), отложенной загрузки (lazy loading) и настройки генерируемого кода для сущностей.

Смысл WCF Data Services 4.0 в поддержке обновлений Open Data Protocol (odata.org) и его новой функциональности, в том числе двухстороннего связывания с данными для Windows Presentation Foundation (WPF) и Silverlight, механизма Server-Driven Paging (пролистывания страниц, управляемого сервером), расширенной поддержке больших двоичных объектов (binary large object, BLOB) и проекций.

Используя приложение-пример MyBlog в качестве основы, мы исследуем новые возможности EF и WCF Data Services, а также рассмотрим, как сочетание этих технологий упрощает моделирование и использование данных. Этот пример будет одновременно и веб-приложением ASP.NET, позволяющим только читать сообщения в блоге, и Silverlight-клиентом для администратора блога, который сможет редактировать сообщения. Я начну с приложения, использующего Model First для создания модели данных сущности (Entity Data Model, EDM), а затем сгенерирую базу данных и код для взаимодействия с этой базой данных. В примере также будет использоваться Data Services Update for Silverlight 3 CTP 3.

Приступая к работе с EF 4.0

Начнем с проекта веб-приложения ASP.NET. (Мое приложение называется BlogModel; вы можете скачать сопутствующий исходный код по ссылке code.msdn.microsoft.com/mag201004VSData.) Чтобы начать работу с EF, я добавляю ADO.NET EDM с помощью мастера Add New Item, выбираю модель Empty, которой присваиваю имя BlogModel. Щелкнув правой кнопкой мыши на пустой области дизайнера и выбрав Properties, вы увидите имя Entity Container по умолчанию — в данном случае BlogModelCon­tainer. Первым делом я сменю его имя на BlogContext, а потом создам модель.

MyBlog требует наличия трех сущностей, которым я присвоила имена Blog, Post и Tag (рис. 1) Чтобы создать их, я перетаскивала Entity из окна инструментария на поверхность дизайнера, щелкала правой кнопкой мыши и выбирала Properties для редактирования свойств сущности. Мне также понадобится несколько скалярных свойств в каждой сущности (выбираем из того же контекстного меню команды Add | Scalar Property).

image: Blog, Post and Tag Entities and Associated Property Settings

Рис. 1 Сущности Blog, Post и Tag и настройка связанных с ними свойств

Поддержка внешнего ключа в EF 4.0

Далее я добавлю отношения между этими сущностями. Щелкните правой кнопкой мыши на поверхности дизайнера и выберите Add | Association, как показано на рис. 2. EF теперь поддерживает внешние ключи, что позволяет включать в сущность свойства, выступающие в роли внешнего ключа. Заметьте, что добавление отношения привело к появлению в сущности Post свойства BlogBlogID (внешнего ключа).

image: Associations Between Blog, Post and Tag Entities

Рис. 2 Связи между сущностями Blog, Post и Tag

Включение свойств внешнего ключа в сущности упрощает ряд шаблонов кодирования ключа, в том числе связывание с данными, динамические данные, управление параллельной обработкой и разработку промежуточного уровня в распределенных приложениях. Например, если я выполняю привязку к сетке, которая показывает продукты, и у меня есть в сетке свойство CategoryID (значение внешнего ключа), но нет соответствующего объекта Category, то поддержка внешнего ключа в EF означает, что мне больше не нужно выполнять специальный запрос для получения этого объекта.

Model First в EF 4.0

Теперь, когда модель построена (рис. 3), приложению нужна база данных. В этом случае MyBlog является новым приложением, и у него еще нет базы данных. Я не хочу сама создавать базу данных — я предпочла бы, чтобы это сделали за меня.И это возможно. С поддержкой Model First в EF 4.0 среда Visual Studio теперь может генерировать не только код для сущностей, но и базу данных на основе только что созданной модели.

image: Blog Model

Рис. 3 Модель блога

Сначала нужно создать пустую базу данных, к которой я применю сгенерированную схему. Для этого открываем Server Explorer, щелкаем правой кнопкой мыши узел Data Connections и выбираем Create New SQL Server Database (рис. 4). Создав пустую базу данных, щелкаем правой кнопкой мыши поверхность дизайнера модели и выбираем Generate Database from Model. Пройдя через экраны мастера Generate Database, мы получим файл Blog­Model.edmx.sql. При открытом новом файле достаточно щелкнуть правой кнопкой мыши этот файл и запустить SQL-сценарий, который создаст схему для базы данных.

image: Create a New Empty Database and Generate Database Schema from EDM

Рис. 4 Создание новой пустой базы данных и генерация ее схемы на основе EDM

Генерация собственного кода с помощью EF 4.0

К этому моменту можно предпринять ряд следующих шагов, один из которых — настройка кода, генерируемого Entity Framework, на основе шаблонов T4 (T4 Templates). Хотя EF в Visual Studio 2008 SP1 предоставлял некоторые возможности по настройке генерации кода, ими было трудно пользоваться. Теперь EF 4.0 поддерживает шаблоны T4, что дает гораздо более простой, гибкий и эффективный способ настройки генерируемого кода.

Чтобы добавить в проект новый шаблон T4, щелкните правой кнопкой мыши поверхность дизайнера сущностей (Entity Designer) и выберите Add Code Generation Item. Отсюда выберите любой установленный на данный момент шаблон для использования в качестве отправной точки или просмотрите список доступных шаблонов в Online Gallery. Чтобы взять в этом проекте за отправную точку шаблон EF по умолчанию, я выберу шаблон ADO.NET EntityObject Generator; по умолчанию этому шаблону присваивается имя Model1.tt. Когда мы добавляем шаблон генерации кода таким способом, EF автоматически отключает стандартную генерацию кода для модели. Сгенерированный код удаляется из BlogModel.Designer.cs и размещается в Model1.cs. Теперь шаблон можно редактировать для настройки сущностей, которые он будет генерировать, и при каждом сохранении файла .tt, зависимый код будет генерироваться заново. Подробнее о редактировании и использовании шаблонов T4 в EF 4.0 см. в блоге группы ADO.NET по ссылке blogs.msdn.com/adonet.

Использование сущностей POCO в EF 4.0

Visual Studio 2008 SP1 накладывает ряд ограничений на классы сущностей, как минимум, затрудняющие создание классов, которые были бы по-настоящему независимы от проблем сохранения. Одна из функций EF 4.0, которые наиболее часто просили ввести, — возможность создания типов Plain Old CLR Object (POCO) для сущностей, которые работают в EF и не накладывают тех ограничений на типы, как в Visual Studio 2008 SP1.

Вернемся к примеру MyBlog. Я создам POCO-объекты для трех сущностей:Blog, Post и Tag. Во-первых, нужно отключить генерацию кода и удалить файл .tt, который был добавлен в предыдущем разделе. Чтобы проверить свойства модели, щелкните правой кнопкой мыши поверхность Entity Designer. Как показано на рис. 5, для отключения генерации кода надо установить свойство Code Generation Strategy в None.

image: Code Generation Strategy Property

Рис. 5 Свойство Code Generation Strategy

Заметьте, что это свойство устанавливается в None автоматически, если вы добавляете в проект Code Generation Item (T4 Template). Если в проекте на этот момент существует файл TT, вам придется удалить его до использования POCO-объектов. И с этого момента можно добавлять классы POCO-объектов: Blog.cs, Post.cs и Tag.cs (рис. 6, 7 и 8).

Рис. 6 POCO-объект для сущности Blog

public class Blog

{

  public intBlogID

  {

    get;

    set;

  }

  public string Name

  {

    get;

    set;

  }

  public string Owner

  {

    get;

    set;

  }

  public List<Post> Posts

  {

    get { return _posts; }

    set { _posts = value; }

  }

  List<Post> _posts = new List<Post>();

}

Рис. 7 POCO-объект для сущности Tag

public class Tag

{

  public int TagID

  {

    get;

    set;

  }

  public string Name

  {

    get;

    set;

  }

  public List<Post> Posts

  {

    get { return _posts; }

    set { _posts = value; }

  }

  List<Post> _posts = new List<Post>();

}

Рис. 8 POCO-объект для сущности Post

public class Post

{

  public int PostID

  {

    get;

    set;

  }

  public DateTime CreatedDate

  {

    get;

    set;

  }

  public DateTime ModifiedDate

  {

    get;

    set;

  }

  public string Title

  {

    get;

    set;

  }



  public string PostContent

  {

    get;

    set;

  }

  public Blog Blog

  {

    get;

    set;

  }

  public int BlogBlogID

  {

    get;

    set;

  }

  public Boolean Public

  {

    get;

    set;

  }

  public List<Tag> Tags

  {

    get { return _tags; }

    set { _tags = value; }

  }

  private List<Tag> _tags = new List<Tag>();

}

Наконец, нужно создать класс контекста, который во многом похож на реализацию ObjectContext, созданную в стандартном процессе генерации кода, но я назову его BlogContext. Он будет наследовать от класса ObjectContext. Контекст — это класс, поддерживающий сохранение (persistence-aware). Он позволит формировать запросы, материализовать сущности и сохранять изменения обратно в базу данных (рис. 9).

Рис. 9 BlogContext

public class BlogContext : ObjectContext 

{

  public BlogContext() 

    : base("name=BlogContext", "BlogContext") 

      { 

      }

  public ObjectSet<Blog> Blogs 

  {

    get 

    {

      if (_Blogs == null) 

      { 

         _Blogs = 

           base.CreateObjectSet<Blog>("Blogs"); 

      }

    return _Blogs; 

  } 

}

private ObjectSet<Blog> _Blogs;

public ObjectSet<Post> Posts 

{

  get 

  {

    if (_Posts == null) 

    { 

      _Posts = 

        base.CreateObjectSet<Post>("Posts"); 

    }

  return _Posts; 

  } 

}

private ObjectSet<Post> _Posts;

public ObjectSet<Tag> Tags 

{

  get 

  {

    if (_Tags == null) 

  { 

    _Tags = base.CreateObjectSet<Tag>("Tags"); 

  }

  return _Tags; 

  } 

}

private ObjectSet<Tag> _Tags; 

}

Отложенная загрузка

В Visual Studio 2008 SP1 инфраструктура EF поддерживала два основных способа загрузки связанных сущностей, и оба гарантировали, что приложение обращается к базе данных, только если используется метод Load для явной загрузки связанных сущностей или метод Include для загрузки связанных сущностей в рамках запроса. Так вот, теперь EF 4.0 поддерживает отложенную загрузку (lazy loading). Если выполнение явной загрузки не требуется, вы можете использовать отложенную для загрузки связанных сущностей при первом обращении к навигационному свойству. В Visual Studio 2010 с этой целью навигационные свойства преобразованы в виртуальные.

В примере MyBlog открытое свойство List<Post> Posts в Blog.cs и Tag.cs превратилось бы в открытое виртуальное List<Post> Posts, а открытое свойство List<Tag> Tags в Post.cs стало бы открытым виртуальным List<Tag> Tags. В период выполнения EF создала бы прокси-тип, которому известно, как выполнять загрузку, поэтому никаких дополнительных изменений в коде не понадобилось бы. Однако, поскольку в примере MyBlog используется технология WCF Data Services для доступа к сущностям через сервис Open Data Protocol (OData), в этом приложении не нужна отложенная загрузка.

Создание WCF-сервиса данных в Visual Studio 2010

MyBlog использует преимущества решения «почти под ключ», предоставляемого WCF Data Services; это решение обеспечивает доступ к OData-сервису через EDM и включает Silverlight-клиент для администратора блога, использующий этот OData-сервис. Open Data Protocol является стандартом обмена данными и способствует созданию эффективной экосистемы взаимодействия для потребителей данных (клиентов) и источников этих данных (служб), давая возможность большему количеству приложений использовать более широкий набор данных.

После создания EDM и базы данных добавить к приложению новый WCF-сервис данных достаточно легко:с помощью мастера Add New Item wizard.Я добавила такой сервис и назвала его BlogService. Эта операция приводит к генерации файла BlogService.svc, в котором содержится скелет сервиса; он настраивается на EDM через ранее созданный контекст. Поскольку служба по умолчанию полностью заблокирована, обращение к наборам сущностей, которые должны быть доступны, нужно разрешить явным образом с помощью config.SetEntitySetAccessRule. С этой целью для каждого EntitySet, к которому нужно открыть доступ, настраивается правило, как показано на рис. 10.

Рис. 10 BlogService.svc

public class BlogService : DataService<BlogContext> 

{ 

    // This method is called only once to initialize service-wide policies. 

    public static void InitializeService(DataServiceConfiguration config) 

    { 

       // TODO: set rules to indicate which entity sets and service 

       // operations are visible, updatable, etc. 

       // Examples: 

       config.SetEntitySetAccessRule("Blogs", EntitySetRights.All); 

       config.SetEntitySetAccessRule("Posts", EntitySetRights.All); 

       config.SetEntitySetAccessRule("Tags", EntitySetRights.All); 

       // config.SetServiceOperationAccessRule("MyServiceOperation", 

       // ServiceOperationRights.All); 

       config.DataServiceBehavior.MaxProtocolVersion =      

       DataServiceProtocolVersion.V2; 

    } 

}

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

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

Рис. 11 Перехватчик запроса

// returns only public posts and posts owned by the current user 

[QueryInterceptor("Posts")]

public Expression<Func<Post, bool>>OnPostQuery() 

{

  return p =>p.Public == true ||

  p.Blog.Owner.Equals(HttpContext.Current.User.Identity.Name); 

}

// returns only the blogs the currently logged in user owns 

[QueryInterceptor("Blogs")]

public Expression<Func<Blog, bool>>OnBlogQuery() 

{

  return b =>

  b.Owner.Equals(HttpContext.Current.User.Identity.Name); 

}

Использование WCF-сервиса данных в Silverlight

Подробности создания Silverlight UI выходят за рамки этой статьи, поэтому я лишь в двух словах упомяну о некоторых из них. Прежде чем рассказывать, как подключить сервис данных к приложению Silverlight, я добавляю к проекту новое приложение Silverlight, которое содержит стандартную Silverlight-страницу MainPage.xaml. В нее я включаю DataGrid, Combo­Box, Button и пару меток. Получив скелет приложения Silverlight (рис. 12), можно подключить службу данных.

image: Basic Layout of MyBlog Silverlight

Рис. 12 Базовая структура приложения Silverlight для администратора (MyBlog)

Для начала приложению Silverlight нужны объекты, представляющие каждую сущность, которая определена в сервисе данных. Мастер Add Service Reference в Visual Studio позволяет автоматически сгенерировать клиентские классы для сервиса данных. (Заметьте, что для использования Add Service Reference нужно временно отключить проверки авторизации, реализованные в сервисе, чтобы у мастера был полный доступ к сервису. Я указала мастеру Add Service Reference базовый URI сервиса, который для MyBlog выглядит как localhost:48009/BlogService.svc.)

Связывание с данными в WCF Data Services 4.0

Поддержка связывания с данными в WCF Data Services 4.0 улучшена, и в клиентскую библиотеку добавлен новый тип-набор DataServiceCollection, расширяющий ObservableCollection. Однако в Silverlight 3 связывание с данными по умолчанию отключается, когда в проект добавляется ссылка на сервис. Поэтому, чтобы задействовать преимущества новой функциональности связывания с данными в WCF Data Services, нужно самостоятельно включить это связывание, а ссылку на сервис — обновить. В Solution Explorer щелкните кнопку Show All Files и раскройте элемент BlogService в узле Service References.  Дважды щелкните файл сопоставлений Reference.datasvc и замените элемент Parameters фрагментом XML-кода, показанного ниже:

<Parameters>

  <Parameter Name="UseDataServiceCollection" Value="true" />

  <Parameter Name="Version" Value="2.0" />

</Parameters>

Присваивание параметру UseDataServiceCollection значения true приводит к автоматической генерации типов на клиентской стороне, реализующих интерфейсы INotifyProperty­Changed и INotifyCollectionChanged. Это означает, что любые изменения, внесенные в содержимое DataServiceCollection или в сущности в наборе, отражаются в клиентском контексте. Это же подразумевает, что при повторном запросе сущности в наборе любые изменения в ней отражаются в сущностях, содержащихся в DataServiceCollection. И еще:поскольку DataServiceCollection реализует стандартные интерфейсы связывания, его можно привязать как DataSource к большинству элементов управления WPF и Silverlight.

Но вернемся к примеру MyBlog.Следующий шаг — создание соединения с сервисом; для этого создается новый DataServiceContext и с его помощью запрашивается сервис. На рис. 13 показаны файлы MainPage.xaml и MainPage.xaml.cs; здесь видно, как создается новый DataService­Context и запрашиваются все блоги от службы (в данном случае сервис возвращает все блоги, принадлежащие текущему пользователю), которые привязываются к ComboBox в приложении Silverlight.

Рис 13 MainPage.xaml и MainPage.xaml.cs

MainPage.xaml

<Grid x:Name="LayoutRoot" Background="White" Width="618">

  <data:DataGrid Name="grdPosts" AutoGenerateColumns="False" 

  Height="206" HorizontalAlignment="Left"Margin="17,48,0,0"

  VerticalAlignment="Top" Width="363" ItemsSource="{Binding Posts}">

    <data:DataGrid.Columns>

      <data:DataGridTextColumn Header="Title" Binding="{Binding Title}"/>

      <data:DataGridCheckBoxColumn Header="Public" 

      Binding="{Binding Public}"/>

      <data:DataGridTextColumn Header="Text" 

      Binding="{Binding PostContent}"/>

    </data:DataGrid.Columns>

  </data:DataGrid>

  <Button Content="Save" Height="23" HorizontalAlignment="Left" 

  Margin="275,263,0,0" Name="btnSave" VerticalAlignment="Top"

  Width="75" Click="btnSave_Click_1" />

  <ComboBox Height="23" HorizontalAlignment="Left" 

  Margin="86,11,0,0" Name="cboBlogs" VerticalAlignment="Top"

  Width="199" ItemsSource="{Binding}" DisplayMemberPath="Name" 

  SelectionChanged="cboBlogs_SelectionChanged" />

  <dataInput:Label Height="50" HorizontalAlignment="Left" 

  Margin="36,15,0,0" Name="label1" 

  VerticalAlignment="Top"Width="100" Content="Blogs:" />

  <dataInput:Label Height="17" HorizontalAlignment="Left" 

  Margin="17,263,0,0" Name="lblCount" VerticalAlignment="Top"

  Width="200" Content="Showing 0 of 0 posts"/>

  <Button Content="Load More Posts" Height="23" HorizontalAlignment="Left" Margin="165,263,0,0" Name="btnMorePosts"

VerticalAlignment="Top" Width="100" Click="btnMorePosts_Click" />

</Grid>

MainPage.xaml.cs

public MainPage() 

{

  InitializeComponent(); 

  svc = new BlogContext(new Uri("/BlogService.svc", UriKind.Relative)); 

  blogs = new DataServiceCollection<Blog>(svc);

  this.LayoutRoot.DataContext = blogs;

  blogs.LoadCompleted += 

  new EventHandler<LoadCompletedEventArgs>(blogs_LoadCompleted);

  var q = svc.Blogs.Expand("Posts");

  blogs.LoadAsync(q); 

}

void blogs_LoadCompleted(object sender, LoadCompletedEventArgs e) 

{

  if (e.Error == null) 

  {

    if (blogs.Count> 0) 

    {

      cboBlogs.SelectedIndex = 0; 

    } 

  } 

}

Для связывания DataGrid добавляется метод cboBlogs_SelectionChanged():

private void cboBlogs_SelectionChanged(object sender, SelectionChangedEventArgs e) 

{

  this.grdPosts.DataContext = ((Blog)cboBlogs.SelectedItem); 

}

Этот метод вызывается всякий раз, когда в ComboBox происходит смена текущего выбранного элемента.

Последний элемент, который нужно подключить в этом приложении Silverlight, — кнопка Save.Для этого добавляется метод btnSave_Click, который вызывает SaveChanges в DataServiceContext, как показано на рис. 14.

Рис. 14 Сохранение изменений обратно в базе данных

private void btnSave_Click_1(object sender, RoutedEventArgs e) 

{

  svc.BeginSaveChanges(SaveChangesOptions.Batch, OnChangesSaved, svc); 

}

private void OnChangesSaved(IAsyncResult result) 

{

  var q = result.AsyncState as BlogContext;

  try 

  {

    // Complete the save changes operation

    q.EndSaveChanges(result); 

  }

  catch (Exception ex) 

  {

    // Display the error from the response.

    MessageBox.Show(ex.Message); 

  } 

}

Механизм Server-Driven Paging

Часто возникает необходимость в ограничении общего количества результатов, возвращаемых сервером в ответ на конкретный запрос, чтобы избежать случайной выборки приложением крайне больших объемов данных. Механизм Server-Driven Paging в WCF Data Services 4.0 позволяет автору сервиса задать ограничения индивидуально для каждого набора на общее количество сущностей, которые возвращает сервис для каждого запроса.Для этого задается свойство SetEntitySetPageSize в методе InitializeService для каждого набора сущностей. Кроме ограничения количества сущностей, возвращаемых для каждого набора, сервис данных предоставляет клиенту ссылку «далее» — URI, указывающий, как клиент должен извлекать следующий набор сущностей, в виде элемента AtomPub<link rel="next">.

Вернемся к примеру MyBlog.Я указываю в свойстве SetEntitySetPage­Size моего сервиса ограничение для набора сущностей Posts пятью результатами:

config.SetEntitySetPageSize("Posts", 5);

Это ограничит количество сущностей, возвращаемых сервисом при запросе Posts. Я присваиваю здесь свойству SetEntitySetPageSize небольшое значение, чтобы проиллюстрировать, как работает это средство; в целом, в приложении задают такой предел, которого не достигает большинство клиентов.

Я также добавляю новую кнопку в приложение, чтобы пользователь мог запрашивать следующую страницу сущностей Posts от сервиса. В следующем фрагменте кода метод btnMorePosts_Click обращается к следующему множеству Posts:

private void btnMorePosts_Click(object sender, RoutedEventArgs e) 

{

  Blog curBlog = cboBlogs.SelectedItem as Blog;

  curBlog.Posts.LoadCompleted += new   

    EventHandler<LoadCompletedEventArgs>(Posts_LoadCompleted);

  curBlog.Posts.LoadNextPartialSetAsync(); 

}

Счетчик строк

Одна из функций, введения которых наиболее часто просили после выпуска ADO.NET Data Services в Visual Studio 2008 SP1, была возможность определения общего количества сущностей в некоем множестве без реальной выборки их из базы данных. В WCF Data Services 4.0 с этой целью была добавлена функция подсчета строк (Row Count).

При создании запроса на клиенте можно вызывать метод IncludeTotalCount, который включает в ответ поле счетчика. Это значение доступно через свойство TotalCount объекта QueryOperationResponse (рис. 15).

Рис. 15 Использование счетчика строк

private void cboBlogs_SelectionChanged(object sender, SelectionChangedEventArgs e) 

{

  Blog curBlog = this.cboBlogs.SelectedItem as Blog;

  this.grdPosts.DataContext = curBlog;

  var q = (from p in svc.Posts.IncludeTotalCount()

  where p.BlogBlogID == curBlog.ID

  select p) as DataServiceQuery<Post>;

  curBlog.Posts.LoadCompleted += new     

  EventHandler<LoadCompletedEventArgs>(Posts_LoadCompleted);

  curBlog.Posts.LoadAsync(q); 

}

void Posts_LoadCompleted(object sender, LoadCompletedEventArgs e) 

{

  if (e.Error == null) 

  {

    Blog curBlog = cboBlogs.SelectedItem as Blog;

    totalPostCount = e.QueryOperationResponse.TotalCount;

    string postsCount = string.Format("Displaying {0} of {1} posts",

    curBlog.Posts.Count, totalPostCount);

    this.lblCount.Content = postsCount;

    curBlog.Posts.LoadCompleted -= Posts_LoadCompleted; 

  } 

}

Проекции

Еще одна давно ожидаемая функция в WCF Data Services 4.0 — проекции.Это возможность указывать подмножество свойств сущности, возвращаемых запросом, что позволяет в приложениях оптимизировать использование пропускной способности и занимаемой памяти. В Visual Studio 2010 формат Data Services URI был расширен для включения параметра запроса $select, чтобы клиенты могли указывать подмножество свойств, возвращаемых запросом.  Например, в случае MyBlog я могла бы запрашивать все Posts и получать проекцию только свойств Title и PostContent, используя следующий URI:  BlogService.svc/Posts?$select=Title,PostContent. На клиентской стороне теперь можно использовать и LINQ для запроса с проекциями.

Где узнать больше

В этой статье освещен круг вопросов, вполне достаточный, чтобы начать работу с Entity Framework 4.0 и WCF Data Services 4.0 в Visual Studio 2010. Возможно, вас интересует ряд других новых средств.Более подробные сведения вы найдете в центре MSDN Data Development по ссылке msdn.microsoft.com/data.  

Элиза Фласко (Elisa Flasko) — менеджер программ в группе Data Programmability в Microsoft, специализируется на технологиях ADO.NET Entity Framework, WCF Data Service, M, Quadrant и SQL Server Modeling Services. С ней можно связаться через ее блог blogs.msdn.com/elisaj..

Выражаем благодарность за рецензирование статьи эксперту Люку Хобану (Luke Hoban). Джефф Дерштадт (Jeff Derstadt) и Майк Фласко (Mike Flasko)