Предыдущие части.
Уроки по 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<Book>().ToList(); //Отображение данных из таблицы Book //Создаем критерий для выборки книг var criteria = session.CreateCriteria<Book>(); //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<Book> var books = criteria.List<Book>(); return View(books); } }
Небольшое объяснение
- var criteria = session.CreateCriteria<Book>(); — подобно выполнению скрипта 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 ISet<Genre> Genres{ 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<BibliotecaTutor.Models.Book> @{ Layout = null; } <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>Index</title> <style> th,td {border: 1px solid; } </style> </head> <body> <p>@Html.ActionLink("Create New", "Create")</p> <table> <tr> <th>@Html.DisplayNameFor(model => model.Image)</th> <th>@Html.DisplayNameFor(model => model.Name)</th> <th>@Html.DisplayNameFor(model => model.MfRaiting)</th> <th>@Html.DisplayNameFor(model => model.Mind)</th> <th>@Html.DisplayNameFor(model => model.Series)</th> <th>@Html.DisplayNameFor(model => model.Genres)</th> <th>@Html.DisplayNameFor(model => model.Authors)</th> <th>Операции</th> </tr> @foreach (var item in Model) { <tr> <td> <img src="~/Content/img/@item.Image" /></td>//Ссылка на рисунки <td>@Html.DisplayFor(modelItem => item.Name)</td> <td>@Html.DisplayFor(modelItem => item.MfRaiting)</td> <td>@Html.DisplayFor(modelItem => item.Mind.MyMind)</td> <td>@Html.DisplayFor(modelItem => item.Series.Name)</td> <td> @foreach (var genre in item.Genres) { @Html.DisplayFor(modelItem => genre.Name) <br /> } </td> <td> @foreach (var author in item.Authors) { @Html.DisplayFor(modelItem => author.Name) <br /> } </td> <td> @Html.ActionLink("Edit", "Edit", new { id = item.Id }) | @Html.ActionLink("Details", "Details", new { id = item.Id }) | @Html.ActionLink("Delete", "Delete", new { id = item.Id }) </td> </tr> } </table> </body> </html>
После этих всех действий запускаем проект и видим вот такую таблицу:
Дополнительный материал.
Знакомые с Nhibernate, увидев следующие строчки
//Создаем критерий для выборки книг var criteria = session.CreateCriteria<Book>(); //Left Join с таблицей Genres criteria.CreateAlias("Genres", "genre", JoinType.LeftOuterJoin); ****** DistinctRootEntityResultTransformer()); var books = criteria.List<Book>();
могут спросить: «Ну и где тут FluentNhibernate, поддержка intellisense?» выкладываю запись, предназначенная только для fluentNhibernate, действие которой аналочно действию коду выше.
//Методы с поддержкой intellisense Book bookAl = null; Genre genreAl = null; IQueryOver<Book, Book> bookQuery = session.QueryOver<Book>(() => bookAl) .JoinAlias(() => bookAl.Genres, () => genreAl, JoinType.LeftOuterJoin) .TransformUsing(Transformers.DistinctRootEntity); var books = bookQuery.List<Book>();
Мне он не нравится тем, что нужно создавать лишние (в данном примере) переменные, которые я далее в коде не использую, да и следующие значения, «IQueryOver<Book, Book>» и "()" — не совсем понятны… Какой из методов использовать, конечно же, решать программисту.
Для тех, кто любит писать 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<Book>().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<Triangle> { public TriangleMap() { Id(x => x.Id); Map(x => x.Style); Map(x => x.Height); Map(x => x.Width); } }
После запуска приложения, в БД Biblioteca появится следующая (пустая) таблица
ссылка на оригинал статьи http://habrahabr.ru/post/265087/
Добавить комментарий