Добавление модели

Rick Anderson

В этом руководстве мы добавим некоторые классы для управления роликами в БД. Эти классы будут частью “Model” в MVC.

Для работы с этими классами мы будем использовать технологию доступа к данным .NET Framework, известную как Entity Framework Core. Entity Framework Core (EF Core) раскрывает парадигму разработки, которая называется Code First. Сперва вы пишете код, а таблицы БД создаются из этого кода. Code First позволяет создавать объекты модели из простых классов. (Они также известны как POCO классы, от “plain-old CLR objects”). Если вам требуется сначала создать БД, вы все равно можете следовать этому руководству, чтобы получить информацию по MVC и EF разработке.

Создание нового проекта с отдельными пользовательскими аккаунтами

В текущей версии инструментария ASP.NET Core MVC для Visual Studio скаффолдинг модели поддерживается только тогда, когда вы создаете новый проект с отдельными пользовательскими аккаунтами. Надеюсь, скоро это будет исправлено. А пока мы создаем новый проект с тем же самым именем. Из-за этого вам нужно разместить данный проект в новой директории.

На странице Visual Studio Start нажмите New Project.

../../_images/new_project.png

Кроме того, для создания нового проекта вы можете использовать меню. Нажмите File > New > Project.

../../_images/alt_new_project.png

В диалоговом окне New Project:

  • На левой панели нажмите Web
  • На центральной панели нажмите ASP.NET Core Web Application (.NET Core)
  • Измените местоположение, чтобы оно отличалось от местоположения предыдущего проекта (директория должна быть другой), иначе выскочит ошибка
  • Назовите проект “MvcMovie” (Это важно, поскольку когда вы будете копировать код, пространство имен совпадет).
  • Нажмите OK
../../_images/new_project2.png

Предупреждение

Чтобы работал движок скаффолдинга, Authentication должна быть установлена на Individual User Accounts.

В диалоговом окне New ASP.NET Core Web Application - MvcMovie:

  • нажмите Web Application
  • нажмите кнопку Change Authentication и измените аутентификацию на Individual User Accounts, нажмите OK
../../_images/p4.png ../../_images/indiv.png

Следуйте инструкциям в Изменение названия и меню в файле с версткой, чтобы вы могли нажать ссылку MvcMovie и вызвать контроллер Movie. В этом руководстве мы проведем скаффолдинг контроллера.

Добавление классов модели

В Solution Explorer кликните правой клавишей мышки по папке Models > Add > Class. Назовите класс Movie и добавьте следующие свойства:

using System;

namespace MvcMovie.Models
{
    public class Movie
    {
        public int ID { get; set; }
        public string Title { get; set; }
        public DateTime ReleaseDate { get; set; }
        public string Genre { get; set; }
        public decimal Price { get; set; }
    }
}

Кроме нужных свойств БД требует поле ID для первичного ключа. Соберите проект. Если вы не соберете приложение, то дольше получите ошибку.

Скаффолдинг контроллера

В Solution Explorer кликните правой клавишей мышки по папке Controllers > Add > Controller.

../../_images/add_controller1.png

В диалоговом окне Add Scaffold нажмите MVC Controller with views, using Entity Framework > Add.

../../_images/add_scaffold2.png

В диалоговом окне Add Controller:

  • Model class: Movie(MvcMovie.Models)
  • Data context class: ApplicationDbContext(MvcMovie.Models)
  • Views:: не снимайте галочек с опций по умолчанию
  • Controller name: оставьте MoviesController
  • Нажмите Add
../../_images/add_controller2.png

В Visual Studio движок скаффолдинга создает следующее:

  • контроллер (Controllers/MoviesController.cs)
  • файлы представлений Razor Create, Delete, Details, Edit и Index (Views/Movies)

Visual Studio автоматически создал методы действия CRUD (create, read, update и delete) и представления (автоматическое создание действий CRUD и представлений известно как скаффолдинг). Скоро у вас появится полностью функционирующее веб приложение, которое позволит вам создавать, считывать, редактировать и удалять записи по роликам.

Если вы запустите приложение и нажмете на ссылку Mvc Movie, то выскочат следующие ошибки:

../../_images/m1.png ../../_images/pending.png

Мы последуем этим инструкция, чтобы подготовить БД для нашего приложения.

Обновление базы дынных

Предупреждение

Перед обновлением БД нужно остановить IIS Express.

Остановка IIS Express:

  • Кликните правой клавишей мышки по иконке IIS Express в уведомлениях
../../_images/iisExIcon.png
  • Нажмите Exit или Stop Site
../../_images/stopIIS.png
  • Как вариант, вы можете выйти или перезагрузить Visual Studio
  • Откройте командную строку с директорией проекта (MvcMovie/src/MvcMovie). Следуйте данным инструкциям, чтобы быстро открыть папку в директории проекта.
    • откройте файл в корневой директории проекта (для этого примера используйте Startup.cs.)
    • кликните правой клавишей мышки по Startup.cs > Open Containing Folder.

../../_images/quick.png

  • “Shift + плавая клавиша мышки” по папке > Open command window here

../../_images/folder.png

  • Запустите cd .., чтобы вернуться в директорию проекта
  • В командной строке запустите следующие команды:
dotnet ef migrations add Initial
dotnet ef database update

Примечание

Если IIS-Express запущен, выскочит ошибка CS2012: Cannot open ‘MvcMovie/bin/Debug/netcoreapp1.0/MvcMovie.dll’ for writing – ‘The process cannot access the file ‘MvcMovie/bin/Debug/netcoreapp1.0/MvcMovie.dll’ because it is being used by another process.’

Команды dotnet ef

  • dotnet (.NET Core) - это кроссплатформенная реализация .NET. См. здесь
  • dotnet ef migrations add Initial запускает миграционные команды Entity Framework .NET Core CLI и саму начальную миграцию. Параметр “Initial” не обязателен для первой (начальной) БД миграции. При этой операции создается файл Data/Migrations/<date-time>_Initial.cs, содержащий миграционные команды для добавления таблицы Movie в БД
  • dotnet ef database update обновляет БД с помощью миграции, которую мы только что создали

Тестирование приложения

Примечание

Если ваш браузер не может соединиться с приложением, подождите, как IIS Express его загрузит. Иногда это занимает до 30 секунд, пока вы не получите ответ на запрос.

  • Запустите приложение и нажмите на ссылку Mvc Movie
  • Нажмите на ссылку Create New и создайте запись о ролике
../../_images/movies.png

Примечание

Возможно, вы не сможете ввести десятичные точки или запятые в поле Price. В таком случае для поддержки валидации jQuery вам потребуется глобализовать приложение. См. Дополнительные ресурсы. А пока что вводите целые числа, например 10.

Примечание

In some locales you’ll need to specify the date format. See the highlighted code below.

using System;
using System.ComponentModel.DataAnnotations;

namespace MvcMovie.Models
{
    public class Movie
    {
        public int ID { get; set; }
        public string Title { get; set; }
        [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
        public DateTime ReleaseDate { get; set; }
        public string Genre { get; set; }
        public decimal Price { get; set; }
    }
}

При нажатии Create форма отправляется на сервер, где информация о ролике сохраняется в БД. Далее вы перенаправитесь на URL /Movies, где в списке сможете увидеть новый ролик.

../../_images/h.png

Добавьте еще несколько записей. Попробуйте поработать со ссылками Edit, Details и Delete.

Изучение сгенерированного кода

Откройте файл Controllers/MoviesController.cs и изучите сгенерированный метод Index. Часть контроллера с методом Index показана ниже:

public class MoviesController : Controller
{
    private readonly ApplicationDbContext _context;

    public MoviesController(ApplicationDbContext context)
    {
        _context = context;
    }

    // GET: Movies
    public async Task<IActionResult> Index()
    {
        return View(await _context.Movie.ToListAsync());
    }

Конструктор использует внедрение зависимостей, чтобы внедрить контекст БД в контроллер. БД контекст используется в каждом методе CRUD контроллера.

Запрос к контроллеру Movies возвращает все записи тыблицы Movies, а затем передает данные представлению Index.

Строго типизированные модели и ключевое слово @model

Ранее мы рассмотрели, как контроллер передает данные или объекты представлению, используя словарь ViewData. Словарь ViewData - это динамический объект, который предлагает удобный способ передачи информации представлению.

MVC также дает возможность передавать представлению строго типизированные объекты. Такой подход улучшает проверку кода во время компиляции и предлагает более богатые возможности IntelliSense в Visual Studio (VS). Механизм скаффолдинга в VS использовал такой подход с классом MoviesController и представлениями, когда создавал методы и представления.

Изучите сгенерированный метод Details в файле Controllers/MoviesController.cs:

// GET: Movies/Details/5 
public async Task<IActionResult> Details(int? id)
{
    if (id == null)
    {
        return NotFound();
    }

    var movie = await _context.Movie.SingleOrDefaultAsync(m => m.ID == id);
    if (movie == null)
    {
        return NotFound();
    }

    return View(movie);
}

Параметр id передается как роутовые данные, например http://localhost:1234/movies/details/1 устанавливает:

  • контроллер на контроллер movies (первый URL сегмент)
  • метод действия на details (второй URL сегмент)
  • id на 1 (последний URL сегмент)

Также вы можете передать id со строкой запроса:

http://localhost:1234/movies/details?id=1

Если Movie найден, экземпляр модели Movie передается представлению Details:

return View(movie);

Изучите контекст файла Views/Movies/Details.cshtml:

@model MvcMovie.Models.Movie

@{
    ViewData["Title"] = "Details";
}

<h2>Details</h2>

<div>
    <h4>Movie</h4>
    <hr />
    <dl class="dl-horizontal">
        <dt>
            @Html.DisplayNameFor(model => model.Genre)
        </dt>
        <dd>
            @Html.DisplayFor(model => model.Genre)
        </dd>
        <dt>
            @Html.DisplayNameFor(model => model.Price)
        </dt>
        <dd>
            @Html.DisplayFor(model => model.Price)
        </dd>
        <dt>
            @Html.DisplayNameFor(model => model.ReleaseDate)
        </dt>
        <dd>
            @Html.DisplayFor(model => model.ReleaseDate)
        </dd>
        <dt>
            @Html.DisplayNameFor(model => model.Title)
        </dt>
        <dd>
            @Html.DisplayFor(model => model.Title)
        </dd>
    </dl>
</div>
<div>
    <a asp-action="Edit" asp-route-id="@Model.ID">Edit</a> |
    <a asp-action="Index">Back to List</a>
</div>

Включив выражение @model в файл представления сверху, вы можете указать тип объекта, который ожидает представление. Когда вы создали контроллер, Visual Studio автоматически включил следующее выражение @model сверху файла Details.cshtml:

@model MvcMovie.Models.Movie

Эта директива @model позволяет получить доступ к ролику, который контроллер передал представлению, используя строго типизированный объект Model. Например, в представлении Details.cshtml код передает каждое поле с роликами вспомогательным методам HTML DisplayNameFor и DisplayFor с помощью строго типизированного объекта Model. Методы Create и Edit, а также представления передают объект модели Movie.

Изучите представление Index.cshtml и метод Index в контроллере Movies. Обратите внимание, как создается объект List, когда вызывается метод View. Код передает этот список Movies из метода действия Index представлению:

// GET: Movies
public async Task<IActionResult> Index()
{
    return View(await _context.Movie.ToListAsync());
}

Когда вы создали контроллер, Visual Studio автоматически включил следующее выражение @model в файл Index.cshtml сверху:

@model IEnumerable<MvcMovie.Models.Movie>

Директива @model позволяет получить доступ к списку роликов, которые контроллер передал представлению, используя строго типизированный объект Model. Например, в представлении Index.cshtml код проходит циклом по роликам с помощью foreach в строго типизированном объекте Model:

@model IEnumerable<MvcMovie.Models.Movie>

@{
    ViewData["Title"] = "Index";
}

<h2>Index</h2>

<p>
    <a asp-action="Create">Create New</a>
</p>
<table class="table">
    <thead>
        <tr>
            <th>
                @Html.DisplayNameFor(model => model.Genre)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Price)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.ReleaseDate)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Title)
            </th>
            <th></th>
        </tr>
    </thead>
    <tbody>
@foreach (var item in Model) {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.Genre)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Price)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.ReleaseDate)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Title)
            </td>
            @*<snippet_1>*@
            <td>
                <a asp-action="Edit" asp-route-id="@item.ID">Edit</a> |
                <a asp-action="Details" asp-route-id="@item.ID">Details</a> |
                <a asp-action="Delete" asp-route-id="@item.ID">Delete</a>
            </td>
            @*</snippet_1>*@
        </tr>
}
    </tbody>
</table>

Поскольку объект Model является строго типизированным (как объект IEnumerable<Movie>), каждый элемент в цикле прописывается как Movie.

../../_images/ints.png

Теперь у вас есть БД и страницы для создания, редактирования, обновления и удаления данных.

Дополнительные ресурсы

Поделись хорошей новостью с друзьями!
Следи за новостями!