Часть 3. Отображение данных из таблицы (Операция LIST)
Предыдущие части.
Уроки по FluentNHibernate c ASP.NET MVC и SQL Server. Часть 1
Часть 2. Создание классов, маппингов и заполнение БД
В предыдущей части было рассмотрено создание классов и маппинг-классов к ним. В 3 кратких таблицах были представлены маппинги связей один-к-одному, один-ко-многим, многие-ко-многим. Заполнили таблицы в sql server’e данными. В этой статье отобразим данные из БД в представлении View. Вначале добавим изображения в проект.
Отображение данных из таблицы в представление
Прежде чем создавать представление, для начала добавим в приложение изображения. Создадим в папке Content папку img.
и добавим туда изображения, к примеру, обложки этих книг.
yadi.sk/a/OZVgEhJ1iXukT
Далее изменим контроллер, чтобы он отображал все данные, связанные с книгой.
public ActionResult Index()
{
using (ISession session = NHibernateHelper.OpenSession()) {
//var book = session.Query().ToList(); //Отображение данных из таблицы Book
//Создаем критерий для выборки книг
var criteria = session.CreateCriteria();
//Left Join с таблицей Genres
criteria.CreateAlias("Genres", "genre", JoinType.LeftOuterJoin);
criteria.CreateAlias("Series", "series", JoinType.LeftOuterJoin);
criteria.CreateAlias("Mind", "mind", JoinType.LeftOuterJoin);
criteria.CreateAlias("Authors", "author", JoinType.LeftOuterJoin);
//Убирает повторяющиеся id номера таблицы Book.
criteria.SetResultTransformer(new DistinctRootEntityResultTransformer());
//Приводит критерий к коллекции list
var books = criteria.List();
return View(books);
}
}
Небольшое объяснение
- var criteria = session.CreateCriteria
(); — подобно выполнению скрипта SQL: Select * From Book; - criteria.CreateAlias («Genres», «genre», JoinType.LeftOuterJoin); — подобно выполнению скрипта SQL:
SELECT *FROM Book
inner JOIN Book_Genre ON book.id = Book_Genre.Book_id
LEFT JOIN Genre ON Book_Genre.Genre_id = Genre.id - criteria.SetResultTransformer (new DistinctRootEntityResultTransformer ()); — Подобно выполнению скрипта SQL: SELECT distinct Book.Id…, (убирает дублирующие записи с одинаковыми id)
criteria.CreateAlias («Genres», «genre», JoinType.LeftOuterJoin); — первый аргумент «Genres» должен быть такой же, как и наименование коллекции в классе Book: public virtual ISetGenres{ get; set; }.
Второй аргумент «genre» — это псевдоним, который мы будем использовать в критериях.
Виды объединений
criteria.CreateAlias («Genres», «genre», JoinType.LeftOuterJoin);
- LeftOuterJoin — выбирает все записи из левой таблицы (Book), а затем присоединяет к ним записи правой таблицы (Genre). Если не найдена соответствующая запись в правой таблицы, отображает её как Null
- RightOuterJoin действует в противоположность LEFT JOIN — выбирает все записи из правой таблицы (Genre), а затем присоединяет к ним записи левой таблицы (Book)
- InnerJoin — выбирает только те записи из левой таблиц (Book) у которой есть соответствующая запись из правой таблицы (Genre), а затем присоединяет к ним записи из правой таблицы
Далее переделаем страницу Index.cshtml следующим образом.
@model IEnumerable
@{ Layout = null; }
Index
@Html.ActionLink("Create New", "Create")
@Html.DisplayNameFor(model => model.Image)
@Html.DisplayNameFor(model => model.Name)
@Html.DisplayNameFor(model => model.MfRaiting)
@Html.DisplayNameFor(model => model.Mind)
@Html.DisplayNameFor(model => model.Series)
@Html.DisplayNameFor(model => model.Genres)
@Html.DisplayNameFor(model => model.Authors)
Операции
@foreach (var item in Model) {
//Ссылка на рисунки
@Html.DisplayFor(modelItem => item.Name)
@Html.DisplayFor(modelItem => item.MfRaiting)
@Html.DisplayFor(modelItem => item.Mind.MyMind)
@Html.DisplayFor(modelItem => item.Series.Name)
@foreach (var genre in item.Genres) {
@Html.DisplayFor(modelItem => genre.Name)
}
@foreach (var author in item.Authors) {
@Html.DisplayFor(modelItem => author.Name)
}
@Html.ActionLink("Edit", "Edit", new { id = item.Id }) |
@Html.ActionLink("Details", "Details", new { id = item.Id }) |
@Html.ActionLink("Delete", "Delete", new { id = item.Id })
}
После этих всех действий запускаем проект и видим вот такую таблицу:
Дополнительный материал.
Знакомые с Nhibernate, увидев следующие строчки
//Создаем критерий для выборки книг
var criteria = session.CreateCriteria();
//Left Join с таблицей Genres
criteria.CreateAlias("Genres", "genre", JoinType.LeftOuterJoin);
******
DistinctRootEntityResultTransformer());
var books = criteria.List();
могут спросить: «Ну и где тут FluentNhibernate, поддержка intellisense?» выкладываю запись, предназначенная только для fluentNhibernate, действие которой аналочно действию коду выше.
//Методы с поддержкой intellisense
Book bookAl = null; Genre genreAl = null;
IQueryOver bookQuery =
session.QueryOver(() => bookAl)
.JoinAlias(() => bookAl.Genres, () => genreAl, JoinType.LeftOuterJoin)
.TransformUsing(Transformers.DistinctRootEntity);
var books = bookQuery.List();
Мне он не нравится тем, что нужно создавать лишние (в данном примере) переменные, которые я далее в коде не использую, да и следующие значения, «IQueryOver
Для тех, кто любит писать SQL-скрипты, у Nhibernate найдется и для таких инструмент:
//SQl-запрос
var queryBook = string.Format(@"select Id, Name, Description, MfRaiting, PageNumber, Image, IncomeDate from Book");
//Вывод списка всех книг
var books = session.CreateSQLQuery(queryBook)
//SQl-запрос ассоциирует с классом
.SetResultTransformer(Transformers.AliasToBean(typeof(Book)))
.List().ToList();
*Небольшое замечание… в отличие от SQL-скрипта, тут учитываются регистр букв, то есть Id и id — это разные слова.
**Также мы должны выбрать ВСЕ поля, которые есть в классе Book, нельзя выбрать, к примеру только Id и Name. Если ж требуется выбрать определенные поля, то под них следует создать новый класс.
***Почему мы перечислили все поля, а не использовали следующий скрипт Select * from Book? В таблице Book у нас есть поле Series_Id, которого нет в классе Book
Маппинг для классов, у которых есть наследование.
А как маппить классы у которых есть наследование? Допустим, имеем такой пример:
//Класс Двумерных фигур
public class TwoDShape {
//Ширина
public virtual int Width { get; set; }
//Высота
public virtual int Height { get; set; }
}
//Класс треугольник
public class Triangle : TwoDShape {
//Идентификационный номер
public virtual int Id { get; set; }
//Вид треугольника
public virtual string Style { get; set; }
}
В принципе, ничего сложного в этом маппинге нет, мы просто создадим один маппинг для производного класса, то есть таблицы Triangle.
//Маппинг треугольника
public class TriangleMap : ClassMap {
public TriangleMap() {
Id(x => x.Id);
Map(x => x.Style);
Map(x => x.Height);
Map(x => x.Width);
}
}
После запуска приложения, в БД Biblioteca появится следующая (пустая) таблица