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 по умолчанию — в данном случае BlogModelContainer. Первым делом я сменю его имя на BlogContext, а потом создам модель.
MyBlog требует наличия трех сущностей, которым я присвоила имена Blog, Post и Tag (рис. 1) Чтобы создать их, я перетаскивала Entity из окна инструментария на поверхность дизайнера, щелкала правой кнопкой мыши и выбирала Properties для редактирования свойств сущности. Мне также понадобится несколько скалярных свойств в каждой сущности (выбираем из того же контекстного меню команды Add | Scalar Property).
Рис. 1 Сущности Blog, Post и Tag и настройка связанных с ними свойств
Поддержка внешнего ключа в EF 4.0
Далее я добавлю отношения между этими сущностями. Щелкните правой кнопкой мыши на поверхности дизайнера и выберите Add | Association, как показано на рис. 2. EF теперь поддерживает внешние ключи, что позволяет включать в сущность свойства, выступающие в роли внешнего ключа. Заметьте, что добавление отношения привело к появлению в сущности Post свойства BlogBlogID (внешнего ключа).
Рис. 2 Связи между сущностями Blog, Post и Tag
Включение свойств внешнего ключа в сущности упрощает ряд шаблонов кодирования ключа, в том числе связывание с данными, динамические данные, управление параллельной обработкой и разработку промежуточного уровня в распределенных приложениях. Например, если я выполняю привязку к сетке, которая показывает продукты, и у меня есть в сетке свойство CategoryID (значение внешнего ключа), но нет соответствующего объекта Category, то поддержка внешнего ключа в EF означает, что мне больше не нужно выполнять специальный запрос для получения этого объекта.
Model First в EF 4.0
Теперь, когда модель построена (рис. 3), приложению нужна база данных. В этом случае MyBlog является новым приложением, и у него еще нет базы данных. Я не хочу сама создавать базу данных — я предпочла бы, чтобы это сделали за меня.И это возможно. С поддержкой Model First в EF 4.0 среда Visual Studio теперь может генерировать не только код для сущностей, но и базу данных на основе только что созданной модели.
Рис. 3 Модель блога
Сначала нужно создать пустую базу данных, к которой я применю сгенерированную схему. Для этого открываем Server Explorer, щелкаем правой кнопкой мыши узел Data Connections и выбираем Create New SQL Server Database (рис. 4). Создав пустую базу данных, щелкаем правой кнопкой мыши поверхность дизайнера модели и выбираем Generate Database from Model. Пройдя через экраны мастера Generate Database, мы получим файл BlogModel.edmx.sql. При открытом новом файле достаточно щелкнуть правой кнопкой мыши этот файл и запустить SQL-сценарий, который создаст схему для базы данных.
Рис. 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.
Рис. 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, ComboBox, Button и пару меток. Получив скелет приложения Silverlight (рис. 12), можно подключить службу данных.
Рис. 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 приводит к автоматической генерации типов на клиентской стороне, реализующих интерфейсы INotifyPropertyChanged и INotifyCollectionChanged. Это означает, что любые изменения, внесенные в содержимое DataServiceCollection или в сущности в наборе, отражаются в клиентском контексте. Это же подразумевает, что при повторном запросе сущности в наборе любые изменения в ней отражаются в сущностях, содержащихся в DataServiceCollection. И еще:поскольку DataServiceCollection реализует стандартные интерфейсы связывания, его можно привязать как DataSource к большинству элементов управления WPF и Silverlight.
Но вернемся к примеру MyBlog.Следующий шаг — создание соединения с сервисом; для этого создается новый DataServiceContext и с его помощью запрашивается сервис. На рис. 13 показаны файлы MainPage.xaml и MainPage.xaml.cs; здесь видно, как создается новый DataServiceContext и запрашиваются все блоги от службы (в данном случае сервис возвращает все блоги, принадлежащие текущему пользователю), которые привязываются к 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.Я указываю в свойстве SetEntitySetPageSize моего сервиса ограничение для набора сущностей 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)