ASP .NET MVC - CRUD Usando o padrão Repository (revisitado)


Este artigo mostrar como usar o padrão Repository em uma aplicação ASP .NET MVC para realizar as operações básicas de manutenção de dados - CRUD : Create, Read, Update, Delete.

Objetivo:

Recursos :

Conceitos

Padrão Repositório

O padrão repositório cria uma camada de abstração entre a camada de acesso a dados e a camada da lógica de negócios de uma aplicação. É um padrão de acesso a dados que pede uma abordagem mais flexível. Para usar o padrão geralmente criamos a lógica de acesso a dados em uma classe separada, ou conjunto de classes, chamado de repositório com a responsabilidade de persistir o modelo de negócios do aplicativo.

Neste artigo, vamos implementar o padrão em uma abordagem bem simples para criar um repositório no qual há uma classe repositório para cada tipo de entidade. Vamos criar para uma entidade Livro uma interface e uma classe concreta de forma que quando instanciarmos o repositório em nosso controlador na aplicação MVC vamos usar a interface para que o controlador aceite uma referência a qualquer objeto que implementa a interface repositório.

No nosso exemplo quando o controlador for executado em um servidor web ele receberá um repositório que trabalha com o Entity Framework.

Os controladores MVC interagem com repositórios para carregar e manter um modelo de negócio da aplicação. Tirando proveito de injeção de dependência (DI), os repositórios podem ser injetados em um construtor de um controlador. O diagrama a seguir mostra a relação entre o repositório e contexto de dados do Entity Framework, no qual os controladores MVC interagem com o repositório ao invés de diretamente com o Entity Framework.

Entity Framework

O ADO.NET Entity Framework(EF) é um mapeador objeto relacional (ORM) incluído na plataforma .NET; ele basicamente gera objetos de negócios e entidades de acordo com as tabelas de banco de dados, fornecendo as operações básicas CRUD, o gerenciamento das relações entre as entidades com a capacidade de ter um relacionamento de herança entre entidades.

Ao utilizar EF, nós interagimos com um modelo e não com o banco de dados relacional. Essa abstração permite que nos concentremos nas regras de negócio e nas relações entre as entidades. Usamos o contexto de dados do Entity Framework para realizar consultas. Quando uma das operações CRUD é invocada, a estrutura de entidades irá gerar o SQL necessário para realizar a operação.

Podemos trabalhar com o Entity Framework usando 3 abordagens:

1- DataBase First - É uma abordagem centrada nos dados baseada em um banco de dados existente. O Entity Framework é capaz de gerar um modelo de negócios com base nas tabelas e colunas de um banco de dados relacional. As informações sobre a estrutura do banco de dados (esquema de armazenamento), o modelo de dados (modelo conceitual), e o mapeamento entre eles são armazenados em arquivos XML com extensão .edmx.
2- Model First - Nesta abordagem, não temos um banco de dados existente e o Entity Framework oferece um designer que pode criar um modelo de dados conceitual. Ele também usa um arquivo .edmx para Armazenar as informações do modelo e do mapeamento. Quando o modelo for criado, o designer pode gerar o esquema da base de dados que pode ser usado para criar o banco.
3- Code First - Quer você já tenha um banco de dados ou não, você pode codificar suas próprias classes e propriedades que correspondam às tabelas e colunas e usá-los com o Entity Framework sem precisar do arquivo .edmx. Nesta abordagem, o Entity Framework não aproveitar qualquer tipo de arquivo de configuração (arquivo .edmx) para armazenar o esquema de banco de dados, porque a API de mapeamento utiliza estas convenções para gerar o esquema de banco de dados dinamicamente em tempo de execução.

Neste artigo, vamos usar a abordagem Code First para desenvolver uma camada de acesso a dados em uma aplicação MVC. A grande vantagem desta abordagem é a capacidade de usar as classes POCO(Plain Old CLR Objects) onde se utiliza um conjunto de convenções para mapear as classes POCO mas que pode ser alterada usando a anotação de dados (data annotations).

Criando a aplicação MVC e usando o padrão repositório

Abra o Visual Studio 2012 Express for Web e clique em New Project selecionando o template Visual C# -> Web e ASP .NET MVC 4 Web Application e informe o nome Crud_Repositorio_Mvc;

Selecione o template Internet Application e o engine Razor e clique em Ok;

Com essas opções estamos criando uma aplicação MVC 4 com o engine Razor de forma que nosso projeto já irá incluir a referência ao Entity Framework.

Criando o Modelo

Vamos criar um modelo para a entidade Livro na pasta Models. O modelo é na verdade uma classe que usa uma entidade e um entity set. Ao criar a classe Livro na pasta Models usando Code First vamos usar o recurso data annotation para definir atributos que auxiliarão a criação da tabela a partir da classe.

Clique com o botão direito do mouse sobre a pasta Models e selecione Add Class;

Selecione o template Class e informe o nome Livro.cs e a seguir defina o código abaixo neste arquivo:

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace Crud_Repositorio_Mvc.Models
{
    public class Livro
    {
        [Key]
        public int Id { get; set; }
        [Required]
        [MaxLength(30)]

        public string Titulo { get; set; }
        public string Autor { get; set; }

        [Column("Ano")]
        [Display(Name = "Ano Publicacao")]

        public string anoPublicacao { get; set; }

        [Column("Preco")]
        [Display(Name = "Preco")]

        public decimal Preco { get; set; }
    }
}

Criando o Data Context.

A abordagem Code First nos obriga a criar um classe de contexto de acesso a dados que herda da classe DbContext. Esta classe deve conter as propriedades de cada uma das entidades no modelo de domínio.

A seguir temos um data context para o nosso exemplo que contém uma entidade, Livro, onde criamos esta classe de contexto (LivroContext), sob a pasta Models.

Abaixo a definição da classe de contexto de dados que tem um construtor para passa uma string de conexão que é definida no arquivo web.config. Por padrão, o nome da string de conexão é o mesmo nome da classe de contexto de dados, mas podemos utilizar um nome diferente de forma que todos os contextos de dados possam usar uma única seqüência de conexão.

Clique com o botão direito do mouse sobre a pasta Models e selecione Add Class;

A seguir informe o nome LivroContext.cs e inclua o código abaixo neste arquivo:

using System.Data.Entity;

namespace Crud_Repositorio_Mvc.Models
{
    public class LivroContext : DbContext
    {
        public LivroContext()
            : base("name=LivrariaConnectionString")
        {          
        }

        public DbSet<Livro> Livros { get; set; }
    }
}

A string de conexão definida no arquivo web.config pode ser vista abaixo:

<connectionStrings>
    <add name="LivrariaConnectionString" connectionString="Data Source=(LocalDb)\v11.0;Initial Catalog=aspnet-Crud_Repositorio_Mvc-20130802105353;
Integrated Security=SSPI;AttachDBFilename=|DataDirectory|\aspnet-Crud_Repositorio_Mvc-20130802105353.mdf" providerName="System.Data.SqlClient" />
  </connectionStrings>

Note que estamos usando a versão LocalDB do SQL Server.

Vamos agora criar a classe para o repositório. Clique com o botão direito sobre a pasta Models e selecione Add New Item;

Selecione a aba Code e a seguir o template Interface e informe o nome ILivroRepositorio.cs incluindo a seguir o código abaixo nesta interface:

using System;
using System.Collections.Generic;

namespace Crud_Repositorio_Mvc.Models
{
    interface ILivroRepositorio : IDisposable
    {
        IEnumerable<Livro> GetLivros();
        Livro GetLivroPorID(int livroId);
        void InserirLivro(Livro livro);
        void DeletarLivro(int bookID);
        void AtualizaLivro(Livro livro);
        void Salvar();
    }
}

Vamos criar a classe LivroRepostiorio que implementa a interface "ILivroRepositorio" sendo que "ILivroRepositorio" herda a interface IDisposable de forma que a interface IDisposable é indiretamente implementada pela classe LivroRespositorio.

O contexto de banco de dados é definido em uma variável de classe (_context) , e o construtor espera o objeto de chamada para passar em uma instância do contexto. Aqui estamos passando a instância LivroContext para o construtor.

using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;

namespace Crud_Repositorio_Mvc.Models
{
    public class LivroRepositorio : ILivroRepositorio
    {
         private LivroContext _context;
         public LivroRepositorio(LivroContext livroContext)
         {
             this._context = livroContext;
         }

        public IEnumerable<Livro> GetLivros()
        {
            return _context.Livros.ToList();
        }

        public Livro GetLivroPorID(int id)
        {
            return _context.Livros.Find(id);
        }

        public void InserirLivro(Livro livro)
        {
           _context.Livros.Add(livro);
        }

        public void DeletarLivro(int livroID)
        {
            Livro livro = _context.Livros.Find(livroID);
            _context.Livros.Remove(livro);
        }

        public void AtualizaLivro(Livro livro)
        {
            _context.Entry(livro).State = EntityState.Modified;
        }

        public void Salvar()
        {
            _context.SaveChanges();
        }

        private bool disposed = false;
        protected virtual void Dispose(bool disposing)
        {
            if (!this.disposed)
            {
                if (disposing)
                {
                    _context.Dispose();
                }
            }
            this.disposed = true;
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
    }
}

O código usa os recursos do Entity Framework para realizar as operações definidas na interface ILivroRepositorio.

Dessa forma concluímos a criação do nosso modelo de dados, nosso repositório e nosso contexto de dados. Nossa próxima tarefa será definir o controlador na pasta Controllers.

Criando o Controlador e as Views

Vamos criar o controlador para que irá realizar as operações CRUD. Para isso temos que

Clique com o botão direito do mouse sobre a pasta Controllers e clique em Add Controller;

Informe o nome LivroController e o template MVC controller with empty read/write actions;

Assim teremos o nosso controlador LivroController criado com actions que poderemos ajustar adequando-as ao nosso projeto.

Vamos começar definindo os namespaces que iremos usar no arquivo LivroController.cs conforme abaixo:

using System.Data;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Crud_Repositorio_Mvc.Models;

Ainda no arquivo LivroController.cs vamos criar uma instância da interface ILivroRepositorio e inicializar o repositório livro usando o construtor do controlador Livro na classe LivroController conforme abaixo:

private ILivroRepositorio _livroRepositorio;

public LivroController()
{
   this._livroRepositorio = new LivroRepositorio(new LivroContext());
}

Agora vamos ajustar a Action Index para retornar uma lista de livros:

 // GET: /Livro/
 public ActionResult Index()
 {
     var livros = from livro in _livroRepositorio.GetLivros()
                      select livro;

          return View(livros);
 }

Para verificarmos o funcionamento temos que criar as Views correspondentes.

Compile o projeto antes de prosseguir e clique com o botão direito do mouse sobre a Action Index e clique em Add View;

Aceite o nome Index e a View Engine Razor;

Marque a caixa Create a strongly-type view e selecione a classe Livro em Model Class;

Em Scalfold template selecione o item List e marque as opções - Reference script libraries e Use a layout or master page;

Clique no botão Add;

Será criada a pasta Livro e o arquivo Index.cshtml representando a view retornada pelo método Action Index do controlador LivroController;

Vamos agora ajustar o método Action Details(int id) do controlador LivroController conforme o código a seguir:

   // GET: /Livro/Details/5
   public ActionResult Details(int id)
   {
        Livro livro = _livroRepositorio.GetLivroPorID(id);
        return View(livro);
  }

A seguir vamos criar a View para este método do controlador.

Compile o projeto antes de prosseguir e clique com o botão direito do mouse sobre a Action Details e clique em Add View;

Aceite o nome Index e a View Engine Razor;

Marque a caixa Create a strongly-type view e selecione a classe Livro em Model Class;

Em Scalfold template selecione o item Details e marque as opções - Reference script libraries e Use a layout or master page;

Será criado o arquivo Details.cshtml na pasta Livro representando a view retornada pelo método Action Details do controlador LivroController;

Agora vamos ajustar as Action Create no controlador LivroController uma para o criar um novo livro (GET) e outra para submeter os detalhes do novo livro criado(POST).

Abaixo temos o código das duas Actions Create ajustados:

        //
        // GET: /Livro/Create
        public ActionResult Create()
        {
            return View(new Livro);
        }

        //
        // POST: /Livro/Create
        [HttpPost]
        public ActionResult Create(Livro livro)
        {
            try
            {

                if (ModelState.IsValid)
                {
                    _livroRepositorio.InserirLivro(livro);
                    _livroRepositorio.Salvar();
                    return RedirectToAction("Index");
                }
            }
            catch (DataException)
            {
                ModelState.AddModelError("", "Não foi possível salvar as mudanças. Tente novamente....");
            }
            return View(livro);
        }

A seguir vamos criar a View para o método Create (GET) do controlador.

Compile o projeto antes de prosseguir e clique com o botão direito do mouse sobre a Action Create e clique em Add View;

Aceite o nome Index e a View Engine Razor;

Marque a caixa Create a strongly-type view e selecione a classe Livro em Model Class;

Em Scalfold template selecione o item Create e marque as opções - Reference script libraries e Use a layout or master page;

Será criado o arquivo Create.cshtml na pasta Livro representando a view retornada pelo método Action Create do controlador LivroController;

Continuando vamos criar duas Actions no controlador, uma para editar um livro existente (GET) e outra para submeter os detalhes do livro atualizado para o repositório (POST)

        // GET: /Livro/Edit/5
        public ActionResult Edit(int id)
        {
            return View();
        }

        //
        // POST: /Livro/Edit/5
        [HttpPost]
        public ActionResult Edit(Livro livro)
        {
            try
            {
                if (ModelState.IsValid)
                {
                    _livroRepositorio.AtualizaLivro(livro);
                    _livroRepositorio.Salvar();
                    return RedirectToAction("Index");
                }
            }
            catch (DataException)
            {
                ModelState.AddModelError("", "Não foi possível salvar as mudanças. Tente novamente.....");
            }
            return View(livro);
        }

Agora vamos criar a View para o método Edit(GET) do controlador.

Compile o projeto antes de prosseguir e clique com o botão direito do mouse sobre a Action Edit e clique em Add View;

Aceite o nome Index e a View Engine Razor;

Marque a caixa Create a strongly-type view e selecione a classe Livro em Model Class;

Em Scalfold template selecione o item Edit e marque as opções - Reference script libraries e Use a layout or master page;

Será criado o arquivo Edit.cshtml na pasta Livro representando a view retornada pelo método Action Edit do controlador LivroController;

Para concluir vamos criar mais duas Actions no controlador LivroController, uma p ara exibir os detalhes do livro após clicar no link para Deletar o livro (GET) e outra para deletar o livro (POST).

Abaixo vemos o código dessas Actions:

       // GET: /Livro/Delete/5
        public ActionResult Delete(int id, bool? saveChangesError)
        {
            if (saveChangesError.GetValueOrDefault())
            {
                ViewBag.ErrorMessage = "Não foi possível salvar as mudanças. Tente novamente......";
            }
            Livro livro = _livroRepositorio.GetLivroPorID(id);
            return View(livro);
        }

        //
        // POST: /Livro/Delete/5
        [HttpPost, ActionName("Delete")]
        public ActionResult Delete(int id)
        {
            try
            {
                Livro livro = _livroRepositorio.GetLivroPorID(id);
                _livroRepositorio.DeletarLivro(id);
                _livroRepositorio.Salvar();
            }
            catch (DataException)
            {
                return RedirectToAction("Delete",
                  new System.Web.Routing.RouteValueDictionary {
               { "id", id },
               { "saveChangesError", true } });
            }
            return RedirectToAction("Index");
        }

Mais uma vez vamos criar a View para o método Edit(GET) do controlador.

Compile o projeto antes de prosseguir e clique com o botão direito do mouse sobre a Action Delete e clique em Add View;

Aceite o nome Index e a View Engine Razor;

Marque a caixa Create a strongly-type view e selecione a classe Livro em Model Class;

Em Scalfold template selecione o item Delete e marque as opções - Reference script libraries e Use a layout or master page;

Ao final deste procedimento teremos os métodos Action definidos no arquivo LivroController na pasta Controllers e as views na pasta /Views/Livro:

para testarmos a nossa aplicação ainda temos que fazermos alguns ajustes nos arquivos que foram gerados no projeto.

...
  <header>
            <div class="content-wrapper">
                <div class="float-left">
                    <p class="site-title">@Html.ActionLink("Macoratti.net", "Index", "Livro")</p>
                </div>
                <div class="float-right">
                    <nav>
                        <ul id="menu">
                            <li>@Html.ActionLink("Livro", "Index", "Livro")</li>
                        </ul>
                    </nav>
                </div>
            </div>
        </header>
...
using System.Web.Mvc;
using System.Web.Routing;

namespace Crud_Repositorio_Mvc
{
    public class RouteConfig
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

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

1,2,3, Testando...

Execute o projeto...

Será apresentada a seguinte página no navegador padrão:

Como não há dados na tabela veremos somente o cabeçalho com o nome dos campos na página.

Abra a janela DataBase Explorer e verifique que o banco de dados e a tabela foram criadas via Code First :

Clicando no link Create New teremos a view Create que permite incluir um livro:

Clicando em Create teremos o livro incluído na tabela do banco de dados e exibido conforme abaixo:

Note que temos os links para Editar, Ver os detalhes e Deletar o livro.

Clicando em Details veremos os detalhes do livro exibido:

Para deletar o livro basta clicar no link Delete e confirmar:

E assim realizamos as operações CRUD na aplicação ASP .NET MVC para manter uma entidade Livro usando o Entity Framework e o padrão Repositório.

Pegue o projeto completo aqui: Crud_Repositorio_Mvc.zip

Veja os Destaques e novidades do SUPER DVD Visual Basic  (sempre atualizado) : clique e confira !

Quer migrar para o VB .NET ?

Veja mais sistemas completos para a plataforma .NET no Super DVD .NET , confira...

Quer aprender C# ??

Chegou o Super DVD C#  com exclusivo material de suporte e vídeo aulas com curso básico sobre C#.

Veja também os Cursos com vídeo aulas e projetos exemplos:

 

             Gostou ?   Compartilhe no Facebook   Compartilhe no Twitter


Referências:


José Carlos Macoratti