Тем, кто пишет запросы в коде страницы посвящается...

Приветствую всех!

На хабре есть немного информации о том, что в следующей версии VisualStudio 2008 будет ADO.NET EntityFramework. (Открою секрет, эта версия уже появилась.) Эта разработка представляет собой универсальный фреймворк, который позволяет создавать даталогику вашего проекта в пару кликов мыши.
До сих пор, работая с даталогикой, я сталкивался с 2 видами проектов. Первые были созданы на небезызвестном фреймворке NHibernate, другие реализовывали даталогику программистами. Я уже 3 года занимаюсь написанием и разработкой различных систем и всё это время разрабатывал логику работы с данными исключительно ручками.
И вот, на днях, после того, как я поставил новую винду, я скачал VisualStudio WebDeveloper Express, и с радостью обнаружил в комплекте поставки ADO.NET EntityFramework. Через некоторое время зарегистрировал домен, создал простенький сайт, и начал тренировать свои силы в написании программ под этот фреймворк.


Я был немного неприятно удивлён тем, что большинство статей о ADO.NET EF были узконаправленными. Невозможно было найти полной информации, от начала до конца, о том, как правильно настроить базу, создать сущности и произвести базовые действия над этими сущностями. Большинство статей раскрывают лишь одну из этих тем. Что-же, обучаясь, я решил поделиться опытом с тобой %username%. В то же время, используя мой код вы не сможете поднять систему работы с бизнес-процессами, но всё-таки, вы поймёте с какой стороны к чему подходить.



Для начала необходимо создать простой Web проект с базой данных. К базе данных тоже неплохо было бы подключится сразу через DataBase Explorer. Просто потом будет удобнее.



После этого, в проект надо добавить новый элемент «ADO.NET Entity Data Model».



Системе надо будет указать строку для соединения с базой, а так же указать, откуда возьмётся первая модель ADO.NET EF.



В своей БД я уже имею две очень простых таблицы Post и User, поэтому не мудрствуя лукаво, я заставил систему создать модель на основе моей БД. После всех этих, очень простых действий, я получил рабочую модель БД. Более того, изучив эту модель визуально, я не забыл заглянуть в код, и посмотреть, как же фрейворк описывает все мои классы?

  1. namespace DataBaseCore
  2. {
  3.   
  4.   /// <summary>
  5.   /// There are no comments for DbModel in the schema.
  6.   /// </summary>
  7.   public partial class DbModel : global::System.Data.Objects.ObjectContext
  8.   {
  9.     /// <summary>
  10.     /// Initializes a new DbModel object using the connection string found in the 'DbModel' section of the application configuration file.
  11.     /// </summary>
  12.     public DbModel() :
  13.         base("name=DbModel", "DbModel")
  14.     {
  15.       this.OnContextCreated();
  16.     }
  17.  
  18. /* Урезал за ненадобностью */
  19.  
  20.   [global::System.Data.Objects.DataClasses.EdmEntityTypeAttribute(NamespaceName="DataBaseCore", Name="Post")]
  21.   [global::System.Runtime.Serialization.DataContractAttribute(IsReference=true)]
  22.   [global::System.Serializable()]
  23.   public partial class Post : global::System.Data.Objects.DataClasses.EntityObject
  24.   {
  25.     /// <summary>
  26.     /// Create a new Post object.
  27.     /// </summary>
  28.     /// <param name="id">Initial value of Id.</param>
  29.     public static Post CreatePost(int id)
  30.     {
  31.       Post post = new Post();
  32.       post.Id = id;
  33.       return post;
  34.     }
* This source code was highlighted with Source Code Highlighter.


Намётанный глаз специалиста по работе с даталогикой показал наличие достаточно простого и изящного класса, который позволил работать как с постами в системе, так и с пользователями.

Ну, что же, код у нас уже есть, осталось только его начать использовать. И тут, нам открываются все прелести и возможности ASP.NET. Среди немалого количества источников данных на странице я увидел Entity Data Source, который с удовольствием предоставляет данные по запросу из нашего класса. Перетаскиваем его на форму, запускаем мастер настройки, и быстренько цепляем датасорс на нашу таблицу постов.



Несомненно, намного приятнее стало выглядеть описание датасорца в ASPX коде.
  1. <asp:EntityDataSource ID="dsPosts" runat="server" ConnectionString="name=DbModel"
  2.     DefaultContainerName="DbModel" EntitySetName="Post">
  3.   </asp:EntityDataSource>
* This source code was highlighted with Source Code Highlighter.

Можно сказать — блещет изяществом.

После появления на форме провайдера данных, нужен и потребитель. Не умничая, я добавил простенький код, который просто отображает все посты последовательно.

  1. <asp:Repeater runat="server" ID="repPosts" DataSourceID="dsPosts">
  2.     <HeaderTemplate>
  3.     </HeaderTemplate>
  4.     <ItemTemplate>
  5.       <div>
  6.         <h3>
  7.           <asp:Label ID="lblHeader" runat="server" Text='<%# Eval("Header") %>'></asp:Label>
  8.         </h3>
  9.         <p>
  10.           <asp:Label ID="lblText" runat="server" Text='<%# Helpers.TypographText(Eval("Text").ToString()) %>'></asp:Label>
  11.         </p>
  12.       </div>
  13.     </ItemTemplate>
  14.   </asp:Repeater>
* This source code was highlighted with Source Code Highlighter.


И вот тут заканчивается самая простая часть моего повествования. До сих пор, всё что было сделано, можно повторить при помощи мыши. Это было достаточно просто. Мы только что создали объектно-ориентированное представления БД, и используя это представление, начали выв��дить данные из базы на страницу. При этом, мы ни разу не написали ни одного запроса, не получали данные из базы напрямую, etc…

Но, что же выводить пользователю, если у нас нет ничего в БД? Нехорошо. Надо написать форму заполнения базы. Теперь мы бросим мышепрограммирование, и займёмся написанием кода.

Я сделал два самых базовых действия для работы с постами в системе — это добавление и удаление. Сделать редактирование по аналогии с этим кодом не составит труда ни для кого.

  1. namespace DBW
  2. {
  3.   public class Post
  4.   {
  5.     public Post()
  6.     {
  7.  
  8.     }
  9.     public static void New(String PostText, String PostHeader, Int32 UserId)
  10.     {
  11.       DataBaseCore.DbModel m = new DataBaseCore.DbModel();
  12.       DataBaseCore.Post p = new DataBaseCore.Post();
  13.       p.Header = PostHeader;
  14.       p.Text = Helpers.TypographText(PostText);
  15.       p.PublishDate = DateTime.Now;
  16.       p.User = (from usr in m.User where usr.Id == UserId select usr).First();
  17.       m.AddToPost(p);
  18.       m.SaveChanges();
  19.     }
  20.  
  21.     public static void Delete(Int32 PostId)
  22.     {
  23.       DataBaseCore.DbModel m = new DataBaseCore.DbModel();
  24.       DataBaseCore.Post p = new DataBaseCore.Post();
  25.       p = (from pst in m.Post where pst.Id == PostId select pst).First();
  26.       m.DeleteObject(p);
  27.       m.SaveChanges();
  28.     }
  29.   }  
  30. }
* This source code was highlighted with Source Code Highlighter.


Казалось бы, всё просто, и да, это так. Но есть пара нюансов.
Во-первых — это LINQ. Без него в ADO.NET никуда. Так что не стоит отлынивать и вообще забивать на SQL или LINQ, писать запросы всё равно придётся.
Во-вторых — этот код автоматически генерируется фреймворком, поэтому особого удобства в некоторых моментах ожидать не придётся, и всегда надо быть готовым изменить уже созданный студией код. Например, тут в строке 16 было бы удобнее использовать не объект типа пользователь, который мне пришлось выбирать из БД, а сразу передавать значение идентификатора пользователя. Так было бы удобнее для этого кода, но это не универсально. Поэтому код нуждается в доработке и переосмыслении. Возможно просто надо передавать не идентификатор пользователя, а объект типа пользователь.

Что дальше? Дальше я буду продолжать писать проект, углубляясь в дебри ADO.NET Entity Framework, и буду с удовольствием делиться своими изысканиями с вами, уважаемые хабраюзеры. Соответственно, будут новые статьи, с более серьёзными и глубокими данными.

UPD. Тема очень обширная. Здесь не раскрыто и процента возможностей, но продолжение будет 8-)