Пояснительная записка. Трач РВ (1228539), страница 4
Текст из файла (страница 4)
var spisok = (from i in db.ЭК_связи where i.ЭК == Сriterion orderby i.ЭК select i).ToList();
ViewData["Criterion"] = Сriterion;
ViewData["ItemsCount"] = spisok.Count();
ViewData["MainInfo"] = EK.Information(Сriterion).ToArray();
return View(spisok);
}
return View();
}
protected override void Dispose(bool disposing){
db.Dispose();
base.Dispose(disposing);
}}
}
Стоит отметить, что наличие метода по закрытию соединения с БД обязателен, т.к. его отсутствие повлечёт неконтролируемые ошибки в обмене данными.
-
Страничная навигация
Часто при отображении большого количества информации встаёт проблема в удобстве чтения. Популярным механизмом порционного вывода табличных данных является страничная навигация. Сложность осуществления таковой в Web-приложении состоит в логическом просчёте ссылок на одну и более страниц вперёд/назад, т.к. при переходе по ссылкам, страница остаётся неизменной, в то время как ссылки должны измениться. Так же следует «научить» контроллер отображать то количество информации на странице, сколько нужно.
Итак, для начала создаётся глобальная переменная «PageSize», которая хранит в себе количество строк по умолчанию, доступных для вывода на одну страницу[ CITATION 20П \l 1049 ]. Затем осуществляется функция по выборке из БД нужное количество отсортированных данных:
public ActionResult EK(string Сriterion, string Category, int PageNum = 0){
string zapros = "select * from ЭК";
if (!String.IsNullOrEmpty(Сriterion) && !String.IsNullOrEmpty(Category)){
zapros += " where " + Category + " = '" + Сriterion + "'";}
zapros = zapros = FilrFromZone(zapros);
var all = db.Database.SqlQuery<ЭК>(zapros);
var spisok = all.Skip(PageSize*PageNum).Take(PageSize).ToList();
ViewGo(PageNum, all.Count(), Сriterion, Category);
return View(spisok);
}
Следует отметить, что функция «ViewGo» нужна для оптимизации кода и реализует передачу вспомогательных данных, передаваемых в представление посредством нетипизированного объекта «ViewData»:
private void ViewGo(int PageNum, int ItemsCount, string Сriterion = "", string Category = ""){
ViewData["PageNum"] = PageNum;
ViewData["PageSize"] = PageSize;
ViewData["ItemsCount"] = ItemsCount;
ViewData["СRITERION"] = Сriterion;
ViewData["CATEGORY"] = Category;
}
Далее следует создать так называемый «Html-helper»[ CITATION Маг10 \l 1033 ]. Его предназначение – генерировать чистый html-код на основе вставок в представление C#-инструкций, выделенных особым оператором «@{}» при использовании Razor. Такой подход позволяет оптимизировать и расширить стандартные возможности web-проектирования.
<div class="numeric">
@Html.PagingNavigator((int)Html.ViewData["PageNum"], (int)Html.ViewData["ItemsCount"], (int)Html.ViewData["PageSize"], 5, "Staff", param)
</div>
В данном случае вызывается метод «PagingNavigator», в который передаётся набор аргументов. Можно заметить, что большинство аргументов связаны с нетипизированным объектом «ViewData», который был получен из контроллера.
Метод «PagingNavigator» содержит логику по вычислению url-ссылок для страничной навигации и возвращает html-код следующим образом:
namespace MVCintranet.Helpers{
public static class Paging{
public static MvcHtmlString PagingNavigator(this HtmlHelper helper,
int pageNum, int itemsCount,int pageSize,int linksPerPage = 10, string actionName = "Index", RouteValueDictionary routeVals = null){
StringBuilder sb = new StringBuilder();
int pagesCount = (int)Math.Ceiling((double)itemsCount / pageSize);
int startPage = pageNum / linksPerPage * linksPerPage;
int visiblePages = startPage + linksPerPage <=
pagesCount ? linksPerPage : pagesCount - startPage;
if (pageNum > 0){
routeVals["pageNum"] = 0;
sb.Append(helper.ActionLink("<<", actionName, routeVals));
sb.Append(" ");
int pageBackNum = startPage - 1;
if (pageBackNum > 0){
routeVals["pageNum"] = pageBackNum;
sb.Append(helper.ActionLink("<", actionName, routeVals));}else{
sb.Append(HttpUtility.HtmlEncode("<"));}}
else{
sb.Append(HttpUtility.HtmlEncode("<< <"));}
sb.Append(" ");}}
-
Взаимодействие пользователя с базой данных
При работе пользователя с любой информационной системой происходит обмен информацией в двустороннем порядке. Информация, которую хочет получить пользователь, находится в хранилище данных СУБД. Для доступа к данным, как уже отмечалось ранее, необходимо создать экземпляр контекста данных и метод, отвечающий за закрытие соединения. Непосредственные выборки данных по критериям можно осуществлять двумя способами: по средством интегрированного языка LINQ и с использованием процедурного расширения SQL – языка транзакций T-SQL.
LINQ – это название набора технологий, основанных на интеграции возможностей запроса непосредственно в язык C# (а также в Visual Basic и, возможно, в любые другие языки .NET) [ CITATION Соз1 \l 1033 ]. Благодаря LINQ запрос теперь является одним из основных структурных элементов языка, подобно классам, методам, событиям и т. д[ CITATION MSD \l 1049 ].
Выражения, написанные на LINQ, отличаются простотой и лаконичностью. Классическим примером выборки данных этим способом является фильтр по одному критерию с сортировкой по дополнительному полю. Таким способом реализована функция поиска списка изменений для ЭК:
public ActionResult Changes(string id){
ViewBag.Message = "Наряд" + id;
var spisok = (from i in db.изменения where i.ЭК == id orderby i.ВРЕМЯ_ЗАКРЫТИЯ descending select i).ToList();
return View(spisok);
}
LINQ помогает разработчику писать сложные SQL-запросы, абстрагируясь на уровне классов и методов. Однако конечный SQL-код, сгенерированный библиотеками может оказаться слишком большим. Это нужно иметь ввиду, когда необходима скорость выполнения запросов.
Классический язык T-SQL удобен в тех случаях, когда появляется необходимость оптимизировать код. В частности, возникают ситуации, когда входные параметры соответствуют полям контекста базы данных. В таких случаях удобно собирать «на лету» чистый T-SQL запрос, конкатенируя строки. Примером такого решения служит метод, возвращающий список рабочих групп с учётом поиска по выбранной категории:
public ActionResult WorkGroups(string Сriterion, string Category, int PageNum = 0){
string zapros = "select * from [рабочие группы]";
if (!String.IsNullOrEmpty(Сriterion) && !String.IsNullOrEmpty(Category)){
zapros += " where " + Category + " = '" + Сriterion + "'";
}
zapros = FilrFromZone(zapros);
var all = db.Database.SqlQuery<рабочие_группы>(zapros);
var spisok = all.Skip(PageSize * PageNum).Take(PageSize).ToList();
ViewGo(PageNum, all.Count(), Сriterion, Category);
return View(spisok);
}
В этом примере метод «ActionResult WorkGroups», принимающий три аргумента (один из которых – номер текущей страницы), формирует T-SQL запрос на основе критерия и категории поиска[ CITATION Уче \l 1033 ].
Для структурированного отображения выбранных данных в MVC используются преимущественно таблицы:
<table class="simple-little-table">
<tr>
<th>Номер</th>
<th>Имя</th>
<th>Шаблон наряда</th>
<th>Рабочая группа</th>
<th>Описание</th>
<th>Зона ответственности</th>
</tr>
@foreach (MVCintranet.Models.расписания_регламентных_работ b in Model){
<tr>
<td><a href="@Url.Action("RegWorks", "Details", new { Id = b.НОМЕР })">@b.НОМЕР</a></td>
<td><p>@b.ИМЯ</p></td>
<td><p>@b.ШАБЛОН_НАРЯДА</td>
<td><p>@b.РАБОЧАЯ_ГРУППА</p></td>
<td><p>@b.ОПИСАНИЕ</p></td>
<td><p>@b.ЗОНА_ОТВЕТСТВЕННОСТИ</p></td>
</tr>
}
</table>
Теперь, чтобы связать представление с передаваемым параметром, надо добавить в представление директиву @model с указанием типа передаваемых данных[ CITATION Net \l 1049 ]. Поскольку класс «расписания регламентных работ» представляет тип IEnumerable< >, то представление будет выглядеть так:
@model IEnumerable<MVCintranet.Models.расписания_регламентных_работ>
По схожему принципу функционируют все страницы в текущем Web-приложении.
-
Поиск по критерию
Очевидно, что для поиска по критерию пользователю необходимо предоставить необходимые элементы управления, чтобы в обработку не попали недопустимые значения. Отличным решением такой задачи служит связка выпадающего списка, поля для ввода данных и кнопкой «Найти» (рисунок 15).
-
Поиск по выбираемому параметру
Для реализации пользовательской части формы поиска необходимо включить в представление следующее Razor-выражение:
@using MVCintranet.Helpers
@{
ViewBag.Title = "Расписание регламентных работ";
RouteValueDictionary param = new RouteValueDictionary(ViewContext.RouteData.Values);
param["Сriterion"] = ViewData["СRITERION"];
param["Category"] = ViewData["CATEGORY"] != null ? ViewData["CATEGORY"] : "";
var selectItems = new List<SelectListItem>() {
new SelectListItem() { Text = "Номер", Value = "НОМЕР"},
new SelectListItem() { Text = "ЭК", Value = "ЭК"},
new SelectListItem() { Text = "Рабочая группа", Value = "ИСПОЛНИТЕЛЬ"},
};
var selected = selectItems.FirstOrDefault(sli => sli.Value == param["Category"]);
if (selected != null) { selected.Selected = true; }
}
Затем, в нужной части кода следует поместить блок поиска [ CITATION Отр \l 1049 ]:
<div class="search">
@using (Html.BeginForm()){
Выберите категорию: @Html.DropDownList("Category", selectItems, htmlAttributes: new { size = 1 })
Строка поиска: @Html.TextBox("Сriterion")
<button>Найти</button>
}
</div>
Такой подход позволят сохранить выбранной текущую категорию поиска при переходе на следующую страницу результатов.
-
Взаимодействие со связанными данными
Для полноценности работы с данными нужно дополнить действующий функционал перекрёстными ссылками, моделируя ситуацию, когда пользователь хочет просмотреть ЭК или рабочую группу, просматривая детальную информацию по инциденту. Для этого достаточно передать ID события из контроллера в модель и обработать вывод следующим образом, обозначая url-адрес:
@foreach (MVCintranet.Models.изменения b in Model)
{
<tr>
<td><a href="@Url.Action("Changes", "Details", new { Id = b.НОМЕР })">@b.НОМЕР</a></td>
<td><p>@b.ИНИЦИАТОР</p></td>
<td><p>@b.ИСТОЧНИК</p></td>
<td><p>@b.ИСПОЛНИТЕЛЬ</p></td>
<td><p>@b.РЕШЕНИЕ</p></td>
</tr>
}
Такой подход обеспечивает генерирование страниц, освобождая разработчика от необходимости создавать всё новые и новые html-документы в каталоге проекта.
-
Визуализация статистики
Для визуализации статистики необходимы данные, которые в явном виде отсутствуют. Для их получения необходим класс «Statistics» с методами, производящие счёт необходимых показателей и возвращающие численное значение интересующего параметра.
namespace MVCintranet.Models{
public class Statistics{
public string Name { get; set; }
public int Kol { get; set; }
private readonly MAO2Context db = new MAO2Context();
public int KolRegWorks(string Zone)
{
Kol = (from i in db.расписания_регламентных_работ where i.ЗОНА_ОТВЕТСТВЕННОСТИ == Zone select i).Count();
return (Kol);
}











