Как написать запрос для бд из с
Для выполнения запросов к базе данных SQLite применяется класс SqliteCommand , который представляет реализацию интерфейса System.Data.IDbCommand . Для создания объекта SqliteCommand можно использовать один из его конструкторов:
SqliteCommand(String) : создает объект SqliteCommand, в конструктор которого передается выполняемое выражение SQL
SqliteCommand(String, SqliteConnection) : создает объект SqliteCommand, в конструктор которого передается выполняемое выражение SQL и используемое подключение к базе данных в виде объекта SqliteConnection
SqliteCommand(String, SqliteConnection, SqliteTransaction) : третий параметр представляет применяемую транзакцию в виде объекта SqliteTransaction
Альтернативным способом создания объекта SqliteCommand представляет метод CreateCommand90 класса SqliteConnection:
Для конфигурации объекта SqliteCommand можно использовать ряд его свойств, некоторые из них:
CommandText : хранит выполняемую команду SQL
CommandTimeout : хранит временной интервал в секундах, после которого SqliteCommand прекращает попытки выполнить команду. По умолчанию равен 30 секундам. Значение 0 представляет отстутсвие интервала.
Parameters : предствляет параметры команды
Connection : предоставляет используемое подключение SqliteConnection
Например, установим свойства подключения и выполняемой команды:
Чтобы выполнить команду, необходимо применить один из методов SqliteCommand:
ExecuteNonQuery : выполняет sql-выражение и возвращает количество измененных записей. Подходит для sql-выражений INSERT, UPDATE, DELETE, CREATE.
ExecuteReader() : выполняет sql-выражение и возвращает считанные из таблицы строки. Подходит для sql-выражения SELECT.
ExecuteScalar() : выполняет sql-выражение и возвращает одно скалярное значение, например, число. Подходит для sql-выражения SELECT в паре с одной из встроенных функций SQL, как например, Min, Max, Sum, Count.
Создание таблицы
Для создания базы данных применяется SQL-команда CREATE TABLE , после которой указывается имя создаваемой таблицы и в скобках определения столбцов.
Например, создадим таблицу «Users», которая будет иметь три столбца — _id (уникальный идентификатор), Name (имя), Age (возраст):
После выполнения команды в базе данных можно будет найти таблицу Users:
Для просмотра бд SQLite можно использовать специальный инструмент — DB Browser for SQLite.
Добавление данных
Теперь добавим в выше созданную таблицу Users новый объект:
Для вставки объекта используется sql-выражение INSERT, которое имеет следующий синтаксис:
В ранее созданной таблице Users определены три столбца — __id и Age, которые хранят целое число, и Name, который хранит строку. Поэтому соответственно мы добавляем для столбца Name значение ‘Tom’, а для столбца Age число 36.
Здесь метод ExecuteNonOuery() возвращает число затронутых строк (в данном случае добавленных в таблицу объектов). Хотя нам необязательно возвращать результат метода, но данный результат может использоваться в качестве проверки, что операция, в частности, добавление, прошла успешно.
После добавления данных мы сможем их увидеть через DB Browser for SQLite:

Подобным образом можно добавить несколько объектов:
Обновление объектов
Для обновления применяется sql-команда UPDATE, которое имеет следующий синтаксис:
Применим эту команду:
Здесь обновляется строка, в которой Name=Tom, то есть выше добавленный объект. Если в таблице будет несколько строк, у которых Name=Tom, то обновятся все эти строки.
Удаление
Удаление производится с помощью sql-выражения DELETE, которое имеет следующий синтаксис:
Удалим, например, всех пользователей, у которых имя Tom:
Во всех трех случаях фактически меняется только sql-выражение, а остальная логика остается неизменной. И мы также можем выполнять сразу несколько операций:
Программирование на C, C# и Java
Уроки программирования, алгоритмы, статьи, исходники, примеры программ и полезные советы
ОСТОРОЖНО МОШЕННИКИ! В последнее время в социальных сетях участились случаи предложения помощи в написании программ от лиц, прикрывающихся сайтом vscode.ru. Мы никогда не пишем первыми и не размещаем никакие материалы в посторонних группах ВК. Для связи с нами используйте исключительно эти контакты: vscoderu@yandex.ru, https://vk.com/vscode
MySQL и C# — работаем с базой данных. Запросы SELECT
В видеоуроке рассмотрим работу с базой данных MySQL на примере SELECT-запросов из программы, написанной на языке программирования C#. В статье вы найдёте исходные коды примеров из видео.
В видео показано выполнение запросов выборки (SELECT) к БД с помощью C#. Рассказывается про получение, как одного значения из базы, так и нескольких столбцов и строк.
Исходный код примера с получением одного значения из базы с помощью метода ExecuteScalar():
Words are DUST
Итак 🙂 Ниже будет пост, бьющий все рекорды просмотров на codepaste. В свое время я почему-то ничего толкового не нашел, было много экспериментов. Теперь я хочу показать тебе маленький, но очень гордый проект для работы с БД MySQL
Предисловие и приготовления
- Скачивание и установка MySQL-сервера (если приложение работает с локальной базой)
- Конфигурация графического интерфейса БД (phpMyAdmin — веб-морда, пригодится, если помимо MySQL-сервера у нас стоит еще и http-сервер(Apache, например). Так будет, если вы берете MySQL из состава Denwer. Иначе, если тебя интересует только БАЗА, то рекомендую dbForge Studio for MySQL)
- Конфигурация базы (собственно, описание ее структуры, связей, типов, состава полей и т.п. ) или перенос дампа с существующей базы
- Написание программы-клиента.
Реализация
Ок, все вводые выполнили, теперь можно приступать. Извращаться не будем, для наглядности пишем в одном файле. Сначала ничего интересного — описываем подключаемые библиотеки, файлы и пространства имен:
А вот теперь заполняем основные константы для подключения к базе и переходим к телу функции main. (Знатоков PHP сейчас начнет хватать за пятку де-жа-вю)
Итак, обращу твое внимание. Мы подключились к базе, уже без палева провели первый запрос. Да. Это функция mysql_query(дескриптор,»Запрос»);. В данном случае, мы подключились и сказали:«Дорогая База Данных! Пожалуйста, сформируй кодировку вывода для соединения link как кириллическую (cp1251)». Тем самым мы, консоль и база говорят на одном языке (кодировке). Теперь можем смело приступать к более осмысленным вещам.
Пусть у тебя есть некая таблица со статьями (articles), в ней есть поля автор (Authors) и название стати (Title). Попробуем «вытащить» из базы названия всех статей, автор которых, к примеру. Хватит это терпеть! Пусть будет Жириновский.
Это не безопасный вариант кода, если у нас какая-то операция не удастся, то программа вылетит с ошибкой. Давай еще раз то же самое, но с проверкой на успешность.
Постскриптум
Функций, доступных разработчикам, много. Мануалы по конкретным задачам гуглятся на ура. Я же ставил себе целью показать некий «Hello, World!», маленький, но уже обросший всем необходимым, 100% рабочий проект.
ASP.NET MVC – работаем с MySQL через ADO.NET
Уже, наверное, раза три подбираюсь к ASP.NET MVC. После десяти лет с ASP.NET WebForms немного сложно переходить именно к технологии MVC, поскольку отличий столько, что скорее проще перечислить, что у этих технологий общего – это разве что библиотеки .NET Framework. Я не буду писать тут – лучше или хуже MVC чем WebForms, просто они обе хороши, и на обеих технологиях можно построить хорошее приложение. Свои мысли по поводу необходимости TDD я тоже пока оставлю при себе, хотя их есть у меня.
А сейчас я буду говорить о стандартнейшей задаче – обычной работе с данными: просмотре в табличном виде списка записей, добавлении, изменении и удалении данных (операции CRUD). Однако практически во всех книгах и во многих решениях в интернете для ASP.NET MVC почему-то рассматривается вариант исключительно через ORM (Object Relation Mapping): или Entity Framework (EF) или LINQ для SQL. Технологии отличные, спору нет, наконец-то программист может и не разбираться – а как вообще эта самая реляционная СУБД (которой он, скорее всего, пользуется) вообще работает, и даже SQL, по идее, знать уже необязательно: прокладка в виде EF и коннектора для СУБД разберутся между собой. «Вот оно счастье – нет его краше». Но тем программистам, которые не боятся прямой работы с базой данных через механизм ADO.NET, зачастую непонятно – а с чего вообще начинать в ASP.NET MVC и надо ли.
Плюс к этому, у меня, например, вначале вызвало дикую ломку отсутствие удобного компонента для отображения данных в таблице-гриде. Подразумевается, что это всё должен реализовывать сам разработчик или брать в менеджере пакетов что-то подходящее. Если вас, как и меня, компонент GridView в ASP.NET WebForms устраивал более чем, то для MVC сложно найти что-то более-менее сопоставимое, разве что Grid.mvc. Но вот доверия у меня к подобным компонентам маловато, чтобы их использовать для достаточно крупного проекта. В случае их использования, программист начинает зависеть от другого разработчика, который, во-первых, неизвестно как написал этот компонент (качественно ли?), а, во-вторых, неизвестно когда и как будет его дорабатывать. Расширять компонент и пилить дальше иногда вроде бы даже можно, но, в случае доработки оного разработчиком, мы вынуждены либо опять перелопачивать свой код, либо замораживать обновление компонента на определенной версии. А если разработчик устранит какую-либо уязвимость – всё равно придется переходить на новую версию. Даже переход на новые версии коннектора MySQL вызывает определенные проблемы, хотя его всё-таки крупная компания разрабатывает, а что там с многочисленными «велосипедами» в менеджере пакетов Nuget?
Итак, попытаемся научиться писать под ASP.NET MVC, при этом будем работать с данными, которые обрабатываются СУБД MySQL. Весь код можно взять вот по этому адресу, ниже этот код будет частично презентован с небольшими ссылками и пояснениями. А здесь можно посмотреть на работу приложения.
Создаем базу данных в MySQL
База данных (БД) будет простая и представлена всего двумя таблицами, со одной связью «один-ко-многим» между ними по полю LanguageID . Этим я собираюсь усложнить ситуацию для необходимости использования выпадающего списка выбора одного из языков для пользователя. Также, для усложнения, для пользователя введём еще поле SupporterTier , которое будет определять уровень поддержки пользователя посредством перечисления (enum). А для того, чтобы у нас в проекте использовались почти все типы данных, добавим ещё поле LastLoginDate типа «дата/время», которое будет заполняться самим приложением при входе пользователя (в данном проекте не отражено).
Создаем проект

Выбираем «MVC». Можно и «Пустой», но у нас учебное, а не реальное приложение, поэтому это нам поможет сразу, без лишних телодвижений, интегрировать в наше приложение Bootstrap и JQuery.

Получаем уже заполненные папки Content, Fonts, Scripts, а также файлы BundleConfig.cs и FilterConfig.cs в каталоге App_Start с регистрациями связок и фильтров ASP.NET MVC. В пустом проекте там есть только регистрация маршрутов в файле RouteConfig.cs. В Global.asax.cs также добавятся вызовы методов, описанных в этих файлах:
Настраиваем инфраструктуру и всю обвязку
Для работы с СУБД MySQL добавляем библиотеку MySql.Data: либо вручную, если коннектор mysql-connector-net-8.0.18 уже установлен на компьютер, либо из менеджера пакетов Nuget:

Добавляем в файл Web.config конфигурацию строки подключения к СУБД MySQL:
Добавляем в раздел <appSettings> строку со ссылкой на добавленную строку подключения: <add key=»ConnectionString» value=»example» />
Добавляем в приложение новый каталог Domain, в нём создаем новый статический класс Base (в файле Base.cs), в котором идут обращения к этим параметрам:
Мне нравится иметь в приложении некий базовый класс со ссылками на параметры приложения и какими-нибудь стандартными функциями, которые можно было бы вызывать из всего приложения.
Название строки подключения определено в параметрах приложения, чтобы в дальнейшем было проще работать со строкой подключения к СУБД: быстро переключаться между разными базами данных и менять параметры подключения. Кроме этого, использование названия строки подключения в параметре приложения, удобно использовать для публикации приложения в Microsoft Azure – там можно задать параметр для службы приложения, которая используется для публикации, и в нём определить нужную строку подключения, которая заранее определена в <connectionStrings> . Тогда при публикации можно не использовать трансформацию файла web.config.
Также мне нравится в тексте использовать значения из глобального файла ресурсов, чтобы не переписывать их в нескольких местах, если это вдруг потребуется. Например:

В файле-макете страницы _Layout.cshtml (стандартно располагается в каталоге Views\Shared и в дальнейшем используется для всех страниц данного проекта) можно теперь использовать эти переменные (см. например, Example_Users.Properties.Resources.Title ):
Также в этом файле видим прикрепление каскадной таблицы стилей подключенного Bootstrap и библиотеки скриптов JQuery. Содержимое всех представлений будет генерироваться в месте размещения вызова функции RenderBody() .
M — значит модель
Добавляем файл UserClass.cs в каталог Domain:
А также файл LanguageClass.cs в тот же каталог:
Тут можно видеть, что свойства классов повторяют структуру таблицы Users и Languages в СУБД. Для типа перечисления создан enum Supporter , чтобы его можно было использовать для свойства класса SupporterTier аналогичного поля таблицы БД. Для полей UserID , LanguageID можно видеть, что они заданы, как первичный ключ, точно так же, как и в БД. Для этого использован атрибут [Key] .
Все остальные атрибуты имеют отношение скорее к представлениям (view), использующим этот класс. И если мы собираемся использовать хелперы для формирования HTML-тегов для этих свойств (что я лично однозначно рекомендовал бы), то нам придется очень тщательно устанавливать эти атрибуты, чтобы получить то, что нам надо. В частности, вот то, что понадобилось для этого проекта:
- [DisplayName] – используется как отображаемое на экран имя для класса. Иногда может быть полезно, в данном проекте специально добавил использование хелпера Html.DisplayNameForModel для демонстрации.
- [Display] со свойством Name – используется как отображаемое на экран название свойства класса. Еще есть полезное свойство Order, позволяющее упорядочить последовательность отображения свойств класса в форме с использованием хелперов (по умолчанию сортировка по порядку определения свойств класса, поэтому в данном проекте свойство Order не использовалось).
- [HiddenInput] со свойством DisplayValue . Используется для свойств, которые либо не надо показывать в формах и списках вообще ( DisplayValue=false , отрисовываются как теги input с типом hidden ), либо для свойств, которые всё-таки надо отображать, но в виде неизменяемого текста ( DisplayValue=true , отрисовывается как чистый текст, без тегов)
- [ScaffoldColumn] – указывает, отображать ли поле в хелперах редактирования (например, Html.EditorForModel ). Если false – то в форме не будут отображены ни описание свойства класса, ни его значение. Тут нельзя использовать [HiddenInput(DisplayValue = false)] , потому что в этом случае значения данного свойства класса вообще не будут отображены не только в формах ввода информации, но и в табличных отображениях. В данном случае это потребовалось для свойства LastLoginDate , которое не вводится вручную, а заполняется где-то автоматически, но видеть нам его всё-таки надо.
- [Required] – для проверки того, введено ли значение для свойства класса, с текстом сообщения об ошибке в свойстве ErrorMessage и свойством AllowEmptyStrings позволяющим вводить пустые строки.
- [EmailAddress] – аналогичный, по сути, атрибут для проверки корректности почтового адреса.
V — значит вендетта представление
В каталоге Views создаем каталог Users для наших представлений. Все наши представления используют стандартный (определен в файле _ViewStart.cshtml в каталоге Views) макет _Layout.cshtml, расположенный в каталоге Views\Shared. Создаем представление Index (файл Index.cshtml в каталоге Users):

Если мы хотим, чтобы данное представление запускалось по умолчанию, то в файл RouteConfig.cs вносим изменение для Default :
В самом представлении надо обратить внимание на строчку с Html.Partial(«List») . Это нужно для отрисовки в данном месте специального отдельного общего частичного представления, расположенного в файле List.cshtml в каталоге Views\Shared. Собственно оно представляет из себя именно таблицу-грид для отображения данных из нашей таблицы БД users :
Видно, что в заголовке таблицы данных используются хелперы Html.DisplayNameFor для отображения названий колонок и для этого приходится указывать ссылку на свойство объекта класса. Поскольку при формировании заголовка таблицы у нас есть только объект Model.Users , который представляет собой список объектов типа UserClass , то приходится применять следующий способ: выбирать первую строку этого списка, как объект класса UserClass . Например, для имени пользователя: Model.Users.First().Loginname . Поскольку у свойства Loginname класса Users указан атрибут [Display(Name = «Login»)] , то в названии колонки будет выведено именно «Login»:

Что еще интересно в представлении List ? Блок с foreach , понятно, отрисовывает объекты класса UserClass , которые находятся в списке Users , полученного из контроллера. А интересны тут объекты SortingInfo и PagingInfo в нашей модели UsersGrid . А эти объекты нужны нам для организации сортировки данных (используется в заголовке таблицы в тегах <th> ) и организации постраничного вывода информации (используется внизу страницы, под таблицей). Именно поэтому мы не используем в качестве модели чисто список объектов типа IEnumerable<UserClass> . А в качестве модели используем класс UsersGrid , который расположили в файле UsersGrid.cs в каталоге Model.
И сами классы PagingInfo и SortingInfo в файле GridInfo.cs в том же месте.
А для использования в представлениях добавлены специальные хелперы в файле GridHelpers.cs (каталог HtmlHelpers):
Поскольку грид с данными без сортировки и без постраничного вывода информации достаточно бесполезная вещь, а стандартного хелпера для целой таблицы данных в ASP.NET MVC нет, то приходится их создавать самостоятельно (либо брать созданный кем-то другим). В данном случае, я подсмотрел несколько реализаций в книгах по ASP.NET MVC и решений представленных в интернете. Причем, почему-то решений, объединяющих вместе хотя бы и сортировку данных и постраничный вывод, либо вовсе нет, либо я не нашел. Пришлось всё это дело осмысливать, объединять и дорабатывать до нормального состояния. Например, постраничный вывод в тех реализациях зачастую не предусматривает вывод более-менее длинного списка страниц – ну а вдруг будет несколько тысяч страниц? Привожу пример отображения для представленного выше решения:

Также нам потребуются представления для создания и модификации данных. Представление для создания объекта типа UserClass :

И код представления будет выглядеть следующим образом:
В этом представлении для примера показано использование хелпера Html.EditorFor в качестве средства для генерации тегов для редактирования всех свойств объектов класса UserClass . Оно отображается следующим образом:

В этом представлении используется в качестве модели класс UserModel , а не UserClass непосредственно. Сам класс UserModel размещен в файле UserModel.cs в каталоге Models:
В этот класс включен собственно сам объект UserClass и дополнительный список объектов типа LanguageClass . Этот список нам потребовался для создания выпадающего списка языков, с выбором в нём текущего языка пользователя: @Html.DropDownListFor(m => Model.User.Language.LanguageID, Model.SelectLanguages(), «»)
В этом хелпере используется вызов функции SelectLanguages() , которая преобразует список языков в объект типа SelectList с уже установленными параметрами идентификатора и названия строки. Выносить генерацию этого объекта в представление было бы неверным, потому что представление по идее не должно знать об этих привязках к названиям полей. Можно было бы, конечно, сразу в контроллере сгенерировать готовый SelectList , но мне вариант с приватным списком объектов доменного класса и функцией нравится больше.
Для генерации выпадающего списка нам приходится использовать отдельные хелперы, потому что хелпер Html.EditorFor(m => m.User) не будет генерировать разметку редактирования для вложенного объекта типа LanguageClass (это можно было бы обойти написав общий шаблон для выпадающих списков, но тут мы это делать не будем…).
И поскольку у нас в представлении используется объект класса UserModel , который включает в себя еще один объект класса UserClass , то и использовать хелпер Html.EditorForModel() не удастся, поскольку хелперы не являются рекурсивными и не будут работать в данной ситуации, поэтому используется хелпер Html.EditorFor() для объекта User .
Также хочется обратить внимание на закомментированный тэг: Html.ActionLink(«Back to list», «Index»)
Обычно подобным образом реализуется возврат из представления для редактирования обратно в список данных. На самом деле, во-первых, на мой взгляд, это смотрится странно – когда в форме у тебя используются кнопки типа button , а кнопка возврата почему-то реализована ссылкой. Во-вторых, если мы будем использовать сортировку и постраничный вывод – придется мудрить с возвратом в тот же вид на ту же страницу – и передавать в представление не только объект UserClass , но и параметры для возврата обратно на страницу. Есть гораздо более простой способ – воспользоваться вариантом с кнопкой вида: /> , которая и отправит пользователя обратно на страницу по истории браузера. Тут, безусловно, есть нюансы (например, вы уже на этой странице пытались сохранить объект, не получилось, и вот – вам уже надо дважды щелкать кнопку отмены), но данный вариант в целом неплохо работает.
И представление для редактирования объекта типа UserClass :

А в этом представлении представлен вариант использования разных хелперов для генерации тегов отдельно для каждого нужного свойства объекта класса. В данном случае можно уже сделать отображение в несколько другом – более симпатичном виде:

И в этом представлении используется другой способ возврата обратно в список. Вместо использования кнопки вида: /> используется такая же кнопка, как и остальные кнопки действия (Save, Remove): /> и возврат обратно осуществляется внутри метода контроллера, обрабатывающего действия этих кнопок (реализацию метода см. ниже).
И тут еще возник нюанс, связанный с использованием свойства класса типа enum. Дело в том, что если мы просто будем использовать хелпер Html.EditorFor() , то на форме отобразится поле ввода текстовой информации (тег вида <input type=”text”/> ), а нам вообще-то нужно поле с выбором из набора значений (т.е. тег <select> с набором опций <option> ).
1. Прямолинейно это решается использованием хелпера типа Html.DropDownListFor() или Html.ListBoxFor() , например, в нашем случае: @Html.DropDownListFor(m => m.Model.User.SupporterTier, new SelectList(Enum.GetNames(typeof(Example_Users.Domain.Supporter)))) . Тут два минуса – каждый раз это придется прописывать индивидуально и для хелпера Html.EditorForModel() или Html.EditorFor() это не подойдет.
2. Можно создать пользовательский шаблон типа Editor . Создаем файл Supporter.cshtml в папке Views\Shared\EditorTemplates:
Название файла должно соответствовать названию типа, либо придется писать не Html.EditorFor(m => Model.SupporterTier) , а Html.EditorFor(m => Model.SupporterTier, «Supporter») . Если файл назвать по-другому, то перед описанием свойства в классе надо будет добавить подсказку [UIHint(«Supporter»)] . И это также придется делать, если планируется использовать Html.EditorForModel() – для него решение вида Html.EditorFor(m => Model.SupporterTier, «Supporter») не подойдет.
Мне этот вариант не подошел из-за того что, при попытке создания пользователя (запуск представления New ) программа для хелперов Html.EditorFor() и Html.EditorForModel() выпадала с ошибкой: «Элемент модели, переданный в словарь, имеет значение NULL, но для этого словаря требуется элемент модели типа «Example_Users.Domain.Supporter», не имеющий значение NULL.» Причина понятна – значение для перечисления не может быть пустым, но решить проблему так и не удалось. Поэтому стал разбираться дальше.
3. Можно использовать хелпер Html.EnumDropDownListFor() , специально сделанный для перечислений. Вот тут всё хорошо, ничего дополнительно писать не нужно, отображается всё корректно, работает и при редактировании и при создании объекта. Кроме одного «но»: хелпер Html.EditorForModel() использует для отображения всех свойств хелперы Html.EditorFor() и, соответственно, не использует Html.EnumDropDownListFor() . И, как я понял, это нельзя обойти с помощью атрибутов для свойств класса – [UIHint] , [DataType] и [EnumDataType] тут не сработают. Также не будут работать атрибуты для значений перечисления, то есть вместо None не получится, например, вывести пустую строку, как это определено в описании перечисления Supporter .
4. В итоге, мне подошел вариант решения, найденный на просторах интернета: создание общего шаблона для перечислений. Создаем файл Enum.cshtml в папке Views\Shared\EditorTemplates:
Вот тут всё вообще хорошо получилось: шаблон замечательно работает везде, где только можно. Даже [UIHint(«Enum»)] можно не добавлять. Причем данный общий шаблон читает атрибут [Display(Name)] для значений перечислений с помощью специальной функции.
C — значит контроллер
Добавляем файл UsersController.cs в каталог Controllers.
Разберём методы контроллера:
Отображение страницы со списком пользователей: public ViewResult Index(string sortOrder, int page = 1)
Тут два входных параметра sortOrder и page . С page всё более-менее понятно, а вот через sortOrder из адресной строки можно передать произвольную строку, которую нам потом придется запихивать в SQL-запрос и делать это напрямую нельзя. Поэтому разбираем эту строку с помощью функции (здесь приводить саму функцию не буду, можно посмотреть в файле Base.cs): sortOrder = Base.parseSortForDB(sortOrder, out sortName, out sortDir);
Далее всё банально, создаем объект репозитария UsersRepository (для работы с СУБД, разобран в следующей главе), вызываем метод List для получения списка пользователей и формируем объект класса UsersGrid из собственно полученного списка пользователей и информации необходимой для организации постраничного вывода информации и сортировки. Причём значение totalItem получаем при вызове метода List , одновременно с созданием объекта класса UsersGrid . Далее этот объект передается для отображения представлению.
Также есть другой метод Index с атрибутом [HttpPost] , который нам потребовался для отработки нажатия кнопки New в представлении Index : public ActionResult Index(string onNewUser)
Входной параметр onNewUser перекликается с элементом /> в представлении Index и при клике на этой кнопке передает в функцию значение, которое мы сверяем с null. Если бы кнопок типа submit было бы в представлении Index несколько, пришлось бы проверять и само значение (в данном случае значение было бы «New user»).
После проверки мы формируем объект класса UserModel , состоящий из нового объекта UserClass и списка языков для выбора их из выпадающего списка и передаем его представлению New . Список языков получается из репозитария LanguageRepository вызовом метода List следующим образом:
Метод New без параметра сделан для отработки клика по ссылке New User для закомментированой строки Html.ActionLink(«New user», «New», «Users») в представлении Index . Действие (открытие представления New ) осуществляется аналогично предыдущему, только проверки на нажатую кнопку нет, потому что отрабатывается нажатие на ссылку.
Метод New с параметром model типа UserModel для отработки события отправки данных формы с целью сохранения нового пользователя в БД: public ActionResult New(UserModel model)
Получает из представления New заполненный объект класса UserModel , проверяет корректность данных (согласно требованиям, описанным в UserClass и LanguageClass ), создает объект репозитария UsersRepository и пытается добавить новую строку в БД, вызвав функцию AddUser(model.User) . Потом осуществляется возврат на предыдущую страницу (откуда был вызов представления New ) и там отображается сообщение об успехе операции или о неудаче.
Метод Edit с входным параметром UserID (идентификатор пользователя) отрабатывает щелчок по имени пользователя в списке для открытия представления редактирования данных пользователя: public ActionResult Edit(int UserID)
В методе опять же создается репозитарий UsersRepository и из него вызывается функция FetchByID(UserID) для получения объекта типа UserClass . В случае удачи создается модель – объект класса UserModel из полученного объекта и списка языков и передается в представление Edit для отображения.
Метод с входным параметром модели типа UserModel и строки action : public ActionResult Edit(UserModel model, string action)
В данный метод передается объект типа UserModel и он отрабатывает действия при нажатии на кнопки (отработка событий отправки данных формы) представления Edit . Для того чтобы понять, какая кнопка нажата используется входной параметр action , который указан в имени HTML-тегов типа input . Поэтому в методе идет сравнение значения данного параметра со значениями параметра value этих кнопок. До проверки модели на валидность проверяется значение Cancel , для выполнения действий по отмене редактирования пользователя. Этот вариант используется вместо возврата назад по истории браузера, примененный в представлении New и использующий запоминание адреса страницы, с которой перешли к представлению Edit . Для этого в контроллере продемонстрирована технология использования своего атрибута ActionFilter : класс ReferrerHoldAttribute в файле ReferrerHoldAttribute.cs (каталог HtmlAttribute):
Он используется для хранения информации о той странице, куда надо вернуться после нажатия кнопки «New user» или ссылки на изменение пользователя: TempData[«referrer»] = ControllerContext.RouteData.Values[«referrer»];
Нам он нужен, чтобы каждый раз не писать одинаковый код в разных методах. Можно было бы написать отдельную функцию в контроллере, но если используется несколько контроллеров, то практичнее использовать специальный тип атрибута.
В дальнейшем, в теле метода, обрабатывающего действия представлений New и Edit , извлекается запомненная информация и используется для переадресации обратно на страницу, откуда были вызваны эти представления: if (TempData[«referrer»] != null) return Redirect(TempData[«referrer»].ToString());
Для определения необходимости сохранения или удаления пользователя происходит сравнение параметра action со значениями Save и Remove соответственно, и вызываются из репозитария UsersRepository функции ChangeUser(model.User) и RemoveUser(model.User) . Потом происходит возврат на предыдущую страницу (откуда был вызов представления Edit ) и там отображается сообщение об успехе операции или о неудаче.
ADO.NET и MySQL – репозитарий
Вот тут мы наконец-то добрались до работы с СУБД. Нам надо реализовать функции добавления пользователя в таблицу Users , внесение изменений в данные пользователя, удаление пользователя из таблицы, получения пользователя по идентификатору, получения списка пользователей и получения списка языков из таблицы Languages .
В основном используются стандартные конструкции для класса MySQL.Data с использованием MySqlCommand :
или MySqlDataReader для чтения строк таблицы, как результата запроса:
Создаем файл UserRepository.cs в каталоге Models:
Он содержит метод AddUser для добавления пользователя, обновления данных пользователя ( ChangeUser ), удаления ( RemoveUser ), поиска пользователя ( FetchByID ) по идентификатору и наиболее интересный метод List для вывода постраничного списка пользователей с сортировкой. Хотелось бы дополнительно прокомментировать функцию List :
- Не стоит возвращать именно таблицу ( DataTable ), как таковую – в этом случае мы потеряем в представлении возможность обращаться к элементам класса и будем вынуждены употреблять строковые константы для обращения к значениям в строке таблицы. Т.е. это будет потенциальное место для возникновения ошибок при изменении SQL-запроса. Поэтому создается список из элементов класса UserClass .
- Для добавления ограничения выборки строк из запроса используется конструкция LIMIT в SQL-операторе SELECT . К сожалению, в MySQL не поддерживаются переменные в этой части, и конструкцию LIMIT приходится конструировать вручную и добавлять к запросу. Но это полбеды, поскольку там используются целочисленные значения, а вот подобная практика для конструкции ORDER BY уже чревата нюансами в части инъекции в наш запрос вредоносного кода. Например, злоумышленник может подсунуть в качестве параметра сортировки некий SQL-конструкт, который прервет нашу команду SQL точкой с запятой, а дальше будет идти уже его команда, которая также может быть выполнена. Необходима проверка и чистка входного параметра сортировки, которая у нас осуществляется в контроллере, поэтому в данном методе мы принимаем уже два разобранных значения: название столбца по которому идёт сортировка и направление сортировки.
- После получения списка из БД мы должны запустить ещё команду SQL вида SELECT FOUND_ROWS() , которая должна нам дать общее количество строк получаемых предыдущим запросом, в котором была конструкция SELECT SQL_CALC_FOUND_ROWS без учета ограничения в LIMIT .
И файл LanguageRepository.cs в каталоге Models:
В нём есть только одна функция для получения списка языков из БД, создающая список из элементов класса LanguageClass .