Tutorial: Implementar a funcionalidade CRUD com o Entity Framework no ASP.NET MVC

No tutorial anterior, você criou um aplicativo MVC que armazena e exibe dados usando o EF (Entity Framework) 6 e SQL Server LocalDB. Neste tutorial, você examinará e personalizará o código CRUD (criar, ler, atualizar, excluir) que o scaffolding MVC cria automaticamente para você em controladores e exibições.

Observação

É uma prática comum implementar o padrão de repositório para criar uma camada de abstração entre o controlador e a camada de acesso a dados. Para manter esses tutoriais simples e focados em ensinar como usar o próprio EF 6, eles não usam repositórios. Para obter informações sobre como implementar repositórios, consulte o Mapa de Conteúdo de Acesso a Dados do ASP.NET.

Aqui estão exemplos das páginas da Web que você cria:

Uma captura de tela da página de detalhes do aluno.

Uma captura de tela da página de criação do aluno.

Uma captura de tela mostra a página de exclusão do aluno.

Neste tutorial, você:

  • Página Criar detalhes
  • Atualizar a página Criar
  • Atualizar o método Editar HttpPost
  • Atualizar a página Excluir
  • Fechará conexões de banco de dados
  • Lidar com transações

Pré-requisitos

Página Criar detalhes

O código com scaffolded para a página Alunos Index deixou de fora a Enrollments propriedade , pois essa propriedade contém uma coleção. Details Na página, você exibirá o conteúdo da coleção em uma tabela HTML.

Em Controllers\StudentController.cs, o método de ação para a Details exibição usa o método Find para recuperar uma única Student entidade.

public ActionResult Details(int? id)
{
    if (id == null)
    {
        return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
    }
    Student student = db.Students.Find(id);
    if (student == null)
    {
        return HttpNotFound();
    }
    return View(student);
}

O valor da chave é passado para o método como o id parâmetro e vem de dados de rota no hiperlink Detalhes na página Índice.

Dica: rotear dados

Dados de rota são dados que o associador de modelo encontrou em um segmento de URL especificado na tabela de roteamento. Por exemplo, a rota padrão especifica controlleros segmentos , actione id :

routes.MapRoute(
    name: "Default",
    url: "{controller}/{action}/{id}",
    defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);

Na URL a seguir, a rota padrão é mapeada Instructor como , controllerIndex como e action 1 como ; idesses são valores de dados de rota.

http://localhost:1230/Instructor/Index/1?courseID=2021

?courseID=2021 é um valor de cadeia de caracteres de consulta. O associador de modelo também funcionará se você passar o id como um valor de cadeia de caracteres de consulta:

http://localhost:1230/Instructor/Index?id=1&CourseID=2021

As URLs são criadas por ActionLink instruções no modo de exibição Razor. No código a seguir, o id parâmetro corresponde à rota padrão, portanto id , é adicionado aos dados de rota.

@Html.ActionLink("Select", "Index", new { id = item.PersonID  })

No código a seguir, courseID não corresponde a um parâmetro na rota padrão, portanto, ele é adicionado como uma cadeia de caracteres de consulta.

@Html.ActionLink("Select", "Index", new { courseID = item.CourseID })

Para criar a página Detalhes

  1. Abra Views\Student\Details.cshtml.

    Cada campo é exibido usando um DisplayFor auxiliar, conforme mostrado no exemplo a seguir:

    <dt>
        @Html.DisplayNameFor(model => model.LastName)
    </dt>
    <dd>
        @Html.DisplayFor(model => model.LastName)
    </dd>
    
  2. Após o EnrollmentDate campo e imediatamente antes da marca de fechamento </dl> , adicione o código realçado para exibir uma lista de registros, conforme mostrado no exemplo a seguir:

    <dt>
                @Html.DisplayNameFor(model => model.EnrollmentDate)
            </dt>
    
            <dd>
                @Html.DisplayFor(model => model.EnrollmentDate)
            </dd>
            <dt>
                @Html.DisplayNameFor(model => model.Enrollments)
            </dt>
            <dd>
                <table class="table">
                    <tr>
                        <th>Course Title</th>
                        <th>Grade</th>
                    </tr>
                    @foreach (var item in Model.Enrollments)
                    {
                        <tr>
                            <td>
                                @Html.DisplayFor(modelItem => item.Course.Title)
                            </td>
                            <td>
                                @Html.DisplayFor(modelItem => item.Grade)
                            </td>
                        </tr>
                    }
                </table>
            </dd>
        </dl>
    </div>
    <p>
        @Html.ActionLink("Edit", "Edit", new { id = Model.ID }) |
        @Html.ActionLink("Back to List", "Index")
    </p>
    

    Se o recuo de código estiver errado depois de colar o código, pressione Ctrl+K, Ctrl+D para formatá-lo.

    Esse código percorre as entidades na propriedade de navegação Enrollments. Para cada Enrollment entidade na propriedade , ela exibe o título do curso e a nota. O título do curso é recuperado da Course entidade armazenada na Course propriedade de navegação da Enrollments entidade. Todos esses dados são recuperados do banco de dados automaticamente quando necessário. Em outras palavras, você está usando o carregamento lento aqui. Você não especificou o carregamento adiantado para a Courses propriedade de navegação, portanto, as matrículas não foram recuperadas na mesma consulta que obteve os alunos. Em vez disso, na primeira vez que você tentar acessar a Enrollments propriedade de navegação, uma nova consulta será enviada ao banco de dados para recuperar os dados. Você pode ler mais sobre carregamento lento e carregamento adiantado no tutorial Lendo dados relacionados mais adiante nesta série.

  3. Abra a página Detalhes iniciando o programa (Ctrl+F5), selecionando a guia Alunos e clicando no link Detalhes de Alexander Carson. (Se você pressionar Ctrl+F5 enquanto o arquivo Details.cshtml estiver aberto, você receberá um erro HTTP 400. Isso ocorre porque o Visual Studio tenta executar a página Detalhes, mas não foi acessada a partir de um link que especifica o aluno a ser exibido. Se isso acontecer, remova "Aluno/Detalhes" da URL e tente novamente ou feche o navegador, clique com o botão direito do mouse no projeto e clique em Exibir>Exibição no Navegador.)

    Você verá a lista de cursos e notas do aluno selecionado.

  4. Feche o navegador.

Atualizar a página Criar

  1. Em Controllers\StudentController.cs, substitua o método de HttpPostAttributeCreate ação pelo código a seguir. Esse código adiciona um try-catch bloco e remove ID do BindAttribute atributo para o método scaffolded:

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Create([Bind(Include = "LastName, FirstMidName, EnrollmentDate")]Student student)
    {
        try
        {
            if (ModelState.IsValid)
            {
                db.Students.Add(student);
                db.SaveChanges();
                return RedirectToAction("Index");
            }
        }
        catch (DataException /* dex */)
        {
            //Log the error (uncomment dex variable name and add a line here to write a log.
            ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists see your system administrator.");
        }
        return View(student);
    }
    

    Esse código adiciona a Student entidade criada pelo ASP.NET associador de modelo MVC ao Students conjunto de entidades e salva as alterações no banco de dados. O associador de modelo refere-se à funcionalidade ASP.NET MVC que facilita o trabalho com os dados enviados por um formulário; um associador de modelo converte valores de formulário postados em tipos CLR e os passa para o método de ação em parâmetros. Nesse caso, o associador de modelo cria uma instância de uma Student entidade para você usando valores de propriedade da Form coleção.

    Você removeu ID do atributo Bind porque ID é o valor da chave primária que SQL Server definirá automaticamente quando a linha for inserida. A entrada do usuário não define o ID valor.

    Aviso de segurança – o ValidateAntiForgeryToken atributo ajuda a evitar ataques de solicitação intersite forjada . Ele requer uma instrução correspondente Html.AntiForgeryToken() na exibição, que você verá mais tarde.

    O Bind atributo é uma maneira de proteger contra o excesso de postagem em cenários de criação. Por exemplo, suponha que a Student entidade inclua uma Secret propriedade que você não deseja que essa página da Web defina.

    public class Student
    {
        public int ID { get; set; }
        public string LastName { get; set; }
        public string FirstMidName { get; set; }
        public DateTime EnrollmentDate { get; set; }
        public string Secret { get; set; }
    
        public virtual ICollection<Enrollment> Enrollments { get; set; }
    }
    

    Mesmo que você não tenha um Secret campo na página da Web, um hacker pode usar uma ferramenta como fiddler ou escrever algum JavaScript para postar um Secret valor de formulário. Sem o BindAttribute atributo que limita os campos que o associador de modelo usa quando cria uma Student instância, o associador de modelo pegaria esse Secret valor de formulário e o usaria para criar a instância de Student entidade. Em seguida, seja qual for o valor que o invasor especificou para o campo de formulário Secret, ele é atualizado no banco de dados. A imagem a seguir mostra a ferramenta fiddler adicionando o Secret campo (com o valor "OverPost") aos valores de formulário postados.

    Captura de tela que mostra a guia Compositor. No canto superior direito, Executar é circulado em vermelho. No canto inferior direito, Segredo igual a Sobre Post é circulado em vermelho.

    Em seguida, o valor "OverPost" é adicionado com êxito à propriedade Secret da linha inserida, embora você nunca desejou que a página da Web pudesse definir essa propriedade.

    É melhor usar o Include parâmetro com o Bind atributo para listar explicitamente os campos. Também é possível usar o Exclude parâmetro para bloquear campos que você deseja excluir. O motivo Include é mais seguro é que, quando você adiciona uma nova propriedade à entidade, o novo campo não é protegido automaticamente por uma Exclude lista.

    Você pode impedir a sobreposição em cenários de edição é ler a entidade do banco de dados primeiro e, em seguida, chamar TryUpdateModel, passando uma lista de propriedades permitidas explícita. Esse é o método usado nestes tutoriais.

    Uma maneira alternativa de evitar a sobreposição preferida por muitos desenvolvedores é usar modelos de exibição em vez de classes de entidade com model binding. Inclua apenas as propriedades que você deseja atualizar no modelo de exibição. Depois que o associador de modelo MVC for concluído, copie as propriedades do modelo de exibição para a instância de entidade, opcionalmente usando uma ferramenta como AutoMapper. Use o banco de dados. Entrada na instância de entidade para definir seu estado como Inalterado e, em seguida, definir Property("PropertyName"). IsModified como true em cada propriedade de entidade incluída no modelo de exibição. Esse método funciona nos cenários de edição e criação.

    Além do Bind atributo , o try-catch bloco é a única alteração feita no código com scaffolded. Se uma exceção que é derivada de DataException é capturada enquanto as alterações estão sendo salvas, uma mensagem de erro genérica é exibida. Às vezes, as exceções DataException são causadas por algo externo ao aplicativo, em vez de por um erro de programação e, portanto, o usuário é aconselhado a tentar novamente. Embora não implementado nesta amostra, um aplicativo de qualidade de produção registrará a exceção em log. Para obter mais informações, consulte a seção Log para informações em Monitoramento e telemetria (criando aplicativos de nuvem do mundo real com o Azure).

    O código em Views\Student\Create.cshtml é semelhante ao que você viu em Details.cshtml, exceto que EditorFor os auxiliares e ValidationMessageFor são usados para cada campo em vez de DisplayFor. Este é o código relevante:

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

    Create.cshtml também inclui @Html.AntiForgeryToken(), que funciona com o ValidateAntiForgeryToken atributo no controlador para ajudar a evitar ataques de solicitação intersite forjada .

    Nenhuma alteração é necessária em Create.cshtml.

  2. Execute a página iniciando o programa, selecionando a guia Alunos e, em seguida, clicando em Criar Novo.

  3. Insira nomes e uma data inválida e clique em Criar para ver a mensagem de erro.

    Essa é a validação do lado do servidor que você obtém por padrão. Em um tutorial posterior, você verá como adicionar atributos que geram código para validação do lado do cliente. O código realçado a seguir mostra o marcar de validação de modelo no método Create.

    if (ModelState.IsValid)
    {
        db.Students.Add(student);
        db.SaveChanges();
        return RedirectToAction("Index");
    }
    
  4. Altere a data para um valor válido e clique em Criar para ver o novo aluno ser exibido na página Índice.

  5. Feche o navegador.

Atualizar o método Editar HttpPost

  1. Substitua o HttpPostAttributeEdit método de ação pelo seguinte código:

    [HttpPost, ActionName("Edit")]
    [ValidateAntiForgeryToken]
    public ActionResult EditPost(int? id)
    {
        if (id == null)
        {
            return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
        }
        var studentToUpdate = db.Students.Find(id);
        if (TryUpdateModel(studentToUpdate, "",
           new string[] { "LastName", "FirstMidName", "EnrollmentDate" }))
        {
            try
            {
                db.SaveChanges();
    
                return RedirectToAction("Index");
            }
            catch (DataException /* dex */)
            {
                //Log the error (uncomment dex variable name and add a line here to write a log.
                ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists, see your system administrator.");
            }
        }
        return View(studentToUpdate);
    }
    

    Observação

    Em Controllers\StudentController.cs, o HttpGet Edit método (aquele sem o HttpPost atributo) usa o Find método para recuperar a entidade selecionada Student , como você viu no Details método . Não é necessário alterar esse método.

    Essas alterações implementam uma prática recomendada de segurança para evitar a sobrepostagem, a scaffolder gerou um Bind atributo e adicionou a entidade criada pelo associador de modelo ao conjunto de entidades com um sinalizador Modificado. Esse código não é mais recomendado porque o Bind atributo limpa todos os dados pré-existentes em campos não listados no Include parâmetro . No futuro, o scaffolder do controlador MVC será atualizado para que ele não gere Bind atributos para métodos editar.

    O novo código lê a entidade existente e chama TryUpdateModel para atualizar campos da entrada do usuário nos dados de formulário postados. O controle automático de alterações do Entity Framework define o sinalizador EntityState.Modified na entidade. Quando o método SaveChanges é chamado, o Modified sinalizador faz com que o Entity Framework crie instruções SQL para atualizar a linha do banco de dados. Os conflitos de simultaneidade são ignorados e todas as colunas da linha de banco de dados são atualizadas, incluindo aquelas que o usuário não alterou. (Um tutorial posterior mostra como lidar com conflitos de simultaneidade e, se você quiser que apenas campos individuais sejam atualizados no banco de dados, você pode definir a entidade como EntityState.Unchanged e definir campos individuais como EntityState.Modified.)

    Para evitar a sobrepostagem, os campos que você deseja atualizar pela página Editar são listados nos TryUpdateModel parâmetros. Atualmente, não há nenhum campo extra que está sendo protegido, mas listar os campos que você deseja que o associador de modelos associe garante que, se você adicionar campos ao modelo de dados no futuro, eles serão automaticamente protegidos até que você adicione-os aqui de forma explícita.

    Como resultado dessas alterações, a assinatura de método do método HttpPost Edit é igual ao método de edição HttpGet; portanto, você renomeou o método EditPost.

    Dica

    Estados de entidade e os métodos Attach e SaveChanges

    O contexto de banco de dados controla se as entidades em memória estão em sincronia com suas linhas correspondentes no banco de dados, e essas informações determinam o que acontece quando você chama o método SaveChanges. Por exemplo, quando você passa uma nova entidade para o método Add , o estado dessa entidade é definido como Added. Em seguida, quando você chama o método SaveChanges , o contexto do banco de dados emite um comando SQL INSERT .

    Uma entidade pode estar em um dos seguintes estados:

    • Added. A entidade ainda não existe no banco de dados. O SaveChanges método deve emitir uma instrução INSERT .
    • Unchanged. Nada precisa ser feito com essa entidade pelo método SaveChanges. Ao ler uma entidade do banco de dados, a entidade começa com esse status.
    • Modified. Alguns ou todos os valores de propriedade da entidade foram modificados. O SaveChanges método deve emitir uma instrução UPDATE .
    • Deleted. A entidade foi marcada para exclusão. O SaveChanges método deve emitir uma DELETE instrução .
    • Detached. A entidade não está sendo controlada pelo contexto de banco de dados.

    Em um aplicativo da área de trabalho, em geral, as alterações de estado são definidas automaticamente. Em um tipo de aplicativo da área de trabalho, você lê uma entidade e faz alterações em alguns de seus valores de propriedade. Isso faz com que seu estado da entidade seja alterado automaticamente para Modified. Em seguida, quando você chama SaveChanges, o Entity Framework gera uma instrução SQL UPDATE que atualiza apenas as propriedades reais que você alterou.

    A natureza desconectada dos aplicativos Web não permite essa sequência contínua. O DbContext que lê uma entidade é descartado depois que uma página é renderizada. Quando o HttpPostEdit método de ação é chamado, uma nova solicitação é feita e você tem uma nova instância do DbContext, portanto, você precisa definir manualmente o estado da entidade como Modified. Então, quando você chama SaveChanges, o Entity Framework atualiza todas as colunas da linha de banco de dados, pois o contexto não tem como saber quais propriedades você alterou.

    Se você quiser que a instrução SQL Update atualize apenas os campos que o usuário realmente alterou, você poderá salvar os valores originais de alguma forma (como campos ocultos) para que eles fiquem disponíveis quando o HttpPostEdit método for chamado. Em seguida, você pode criar uma Student entidade usando os valores originais, chamar o Attach método com essa versão original da entidade, atualizar os valores da entidade para os novos valores e, em seguida, chamar SaveChanges. Para obter mais informações, consulte Estados de entidade e SaveChanges e Dados Locais.

    O código HTML e Razor em Views\Student\Edit.cshtml é semelhante ao que você viu em Create.cshtml e nenhuma alteração é necessária.

  2. Execute a página iniciando o programa, selecionando a guia Alunos e clicando em um hiperlink Editar .

  3. Altere alguns dos dados e clique em Salvar. Você verá os dados alterados na página Índice.

  4. Feche o navegador.

Atualizar a página Excluir

Em Controllers\StudentController.cs, o código de modelo do HttpGetAttributeDelete método usa o Find método para recuperar a entidade selecionada Student , como você viu nos Details métodos e Edit . No entanto, para implementar uma mensagem de erro personalizada quando a chamada a SaveChanges falhar, você adicionará uma funcionalidade a esse método e à sua exibição correspondente.

Como você viu para operações de atualização e criação, as operações de exclusão exigem dois métodos de ação. O método chamado em resposta a uma solicitação GET exibe uma exibição que dá ao usuário a chance de aprovar ou cancelar a operação de exclusão. Se o usuário aprová-la, uma solicitação POST será criada. Quando isso acontece, o HttpPostDelete método é chamado e, em seguida, esse método realmente executa a operação de exclusão.

Você adicionará um try-catch bloco ao HttpPostAttributeDelete método para lidar com erros que possam ocorrer quando o banco de dados for atualizado. Se ocorrer um erro, o HttpPostAttributeDelete método chamará o método , passando-o HttpGetAttributeDelete um parâmetro que indica que ocorreu um erro. Em HttpGetAttributeDelete seguida, o método reproduz a página de confirmação junto com a mensagem de erro, dando ao usuário a oportunidade de cancelar ou tentar novamente.

  1. Substitua o HttpGetAttributeDelete método de ação pelo código a seguir, que gerencia o relatório de erros:

    public ActionResult Delete(int? id, bool? saveChangesError=false)
    {
        if (id == null)
        {
            return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
        }
        if (saveChangesError.GetValueOrDefault())
        {
            ViewBag.ErrorMessage = "Delete failed. Try again, and if the problem persists see your system administrator.";
        }
        Student student = db.Students.Find(id);
        if (student == null)
        {
            return HttpNotFound();
        }
        return View(student);
    }
    

    Esse código aceita um parâmetro opcional que indica se o método foi chamado após uma falha ao salvar alterações. Esse parâmetro é false quando o HttpGetDelete método é chamado sem uma falha anterior. Quando ele é chamado pelo HttpPostDelete método em resposta a um erro de atualização de banco de dados, o parâmetro é true e uma mensagem de erro é passada para o modo de exibição.

  2. Substitua o HttpPostAttributeDelete método de ação (chamado DeleteConfirmed) pelo código a seguir, que executa a operação de exclusão real e captura todos os erros de atualização de banco de dados.

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Delete(int id)
    {
        try
        {
            Student student = db.Students.Find(id);
            db.Students.Remove(student);
            db.SaveChanges();
        }
        catch (DataException/* dex */)
        {
            //Log the error (uncomment dex variable name and add a line here to write a log.
            return RedirectToAction("Delete", new { id = id, saveChangesError = true });
        }
        return RedirectToAction("Index");
    }
    

    Esse código recupera a entidade selecionada e chama o método Remove para definir o status da entidade como Deleted. Quando SaveChanges é chamado, um comando SQL DELETE é gerado. Você também alterou o nome do método de ação de DeleteConfirmed para Delete. O código scaffolded chamado método HttpPostDeleteDeleteConfirmed para dar ao HttpPost método uma assinatura exclusiva. (O CLR requer métodos sobrecarregados para ter parâmetros de método diferentes.) Agora que as assinaturas são exclusivas, você pode manter a convenção MVC e usar o mesmo nome para os HttpPost métodos e HttpGet excluir.

    Se melhorar o desempenho em um aplicativo de alto volume for uma prioridade, você poderá evitar uma consulta SQL desnecessária para recuperar a linha substituindo as linhas de código que chamam os Find métodos e Remove pelo seguinte código:

    Student studentToDelete = new Student() { ID = id };
    db.Entry(studentToDelete).State = EntityState.Deleted;
    

    Esse código cria uma instância de uma Student entidade usando apenas o valor da chave primária e, em seguida, define o estado da entidade como Deleted. Isso é tudo o que o Entity Framework precisa para excluir a entidade.

    Conforme observado, o HttpGetDelete método não exclui os dados. Executar uma operação de exclusão em resposta a uma solicitação GET (ou, nesse caso, executar qualquer operação de edição, criar operação ou qualquer outra operação que altere dados) cria um risco de segurança. Para obter mais informações, consulte ASP.NET Dica de MVC nº 46 — Não use Excluir Links porque eles criam falhas de segurança no blog de Stephen Walther.

  3. Em Views\Student\Delete.cshtml, adicione uma mensagem de erro entre o h2 título e o h3 título, conforme mostrado no exemplo a seguir:

    <h2>Delete</h2>
    <p class="error">@ViewBag.ErrorMessage</p>
    <h3>Are you sure you want to delete this?</h3>
    
  4. Execute a página iniciando o programa, selecionando a guia Alunos e clicando em um hiperlink Excluir .

  5. Escolha Excluir na página que diz Tem certeza de que deseja excluir isso?.

    A página Índice é exibida sem o aluno excluído. (Você verá um exemplo do código de tratamento de erros em ação no tutorial de simultaneidade.)

Fechará conexões de banco de dados

Para fechar conexões de banco de dados e liberar os recursos que eles mantêm o mais rápido possível, descarte a instância de contexto quando terminar de usá-la. É por isso que o código scaffolded fornece um método Dispose no final da StudentController classe em StudentController.cs, conforme mostrado no exemplo a seguir:

protected override void Dispose(bool disposing)
{
    if (disposing)
    {
        db.Dispose();
    }
    base.Dispose(disposing);
}

A classe base Controller já implementa a IDisposable interface, portanto, esse código simplesmente adiciona uma substituição ao Dispose(bool) método para descartar explicitamente a instância de contexto.

Lidar com transações

Por padrão, o Entity Framework implementa transações de forma implícita. Em cenários em que você faz alterações em várias linhas ou tabelas e, em seguida, chama SaveChanges, o Entity Framework garante automaticamente que todas as suas alterações tenham êxito ou todas falhem. Se algumas alterações forem feitas pela primeira vez e, em seguida, ocorrer um erro, essas alterações serão revertidas automaticamente. Para cenários em que você precisa de mais controle, por exemplo, se quiser incluir operações feitas fora do Entity Framework em uma transação, consulte Trabalhando com transações.

Obter o código

Baixar Projeto Concluído

Recursos adicionais

Agora você tem um conjunto completo de páginas que executam operações CRUD simples para Student entidades. Você usou auxiliares do MVC para gerar elementos de interface do usuário para campos de dados. Para obter mais informações sobre auxiliares do MVC, consulte Renderizando um formulário usando auxiliares HTML (o artigo é para MVC 3, mas ainda é relevante para MVC 5).

Links para outros recursos do EF 6 podem ser encontrados em ASP.NET Acesso a Dados – Recursos Recomendados.

Próximas etapas

Neste tutorial, você:

  • Criou uma página Detalhes
  • Atualizou a página Criar
  • Atualizado o método HttpPost Edit
  • Atualizou a página Excluir
  • Fechou conexões de banco de dados
  • Transações tratadas

Avance para o próximo artigo para saber como adicionar classificação, filtragem e paginação ao projeto.