вторник, 7 февраля 2012 г.

MVC. Общаемся с БД

Идеология MVC - есть контроллер, который обрабатывает запросы, работает с моделью и генерирует представление, «вьюху». Там нету серверных контролов, форм, кнопок. Только view.
Создадим приложение, которое умеет добавлять новых авторов в нашу БД, редактировать уже имеющихся и удалять их.
Создаем ASP.NET MVC 3 Web Application.

Открываем файл «Web.config» и заменяем строку соединения, которая там есть, на строку соединения с нашей БД. (Как это сделать из самой студии – см здесь)
Ок, приложение есть. Теперь нам нужен ORM. Выбираем «Linq to SQL». (Аналогично тому, как мы делали раньше)
SolutionAdd - New Project
Создаем проект class Library – «Model». Выкидываем оттуда дефолтный класс «Class1.cs». Вместо него добавляем «LINQ to SQL Classes». Назовем его «Books.dbml». Открываем его, открываем Server Explorer. Разворачиваем таблички нашей БД, выделяем нужные и перетаскиваем на форму.
Возвращаемся в Web Application. Добавляем проект «Model» в «References».
И создаем новый контроллер (ControllersAddController) с пустыми actions. Назовем его «AuthorController».

Заполняем его. Каждый метод повторяем дважды - для get запроса и post запроса.
Get запрос идет, когда мы открываем url адрес. Пусть он возвращаем нам некую view

Post запрос идет, в нашем случае, при submit-e формы.
Создадим эту форму: В папке «Views» создаем папку «Author», в которую уже добавляем view с названием «Create». Расписываем ее:

Символ «@» означает, что за ним идет код C#, который Razer обработает и выполнит. Razer  - движок для создания view.
ViewBag.Title = "Добавление";

Это – название самого окна в браузере. Далее идет описание формы и ее параметров. Параметр method - тот метод протокола HTTP, по которому будут переданы параметры на сервер (в нашем случае – POST), action – куда буду отправлены данные.

При создании нового автора нам необходимо ввести ему имя и фамилию (id, напомню, генерится само – это автоинкрементальное поле в нашей БД). Соответственно, указываем внутри формы два input-a типа «тект», добавив к ним лейблы в качестве описания поля.
<br/> - пустая строка (грубо говоря)
В конце формы указываем волшебный input с типом «submit» - он отправляет данные по тому методу, который мы указали. То есть инициирует POST запрос. При сабмите формы мы получаем коллекцию с параметрами, которые ввел клиент на форме.

А что мы хотим от POST запроса? Мы хотим добавить введенного на клиенте автора в Базу Данных! А для этого нам надо послать запрос к БД в виде операции, которую мы делаем внутри транзакции, а для работы с транзакцией нам необходимо открыть соединение. Во как.


Внутри транзакции создаем новый объект класса «Автор» (он сгенерился в Модели, когда мы перетащили в дизайнер табличку авторов).
Далее мы присваиваем этому автору значения из коллекции.

db.Authors.InsertOnSubmit(a);
db.SubmitChanges();

Вставляем автора в Базу Данных и сабмитим изменения – сохраняем их.
После чего возвращаемся на главную страницу – Index.

Если блок «try» не прошел успешно, то возвращаем ту же самую View – остаемся на форме.

Рассмотрим дефолтную страницу – View «Index»


























@model IList<Books.Model.Author> - говорим о том, что будем работать со списком объектов типа «Автор»

«table» - таблица
«thead» - заголовок таблицы
«th» - колонки в заголовке
«tbody»- тело таблицы
«tr» - строки

Выводим в таблицу имя, фамилию и ссылки на редактирование/удаление. В методах редактирования и удаления нам необходимо будет передать в качестве параметра id, поэтому мы создаем объект с единственным свойством, которому передаем значение id из базы.

<td>@Html.ActionLink("Редактировать", "Edit", new {id = a.id})</td>


Сам метод edit:

Get


Author a = db.Authors.Single(p => p.id == id);

Этот код идентичен такому:



Post запрос метода Edit:


Метод «Delete» аналогично. Get такой же, в теле транзакции в POST запросе:
 Author a = db.Authors.Single(p => p.id == id);
 db.Authors.DeleteOnSubmit(a);
 db.SubmitChanges();
 tran.Complete();
 return RedirectToAction("Index");

Вьюхи:













Все, запускаем наше приложение и любуемся результатом J

пятница, 3 февраля 2012 г.

Web Forms. Общаемся с БД

Идеология Web Forms очень похожа на идеологию Win Forms. Есть страницы с элементами управления, генерящими некие события.
Сделаем Web Application, которое умеет получать список книг и их жанров.
Создаем ASP.NET Web Application. Открываем файл «Web.config» и заменяем строку соединения, которая там есть, на строку соединения с нашей БД. (Как это сделать из самой студии – см здесь)
Ок, приложение есть. Теперь нам нужен ORM. Выбираем «Linq to SQL», так как он довольно простой. Хорошая интеграция со студией и самим SQL Server, основные возможности (отслеживание изменений, преобразование типов данных, генерация запросов…) все есть.
Solution – Add - New Project
Создаем проект, class Library Model. Выкидываем оттуда дефолтный класс «Class1.cs». Вместо него добавляем «LINQ to SQL Classes».

Назовем его «Books.dbml». Открываем его, открываем Server Explorer. Разворачиваем таблички нашей БД, выделяем нужные и просто перетаскиваем на форму.

Как только перетащили таблицы, студия сгенерила классы для работы с «Linq to SQL».
Возвращаемся в Web Application. Добавляем проект «Model» в «References». И создаем новую страницу:
Назовем ее Books.aspx. Переключим ее в режим дизайнера

Открываем Toolbox и перетаскиваем GridView на нашу страничку.

Перетащили. В свойствах таблички указываем «AutoGenerateColumns» значение «False» - «лишние колонки пропадут». Ну и заодно название меняем, например – gvBooks.
Щелкаем на стрелку справа вверху таблички – Edit columns. Можно еще в «AutoFormat» настроить внешний вид, чтобы было красиво J
В «Edit columns» добавляем две колонки типа «BoundField», в свойствах выставляем названия самих колонок – «HeaderText» и то, откуда приедет информация – «DataField».

Назовем источники информации для книг «BookName», а для жанров – «GenreName».
F7 – переход к коду страницы. Открывается метод «Page_Load» - который сработает при загрузке страницы.

Расписываем его.

Открываем соединение:

using (var conn = new SqlConnection(ConfigurationManager.ConnectionStrings["ApplicationServices"].ConnectionString))

ConfigurationManager обращение к конфигурационному файлу, в котором мы в самом начале поменяли строку соединения на нужную нам. Обращаемся к строке по имени - "ApplicationServices" – получаем объект, из которого достаем уже саму строку соединения.

Открываем транзакцию:

using (var tran = new TransactionScope())

TransactionScope потому что мы работаем с «Linq to SQL».

В транзакции:

var context = new BooksDataContext(conn);
var report = from b in context.Books select new { BookName = b.name, GenreName = b.Genre.name };
gvBooks.DataSource = report;
gvBooks.DataBind();
tran.Complete();

Проинициализировали контекст, с которым будем работать, мы создали файл «Books.dbml», к его названию надо добавить DataContext – получим класс, работающий с нашей БД.

Проинициализировали отчет, записанный с помощью линк-запроса, сделали выборку новых объектов, имеющих всего два параметра – BookName и GenreName (которые мы указали в «DataField» колонок таблицы)

Потом указали, что DataSource нашей таблички – тот самый отчет. И Заполнили ее командой DataBind. После чего завершили транзакцию.

Теперь открываем «Site.Master», находим там NavigationMenu и добавляем туда строку

<asp:MenuItem NavigateUrl="~/Books.aspx" Text="Книги"/>



Все, запускаем наше приложение и любуемся результатом J

четверг, 2 февраля 2012 г.

Win Forms. Общаемся с БД

Идеология Win Forms приложений проста: есть окно с некими элементами управления в них. Элементы управления генерируют события. Когда пользователь нажимаем на кнопку - она генерит событие, что на нее нажали.

Нечто подобное мы делали тут.

Создаем Windows Forms Application.

 

View - Toolbox
All Windows Forms –
тут нам понадобятся кнопки (Button) и таблички (DataGridView)


Вытащили кнопку – назвали в свойствах «Добавление жанра».
Клац-клац по ней – попадаем в код.
Что нам надо сделать, чтобы добавить жанр? Обратиться к базе данных. С помощью некой операции, в данном случае Insert. А как уже писалось, чтобы совершить операцию, надо открыть транзакцию (а потом ее закрыть)

Открываем

var tran = connection.BeginTransaction(IsolationLevel.ReadCommitted)

Закрываем

tran.Dispose();

Однако при таком подходе, если у нас что-то пойдет не так – например, отвалится соединение, код не доработает до второй строки => транзакция не будет закрыта.
Поэтому оборачиваем использование транзакции в оператор using
using (var tran = connection.BeginTransaction(IsolationLevel.ReadCommitted))
{  код внутри транзакции  }
Уровень изоляции выбираем, исходя из нужд приложения. Нам вполне хватит ReadCommitted.

Транзакция, в свою очередь, обращается к соединению – перед тем, как открыть транзакцию, надо открыть соединение. В целях экономии ресурсов использование соединения также оборачивается в оператор using.
Что делает оператор using ? В приведенном ниже примере conn и conn2 идентичны. Но один расписан в 9 строк, а второй делает ровно тоже самое - в одну. А именно - защищает от проблем в коде, в любом случае выполняя завуалированный блок finally, по умолчанию делающий Dispose переменной, указанной в операторе using  
На выходе получаем код:
Внутри транзакции мы создаем новый объект типа «Жанр», присваиваем ему некое имя. После чего выполняем операцию Insert, записывая ее итог в переменную count, для того, чтобы вывести сообщение о том, что строка корректно добавилась, что и сделано после коммита транзакции.
Класс «Жанр» содержит в себе:
Поля id и name, а также их геттеры/сеттеры:
        private int id;
        private string name;

        public int Id
        {
            get { return id; }
            set { id = value; }
        }

        public string Name
        {
            get { return name; }
            set { name = value; }
        }

Методу  Insert мы будем передавать жанр, соединение типа SqlConnection и транзакцию типа SqlTransaction.

После чего создаем SQL команду, которой говорим «добавить в таблицу жанров значение с именем…». Чтобы обозначить передаваемый параметр, ставим собачку перед этим параметром: «@name».

Так как мы создаем новую строку, у которой формируется id, нам надо это id получить. Получаем мы его с помощью комады @@IDENTITY. Она возвращает последнее значение изменения автоинкрементального поля.

После чего с помощью команд

cmd.Parameters.Add(*параметры*);

Добавляем оба параметра в эту команду. Запись вида

new SqlParameter("id", SqlDbType.Int) { Direction = ParameterDirection.Output };

Говорит о том, что id – выходной параметр. Если мы просто указываем новый SQL параметр без каких либо значений в фигурных скобках – по дефолту это входной параметр (Direction = ParameterDirection.Input). Но значение id мы должны получить, а не записать => это выходной параметр.

Записали параметры в cmd, потом указали, что она выполняется в рамках транзакции, перевадаемой методу. И сконвертировали значение полученной id в значение типа int

Метод Update выглядит проще, так как там нам не надо получать параметры


Вот и все, будем теперь по кнопке выполнять какое-то действие, еще и получать корректное сообщение об этом благодаря оператору MessageBox

Теперь о таблицах. Достаем ее на форму – правой кнопкой, edit colums
.

Создаем нужные нам колонки, закрываем. HeаderText - название самой колонки, DataPropertyName - имя свойства объекта, которое мы будем тащить в эту таблицу.


Делаем рядом кнопку «Get Жанры» или «Получить Жанры». Ее код:

За отображение полученного листа информации в таблице отвечает код

dgGenres.DataSource = list;

dgGenres – название нашей таблички, задаем его в Properties

Ну и сам метод получения жанров (в классе Genre.cs). Ему уже не надо передавать объект типа жанр, только соединение и транзакцию.


















Ну и чтобы у нас все работало, нам надо указать - к какой такой Базе Данных мы обращаемся?
Добавляем в проект новый item:


Называем его волшебным словом «App.config», прописываем там строку соединения:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <connectionStrings>
    <add name ="default" connectionString="Data Source=.\SQLEXPRESS;Initial Catalog=Books;Persist Security Info=True;User ID=ap;Password="></add>
  </connectionStrings>
</configuration>

Теперь можно запускать и наслаждаться результатом.

Это уже и автоматизировать можно... Правда, сложно :)
Если работаешь с Web, то и к базе надо обращаться через Web...

Как достать строку соединения с БД?

Постоянно забываю, как мне достать строку соединения :)

Открываем студию. View - Server Explorer.

Если у нас еще нет соединения с БД - добавляем его, "Add connection"
Если уже есть - Modify connection.


Нажимаем на кнопочку "Advanced".


И вот она, наша строка соединения, в самом низу.


Копипастим и вставляем в конфиг файл, в этой строке только пароля нет, надо руками дописать.