Часть 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<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);        } } 

Небольшое объяснение

  1. var criteria = session.CreateCriteria<Book>(); — подобно выполнению скрипта SQL: Select * From Book;
  2. 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
  3. 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);

  1. LeftOuterJoin — выбирает все записи из левой таблицы (Book), а затем присоединяет к ним записи правой таблицы (Genre). Если не найдена соответствующая запись в правой таблицы, отображает её как Null
  2. RightOuterJoin действует в противоположность LEFT JOIN — выбирает все записи из правой таблицы (Genre), а затем присоединяет к ним записи левой таблицы (Book)
  3. 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/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *