Поделиться через


Добавление нового поля

Рик Андерсон

Примечание.

Обновленная версия этого руководства доступна здесь , используя последнюю версию Visual Studio. В новом руководстве используется ASP.NET Core MVC, что обеспечивает множество улучшений в этом руководстве.

В этом руководстве описывается модель MVC ASP.NET Core с контроллерами и представлениями. Razor Pages — это новая альтернатива в ASP.NET Core, модель программирования на основе страниц, которая упрощает создание веб-интерфейса и повышает производительность. Рекомендуем вам сначала попробовать изучить руководство по Razor Pages, прежде чем использовать версию для MVC. Руководство по Razor Pages:

  • проще для выполнения;
  • охватывает дополнительные возможности;
  • Предпочтительный подход для разработки новых приложений.

В этом разделе вы будете использовать миграцию Entity Framework Code First Migrations для переноса некоторых изменений в классы моделей, чтобы изменения применялись к базе данных.

По умолчанию при использовании Entity Framework Code First для автоматического создания базы данных, как и ранее в этом руководстве, Code First добавляет таблицу в базу данных, чтобы отслеживать, синхронизирована ли схема базы данных с классами моделей, из них она была создана. Если они не синхронизированы, Entity Framework выдает ошибку. Это упрощает отслеживание проблем во время разработки, которые можно найти только (по неясным ошибкам) во время выполнения.

Настройка первых миграций кода для изменений модели

Перейдите к Обозреватель решений. Щелкните правой кнопкой мыши файл Movies.mdf и выберите "Удалить ", чтобы удалить базу данных фильмов. Если файл Movies.mdf не отображается, щелкните значок "Показать все файлы", показанный ниже в красном контуре.

Снимок экрана: вкладка

Постройте приложение, чтобы убедиться в отсутствии ошибок.

В меню Сервис щелкните Диспетчер пакетов NuGet, а затем щелкните Консоль диспетчера пакетов.

Добавление человека с пакетом

В окне консоли диспетчер пакетов в строке PM> запроса введите

Enable-Migrations -ContextTypeName MvcMovie.Models.MovieDBContext

Снимок экрана: окно консоли диспетчер пакетов. Выделен текст в команде Enable Migrations.

Команда Enable-Migrations (показана выше) создает файл Configuration.cs в новой папке Migrations .

Снимок экрана: Обозреватель решений. Выбрана вложенная папка Configuration dot c папки Migrations.

Visual Studio открывает файл Configuration.cs . Замените Seed метод в файле Configuration.cs следующим кодом:

protected override void Seed(MvcMovie.Models.MovieDBContext context)
{
    context.Movies.AddOrUpdate( i => i.Title,
        new Movie
        {
            Title = "When Harry Met Sally",
            ReleaseDate = DateTime.Parse("1989-1-11"),
            Genre = "Romantic Comedy",
            Price = 7.99M
        },

         new Movie
         {
             Title = "Ghostbusters ",
             ReleaseDate = DateTime.Parse("1984-3-13"),
             Genre = "Comedy",
             Price = 8.99M
         },

         new Movie
         {
             Title = "Ghostbusters 2",
             ReleaseDate = DateTime.Parse("1986-2-23"),
             Genre = "Comedy",
             Price = 9.99M
         },

       new Movie
       {
           Title = "Rio Bravo",
           ReleaseDate = DateTime.Parse("1959-4-15"),
           Genre = "Western",
           Price = 3.99M
       }
   );
   
}

Наведите указатель мыши на красную линию Movie в нижней области и щелкните ее, а затем щелкните Show Potential Fixes с помощью MvcMovie.Models;

Снимок экрана: меню

При этом добавляется следующая инструкция using:

using MvcMovie.Models;

Примечание.

Code First Migrations вызывает Seed метод после каждой миграции (то есть вызов update-database в консоли диспетчер пакетов), и этот метод обновляет строки, которые уже вставлены, или вставляет их, если они еще не существуют.

Метод AddOrUpdate в следующем коде выполняет операцию upsert:

context.Movies.AddOrUpdate(i => i.Title,
    new Movie
    {
        Title = "When Harry Met Sally",
        ReleaseDate = DateTime.Parse("1989-1-11"),
        Genre = "Romantic Comedy",
        Rating = "PG",
        Price = 7.99M
    }

Так как метод Seed выполняется с каждой миграцией, вы не можете просто вставить данные, так как строки, которые вы пытаетесь добавить, уже будут там после первой миграции, которая создает базу данных. Операция upsert предотвращает ошибки, которые будут возникать при попытке вставить строку, которая уже существует, но переопределяет любые изменения данных, которые, возможно, были сделаны при тестировании приложения. С тестируемыми данными в некоторых таблицах может не потребоваться это сделать: в некоторых случаях при изменении данных при тестировании изменения будут оставаться после обновления базы данных. В этом случае необходимо выполнить условную операцию вставки: вставить строку только в том случае, если она еще не существует.

Первый параметр, переданный методу AddOrUpdate , указывает свойство, используемое для проверки наличия строки. Для данных тестового фильма, которые вы предоставляете, свойство можно использовать для этой цели, Title так как каждое название в списке уникально:

context.Movies.AddOrUpdate(i => i.Title,

В этом коде предполагается, что заголовки уникальны. При добавлении повторяющегося заголовка вручную вы получите следующее исключение при следующем выполнении миграции.

Последовательность содержит несколько элементов

Дополнительные сведения о методе AddOrUpdate см. в разделе "Забота о методе EF 4.3 AddOrUpdate".

Нажмите клавиши CTRL-SHIFT-B, чтобы создать проект.(Если вы не создадите сборку на этом этапе, выполните следующие действия.

Следующим шагом является создание класса для начальной DbMigration миграции. Эта миграция создает новую базу данных, поэтому вы удалили файл movie.mdf на предыдущем шаге.

В окне консоли диспетчер пакетов введите командуadd-migration Initial, чтобы создать начальную миграцию. Имя "Initial" является произвольным и используется для имени созданного файла миграции.

Снимок экрана: консоль диспетчер пакетов. Выделен текст в команде добавления миграции.

Code First Migrations создает другой файл класса в папке Migrations (с именем {DateStamp}_Initial.cs ), а этот класс содержит код, который создает схему базы данных. Имя файла миграции предварительно исправлено с меткой времени для упорядочения. Изучите файл {DateStamp}_Initial.cs , в нем содержатся инструкции по созданию Movies таблицы для базы данных Movie DB. При обновлении базы данных в приведенных ниже инструкциях этот файл {DateStamp}_Initial.cs будет запускаться и создавать схему базы данных. Затем метод Seed будет выполняться для заполнения базы данных тестовых данных.

В консоли диспетчер пакетов введите команду update-database для создания базы данных и запуска Seed метода.

Снимок экрана: консоль диспетчер пакетов. Команда базы данных обновления находится в окне.

Если возникает ошибка, указывающая, что таблица уже существует и не может быть создана, вероятно, это связано с тем, что вы запустили приложение после удаления базы данных и перед выполнением.update-database В этом случае удалите файл Movies.mdf еще раз и повторите update-database команду. Если вы по-прежнему получите ошибку, удалите папку миграции и содержимое, а затем начните с инструкций в верхней части этой страницы (то есть удалите файл Movies.mdf , а затем перейдите к enable-Migrations). Если по-прежнему возникает ошибка, откройте SQL Server обозреватель объектов и удалите базу данных из списка. Если отображается сообщение об ошибке "Не удается подключить файл .mdf в качестве базы данных", удалите свойство initial Catalog в составе строка подключения в файле web.config.

Запустите приложение и перейдите по URL-адресу /Movies . Отображаются начальные данные.

Снимок экрана: индекс фильма M V C с четырьмя фильмами, перечисленными в списке.

Добавление свойства Rating в модель Movie

Начните с добавления нового Rating свойства в существующий Movie класс. Откройте файл Models\Movie.cs и добавьте следующее Rating свойство:

public string Rating { get; set; }

Полный Movie класс теперь выглядит следующим образом:

public class Movie
{
    public int ID { get; set; }
    public string Title { get; set; }

    [Display(Name = "Release Date")]
    [DataType(DataType.Date)]
    [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
    public DateTime ReleaseDate { get; set; }
    public string Genre { get; set; }
    public decimal Price { get; set; }
    public string Rating { get; set; }
}

Создайте приложение (CTRL+SHIFT+B).

Так как вы добавили новое поле в Movie класс, необходимо также обновить список разрешений привязки, чтобы это новое свойство было включено. bind Обновите атрибут и Edit Create методы действия, чтобы включить Rating свойство:

[Bind(Include = "ID,Title,ReleaseDate,Genre,Price,Rating")]

Также необходимо обновить шаблоны представлений, чтобы реализовать отображение, создание и редактирование нового свойства Rating в представлении браузера.

Откройте файл \Views\Movies\Index.cshtml и добавьте <th>Rating</th> заголовок столбца сразу после столбца Price. Затем добавьте <td> столбец в конце шаблона для отрисовки @item.Rating значения. Ниже показано, как выглядит обновленный шаблон представления Index.cshtml :

@model IEnumerable<MvcMovie.Models.Movie>
@{
    ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>
    @Html.ActionLink("Create New", "Create")
    @using (Html.BeginForm("Index", "Movies", FormMethod.Get))
    {
    <p>
        Genre: @Html.DropDownList("movieGenre", "All")
        Title: @Html.TextBox("SearchString")
        <input type="submit" value="Filter" />
    </p>
    }
</p>
<table class="table">
    <tr>
        <th>
            @Html.DisplayNameFor(model => model.Title)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.ReleaseDate)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.Genre)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.Price)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.Rating)
        </th>

        <th></th>
    </tr>

@foreach (var item in Model) {
    <tr>
        <td>
            @Html.DisplayFor(modelItem => item.Title)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.ReleaseDate)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.Genre)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.Price)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.Rating)
        </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>

Затем откройте файл \Views\Movies\Create.cshtml и добавьте Rating поле со следующей выделенной разметкой. Это отрисовывает текстовое поле, чтобы можно было указать оценку при создании нового фильма.

<div class="form-group">
            @Html.LabelFor(model => model.Price, new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Price, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.Price, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.Rating, new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Rating, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.Rating, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Create" class="btn btn-default" />
            </div>
        </div>
    </div>
}

<div>
    @Html.ActionLink("Back to List", "Index")
</div>

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

Теперь вы обновили код приложения для поддержки нового Rating свойства.

Запустите приложение и перейдите по URL-адресу /Movies . Однако при этом вы увидите одну из следующих ошибок:

Снимок экрана: необработанные ошибки пользователя исключения.

Модель, которая поддерживает контекст MovieDBContext, изменилась с момента создания базы данных. Рекомендуется использовать кодовые миграции для обновления базы данных (https://go.microsoft.com/fwlink/?LinkId=238269).

Снимок экрана: браузер с ошибкой сервера уведомлений в приложении.

Эта ошибка возникает, так как обновленный Movie класс модели в приложении теперь отличается от схемы Movie таблицы существующей базы данных. (В таблице базы данных отсутствует столбец Rating.)

Устранить эту ошибку можно несколькими способами:

  1. Можно с помощью Entity Framework автоматически удалить и повторно создать базу данных на основе новой схемы класса модели. Этот подход удобен на ранних стадиях цикла разработки, когда все действия осуществляются с тестовой базой данных. В этом случае развитие модели и схемы базы данных осуществляется одновременно. Однако недостатком является то, что вы теряете существующие данные в базе данных, поэтому вы не хотите использовать этот подход в рабочей базе данных! При разработке приложения часто используется инициализатор для автоматического заполнения базы тестовыми данными. Дополнительные сведения о инициализаторах баз данных Entity Framework см. в руководстве по ASP.NET MVC/Entity Framework.
  2. Можно явно изменить схему существующей базы данных в соответствии с новыми классами модели. Преимущество такого подхода состоит в том, что сохраняются все данные. Это изменение можно выполнить как вручную, так и с помощью соответствующего скрипта базы данных.
  3. Можно обновить схему базы данных с помощью Code First Migrations.

В этом руководстве используется Code First Migrations.

Обновите метод Seed таким образом, чтобы он предоставлял значение для нового столбца. Откройте файл Migrations\Configuration.cs и добавьте поле "Рейтинг" в каждый объект Movie.

new Movie
{
    Title = "When Harry Met Sally",
    ReleaseDate = DateTime.Parse("1989-1-11"),
    Genre = "Romantic Comedy",
    Rating = "PG",
    Price = 7.99M
},

Создайте решение, а затем откройте окно консоли диспетчер пакетов и введите следующую команду:

add-migration Rating

Команда add-migration сообщает платформе миграции, чтобы проверить текущую модель фильма с текущей схемой базы данных фильма и создать необходимый код для переноса базы данных в новую модель. Оценка имени является произвольной и используется для имени файла миграции. Полезно использовать понятное имя для шага миграции.

По завершении этой команды Visual Studio открывает файл класса, определяющий новый DbMigration производный класс, и в методе Up можно увидеть код, создающий новый столбец.

public partial class AddRatingMig : DbMigration
{
    public override void Up()
    {
        AddColumn("dbo.Movies", "Rating", c => c.String());
    }
    
    public override void Down()
    {
        DropColumn("dbo.Movies", "Rating");
    }
}

Создайте решение и введите update-database команду в окне консоли диспетчер пакетов.

На следующем рисунке показаны выходные данные в окне консоли диспетчер пакетов (оценка метки даты будет отличаться).)

Снимок экрана: окно консоли диспетчер пакетов с введенной командой базы данных обновления.

Повторно запустите приложение и перейдите по URL-адресу /Movies. Вы можете увидеть новое поле "Оценка".

Снимок экрана: список индексов фильма M V C с добавленным полем

Щелкните ссылку "Создать" , чтобы добавить новый фильм. Обратите внимание, что можно добавить оценку.

7_CreateRioII

Нажмите кнопку Создать. Новый фильм, включая рейтинг, теперь отображается в списке фильмов:

7_ourNewMovie_SM

Теперь, когда проект использует миграции, вам не потребуется удалить базу данных при добавлении нового поля или в противном случае обновить схему. В следующем разделе мы добавим изменения схемы и используем миграции для обновления базы данных.

Вы также должны добавить Rating поле в шаблоны представлений "Изменить", "Сведения" и "Удалить".

Вы можете снова ввести команду update-database в окне консоли диспетчер пакетов и код миграции не будет выполняться, так как схема соответствует модели. Однако при выполнении метода update-database будет выполняться Seed метод снова, и если вы изменили какие-либо данные начального значения, изменения будут потеряны, так как Seed данные метода upserts. Дополнительные сведения о методе см. Seed в руководстве по популярным ASP.NET MVC/Entity Framework Tom Dykstra.

В этом разделе вы узнали, как изменить объекты модели и синхронизировать базу данных с изменениями. Вы также узнали, как заполнить только что созданную базу данных примерами данных, чтобы вы могли попробовать сценарии. Это было просто краткое введение в код first, см . статью "Создание модели данных Entity Framework" для приложения MVC ASP.NET более полного руководства по теме. Далее давайте рассмотрим, как можно добавить более богатую логику проверки в классы моделей и включить применение некоторых бизнес-правил.