Compartilhar via


Adicionando um Novo Campo

por Rick Anderson

Observação

Uma versão atualizada deste tutorial está disponível aqui usando a versão mais recente do Visual Studio. O novo tutorial usa ASP.NET Core MVC, que fornece muitas melhorias em relação a este tutorial.

Este tutorial ensina a usar o ASP.NET Core MVC com controladores e exibições. O Razor Pages é uma nova alternativa no ASP.NET Core, um modelo de programação baseado em página que torna a criação da interface do usuário da Web mais fácil e produtiva. É recomendável que você tente o tutorial das Páginas Razor antes da versão do MVC. O tutorial Páginas do Razor:

  • É mais fácil de acompanhar.
  • Aborda mais recursos.
  • É a abordagem preferencial para o desenvolvimento de novos aplicativos.

Nesta seção, você usará as Migrações do Code First do Entity Framework para migrar algumas alterações nas classes de modelo para que a alteração seja aplicada ao banco de dados.

Por padrão, quando você usa o Entity Framework Code First para criar automaticamente um banco de dados, como fez anteriormente neste tutorial, o Code First adiciona uma tabela ao banco de dados para ajudar a controlar se o esquema do banco de dados está em sincronia com as classes de modelo das quais ele foi gerado. Se eles não estiverem sincronizados, o Entity Framework gerará um erro. Isso facilita o rastreamento de problemas no tempo de desenvolvimento que, de outra forma, você só encontraria (por erros obscuros) em tempo de execução.

Configurando migrações do Code First para alterações de modelo

Navegue até Gerenciador de Soluções. Clique com o botão direito do mouse no arquivo Movies.mdf e selecione Excluir para remover o banco de dados de filmes. Se você não vir o arquivo Movies.mdf , clique no ícone Mostrar todos os arquivos mostrado abaixo no contorno vermelho.

Captura de tela que mostra a guia Controlador de Filmes dot c s e o Gerenciador de Soluções aberto. O ícone Mostrar todos os arquivos está circulado em vermelho.

Compile o aplicativo para verificar se não existem erros.

No menu Ferramentas, clique em Gerenciador de Pacotes NuGet e, em seguida, em Console do Gerenciador de Pacotes.

Adicionar Pack Man

Na janela Console do Gerenciador de Pacotes , no prompt, PM> digite

Enable-Migrations -ContextTypeName MvcMovie.Models.MovieDBContext

Captura de tela que mostra a janela do Console do Gerenciador de Pacotes. O texto no comando Ativar Migrações é realçado.

O comando Enable-Migrations (mostrado acima) cria um arquivo Configuration.cs em uma nova pasta Migrations .

Captura de tela que mostra o Gerenciador de Soluções. A subpasta Configuration dot c s da pasta Migrações está selecionada.

O Visual Studio abre o arquivo Configuration.cs . Substitua o Seed método no arquivo Configuration.cs pelo seguinte código:

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
       }
   );
   
}

Passe o mouse sobre a linha ondulada vermelha abaixo Movie e clique e Show Potential Fixes clique em usando MvcMovie.Models;

Captura de tela que mostra o menu Mostrar possíveis correções. Usando modelos de pontos de filme MVC é selecionado e um alerta não pode ser encontrado é exibido.

Isso adiciona a seguinte instrução using:

using MvcMovie.Models;

Observação

As Migrações do Code First chamam o Seed método após cada migração (ou seja, chamando update-database no Console do Gerenciador de Pacotes) e esse método atualiza as linhas que já foram inseridas ou as insere se ainda não existirem.

O método AddOrUpdate no código a seguir executa uma operação "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
    }

Como o método Seed é executado com cada migração, você não pode simplesmente inserir dados, porque as linhas que você está tentando adicionar já estarão lá após a primeira migração que cria o banco de dados. A operação "upsert" evita erros que ocorreriam se você tentasse inserir uma linha que já existe, mas substitui quaisquer alterações nos dados que você possa ter feito durante o teste do aplicativo. Com dados de teste em algumas tabelas, talvez você não queira que isso aconteça: em alguns casos, quando você altera dados durante o teste, deseja que suas alterações permaneçam após as atualizações do banco de dados. Nesse caso, você deseja fazer uma operação de inserção condicional: insira uma linha somente se ela ainda não existir.

O primeiro parâmetro passado para o método AddOrUpdate especifica a propriedade a ser usada para verificar se uma linha já existe. Para os dados do filme de teste que você está fornecendo, a Title propriedade pode ser usada para essa finalidade, pois cada título na lista é exclusivo:

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

Esse código pressupõe que os títulos são exclusivos. Se você adicionar manualmente um título duplicado, receberá a seguinte exceção na próxima vez que executar uma migração.

A sequência contém mais de um elemento

Para obter mais informações sobre o método AddOrUpdate, consulte Tomar cuidado com o método AddOrUpdate do EF 4.3.

Pressione CTRL-SHIFT-B para criar o projeto.(As etapas a seguir falharão se você não compilar neste momento.)

A próxima etapa é criar uma DbMigration classe para a migração inicial. Essa migração cria um novo banco de dados, por isso você excluiu o arquivo movie.mdf em uma etapa anterior.

Na janela Console do Gerenciador de Pacotes , insira o comando add-migration Initial para criar a migração inicial. O nome "Inicial" é arbitrário e é usado para nomear o arquivo de migração criado.

Captura de tela que mostra o Console do Gerenciador de Pacotes. O texto no comando adicionar migração é realçado.

As Migrações do Code First criam outro arquivo de classe na pasta Migrações (com o nome {DateStamp}_Initial.cs ), e essa classe contém código que cria o esquema de banco de dados. O nome do arquivo de migração é previamente corrigido com um carimbo de data/hora para ajudar com a ordenação. Examine o arquivo {DateStamp}_Initial.cs , ele contém as instruções para criar a Movies tabela para o banco de dados de filmes. Quando você atualiza o banco de dados nas instruções abaixo, esse arquivo {DateStamp}_Initial.cs é executado e cria o esquema de banco de dados. Em seguida, o método Seed será executado para preencher o banco de dados com dados de teste.

No Console do Gerenciador de Pacotes, insira o comando update-database para criar o banco de dados e executar o Seed método.

Captura de tela que mostra o Console do Gerenciador de Pacotes. O comando update database está na janela.

Se você receber um erro que indica que uma tabela já existe e não pode ser criada, provavelmente é porque você executou o aplicativo depois de excluir o banco de dados e antes de executar update-database. Nesse caso, exclua o arquivo Movies.mdf novamente e tente novamente o update-database comando. Se você ainda receber um erro, exclua a pasta de migrações e o conteúdo e comece com as instruções na parte superior desta página (ou seja, exclua o arquivo Movies.mdf e prossiga para Enable-Migrations). Se você ainda receber um erro, abra o Pesquisador de Objetos do SQL Server e remova o banco de dados da lista. Se você receber um erro indicando "Não é possível anexar o arquivo .mdf como banco de dados", remova a propriedade Catálogo Inicial como parte da cadeia de conexão no arquivo web.config .

Execute o aplicativo e navegue até a URL / Movies . Os dados de semente são exibidos.

Captura de tela que mostra o Índice de Filmes MVC com quatro filmes listados.

Adicionando uma propriedade de classificação ao modelo de filme

Comece adicionando uma nova Rating propriedade à classe existente Movie . Abra o arquivo Models\Movie.cs e adicione a Rating propriedade como esta:

public string Rating { get; set; }

A classe completa Movie agora se parece com o seguinte código:

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; }
}

Construa o aplicativo (Ctrl+Shift+B).

Como você adicionou um novo campo à Movie classe, também precisa atualizar a lista de permissões de associação para que essa nova propriedade seja incluída. Atualize o atributo e Edit Create os bind métodos de ação para incluir a Rating propriedade:

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

Você também precisa atualizar os modelos de exibição para exibir, criar e editar a nova propriedade Rating na exibição do navegador.

Abra o arquivo \Views\Movies\Index.cshtml e adicione um título de <th>Rating</th> coluna logo após a coluna Preço . Em seguida, adicione uma <td> coluna perto do final do modelo para renderizar o @item.Rating valor. Abaixo está a aparência do modelo de exibição Index.cshtml atualizado:

@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>

Em seguida, abra o arquivo \Views\Movies\Create.cshtml e adicione o campo com a marcação realçada Rating a seguir. Isso renderiza uma caixa de texto para que você possa especificar uma classificação quando um novo filme é criado.

<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")
}

Agora você atualizou o código do aplicativo para dar suporte à nova Rating propriedade.

Execute o aplicativo e navegue até a URL / Movies . Ao fazer isso, porém, você verá um dos seguintes erros:

Captura de tela que mostra um erro de exceção não tratado pelo usuário.

O modelo que dá suporte ao contexto 'MovieDBContext' foi alterado desde que o banco de dados foi criado. Considere usar as Migrações do Code First para atualizar o banco de dados (https://go.microsoft.com/fwlink/?LinkId=238269).

Captura de tela que mostra um navegador com a notificação Erro de servidor no aplicativo.

Você está vendo esse erro porque a classe de modelo atualizada Movie no aplicativo agora é diferente do esquema da Movie tabela do banco de dados existente. (Não há nenhuma coluna Rating na tabela de banco de dados.)

Existem algumas abordagens para resolver o erro:

  1. Faça com que o Entity Framework remova automaticamente e recrie o banco de dados com base no novo esquema de classe de modelo. Essa abordagem é muito conveniente no início do ciclo de desenvolvimento, quando você está fazendo o desenvolvimento ativo em um banco de dados de teste; ela permite que você desenvolva rapidamente o modelo e o esquema de banco de dados juntos. A desvantagem, porém, é que você perde os dados existentes no banco de dados — portanto, não deseja usar essa abordagem em um banco de dados de produção! Muitas vezes, o uso de um inicializador para propagar um banco de dados com os dados de teste automaticamente é uma maneira produtiva de desenvolver um aplicativo. Para obter mais informações sobre inicializadores de banco de dados do Entity Framework, consulte ASP.NET tutorial do MVC/Entity Framework.
  2. Modifique explicitamente o esquema do banco de dados existente para que ele corresponda às classes de modelo. A vantagem dessa abordagem é que você mantém os dados. Faça essa alteração manualmente ou criando um script de alteração de banco de dados.
  3. Use as Migrações do Code First para atualizar o esquema de banco de dados.

Para este tutorial, usaremos as Migrações do Code First.

Atualize o método Seed para que ele forneça um valor para a nova coluna. Abra o arquivo Migrations\Configuration.cs e adicione um campo Rating a cada objeto Movie.

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

Compile a solução e, em seguida, abra a janela Console do Gerenciador de Pacotes e insira o seguinte comando:

add-migration Rating

O add-migration comando informa à estrutura de migração para examinar o modelo de filme atual com o esquema de banco de dados de filme atual e criar o código necessário para migrar o banco de dados para o novo modelo. O nome Rating é arbitrário e é usado para nomear o arquivo de migração. É útil usar um nome significativo para a etapa de migração.

Quando esse comando for concluído, o Visual Studio abrirá o arquivo de classe que define a nova DbMigration classe derivada e, no Up método, você poderá ver o código que cria a nova coluna.

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

Compile a solução e insira o update-database comando na janela Console do Gerenciador de Pacotes .

A imagem a seguir mostra a saída na janela Console do Gerenciador de Pacotes (o carimbo de data e hora que precede a Classificação será diferente.)

Captura de tela que mostra a janela do Console do Gerenciador de Pacotes com o comando update database inserido.

Execute novamente o aplicativo e navegue até a URL /Movies. Você pode ver o novo campo Classificação.

Captura de tela que mostra a lista do Índice de Filmes MVC com o campo Classificação adicionado.

Clique no link Criar novo para adicionar um novo filme. Observe que você pode adicionar uma classificação.

7_CreateRioII

Clique em Criar. O novo filme, incluindo a classificação, agora aparece na lista de filmes:

7_ourNewMovie_SM

Agora que o projeto está usando migrações, você não precisará descartar o banco de dados ao adicionar um novo campo ou atualizar o esquema. Na próxima seção, faremos mais alterações de esquema e usaremos migrações para atualizar o banco de dados.

Você também deve adicionar o Rating campo aos modelos de exibição Editar, Detalhes e Excluir.

Você pode inserir o comando "update-database" na janela do Console do Gerenciador de Pacotes novamente e nenhum código de migração será executado, pois o esquema corresponde ao modelo. No entanto, executar "update-database" executará o Seed método novamente e, se você alterou qualquer um dos dados de semente, as alterações serão perdidas porque o Seed método upserta os dados. Você pode ler mais sobre o Seed método no popular tutorial do ASP.NET MVC/Entity Framework de Tom Dykstra.

Nesta seção, você viu como modificar objetos de modelo e manter o banco de dados em sincronia com as alterações. Você também aprendeu uma maneira de preencher um banco de dados recém-criado com dados de exemplo para que possa experimentar cenários. Esta foi apenas uma introdução rápida ao Code First, consulte Criando um modelo de dados do Entity Framework para um aplicativo MVC ASP.NET para obter um tutorial mais completo sobre o assunto. Em seguida, vamos ver como você pode adicionar uma lógica de validação mais avançada às classes de modelo e permitir que algumas regras de negócios sejam impostas.