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.
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.
Na janela Console do Gerenciador de Pacotes , no prompt, PM>
digite
Enable-Migrations -ContextTypeName MvcMovie.Models.MovieDBContext
O comando Enable-Migrations (mostrado acima) cria um arquivo Configuration.cs em uma nova pasta Migrations .
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;
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.
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.
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.
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:
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).
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:
- 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.
- 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.
- 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.)
Execute novamente o aplicativo e navegue até a URL /Movies. Você pode ver o novo campo Classificação.
Clique no link Criar novo para adicionar um novo filme. Observe que você pode adicionar uma classificação.
Clique em Criar. O novo filme, incluindo a classificação, agora aparece na lista de filmes:
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.