ASP .NET MVC - Fazendo o CRUD com LINQ to SQL usando um Repositório (C#) - I

 Hoje vamos rever os conceitos relacionados ao LINQ to SQL em  uma aplicação ASP  .NET MVC 4 realizando um CRUD básico usando a linguagem C#.

O que LINQ To SQL ?

LINQ to SQL é uma implementação específica do LINQ para o SQL Server que converte consultas escritas em C# ou Visual Basic em SQL dinâmico , provendo uma interface que permite mapear os objetos do banco de dados gerando as classes para realizar as operações usando a sintaxe LINQ; também permite realizar alterações nos objetos e atualizar o banco de dados.

Você deve estar pensando : "Mais uma linguagem que eu tenho que aprender, por que não continuar usando SQL , por que uma nova forma de acesso a dados ????"

A primeira vista você pode estar cercado de razões mas se olharmos o cenário atual mais de perto iremos ver que o LINQ To SQL tem um forte motivo para existir.

Quando pensamos em acesso a dados na plataforma .NET pensamos em ADO .NET , certo ?

Pois bem, como fazemos atualmente para acessar os dados em um banco relacional com ADO .NET ?

Geralmente efetuamos a representação das tabelas do banco de dados em classes de forma a criar uma interface para persistência das informações.

Isso é feito hoje basicamente de duas formas:

  1. Fazer o mapeamento objeto relacional usando DataSets e o acesso a dados através de DataAdapters ou TableAdapters com ajuda dos Assistentes de configuração;
  2. Fazer o mapeamento objeto relacional através da criação das classes de negócio via código e acessando os dados usando DataReader;

O LINQ To SQL têm o objetivo de reunir o melhor das duas opções de forma que você possa fazer o mapeamento objeto relacional criando classes que representam as tabelas do banco de dados (inclusive mapeando stored procedures como métodos) e com isso possibilitando a criação de consultas e alterações no banco de dados usando a sintaxe LINQ. (Na verdade as consultas criadas na 'linguagem' LINQ são convertidas em código T-SQL sendo retornado uma coleção de objetos.)

Embora você tenha à sua disposição o Entity Framework e o NHibernate, apenas para citar os mais conhecidos, o LINQ to SQL ainda é uma alternativa existente na plataforma .NET e hoje vamos recordar como usar os seus recursos.

Recursos usados :

Criando a aplicação ASP .NET MVC

Abra o  Visual Studio 2012 Express for web e clique em New Project;

 

A seguir selecione o template Visual C# -> Web -> ASP .NET Web application e informe o nome Mvc_Crud_Linq e clique no botão OK;

 

 

A  seguir selecione o template Internet Application e o View Engine Razor clique no botão OK;

 

Ao final teremos a solução ASP .NET MVC criada com toda a estrutura e referências prontas para ser utilizada, podendo inclusive já executar o projeto.

Como vamos usar o LINQ to SQL vamos definir o banco de dados e a tabela que iremos usar para realizar o CRUD. Você pode usar qualquer tabela do seu banco de dados SQL Server.

Definindo o Banco de dados e a Tabela para realizar o CRUD

Abra a janela Database Explorer e clique com o botão direito sobre Data Connections;

Clique em Add Connection e informe o nome do seu servidor SQL Server em Server name;

Selecione o banco de dados que deseja usar. Eu vou usar o banco de dados Cadastro.mdf

A seguir vemos a tabela Clientes que iremos usar no exemplo e os seus campos definidos : Id . nome, endereco, telefone, email  e observacao

Agora clique no menu PROJECT -> Add New Item e selecione o template Data -> LINQ to SQL Classes informando o nome Clientes.dbml (ou outro nome de sua preferência);

Será aberta a janela do Object Relational Designer, selecione a tabela Clientes, e , arraste-a e solte-a na janela do Designer para mapear a tabela Clientes para a classe Cliente expressa no arquivo Clientes.dbml:

Definindo o Model

Vamos agora definir o nosso modelo na pasta Models da aplicação MVC na janela Solution Explorer.

Clique com o botão direito do mouse sobre a pasta Models e clique a seguir em Add -> Class;

Informe o nome ClienteModel e clique no botão Add;

A seguir defina a classe com o código a seguir. Note que definimos 6 propriedades relacionadas com os campos da tabela Clientes do banco de dados Cadastro.mdf:

namespace Mvc_Crud_LinqToSql.Models
{
    public class ClienteModel
    {
        public int ID { get; set; }
        public string Nome { get; set; }
        public string Endereco { get; set; }
        public string Telefone { get; set; }
        public string Email { get; set; }
        public string Observacao { get; set; }
    }
}

Criando o Repositório

Nesse projeto iremos realizar as operações CRUD usando o padrão Repository e criar um repositório genérico onde iremos definir os métodos de acesso aos dados.

O que é o padrão Repository ?

Um repositório é essencialmente uma coleção de objetos de domínio em memória, e, com base nisso o padrão Repository permite realizar o isolamento entre a camada de acesso a dados (DAL) de sua aplicação e sua camada de apresentação (UI) e camada de negócios (BLL).

Ao utilizar o padrão Repository você pode realizar a persistência e a separação de interesses em seu código de acesso a dados visto que ele encapsula a lógica necessária para persistir os objetos do seu domínio na sua fonte de armazenamento de dados.

Em suma, você pode usar o padrão Repository para desacoplar o modelo de domínio do código de acesso a dados.

Martin Fowler afirma: "O padrão  Repository faz a mediação entre o domínio e as camadas de mapeamento de dados, agindo como uma coleção de objetos de domínio em memória.....Conceitualmente, um repositório encapsula o conjunto de objetos persistidos em um armazenamento de dados e as operações realizadas sobre eles, fornecendo uma visão mais orientada a objetos da camada de persistência.....e também da suporte ao objetivo de alcançar uma separação limpa e uma forma de dependência entre o domínio e as camadas de mapeamento de dados." (http://martinfowler.com/eaaCatalog/repository.html)

Em uma das implementações do padrão repositório podemos começar definindo uma interface que atuará como a nossa fachada de acesso aos dados. Vamos criar então uma interface chamada IClientesRepositorio.

Clique com o botão direito do mouse sobre a pasta Models e a seguir em Add -> New Item;

A seguir selecione o template Code -> Interface e informe o nome IClientesRepositorio e clique no botão Add;

 

A seguir digite o código abaixo na interface onde estamos definindo 5 métodos que deverão ser definido por quem implementar essa interface

using System.Collections.Generic;
namespace Mvc_Crud_LinqToSql.Models
{
    public interface IClientesRepositorio
    {
        IEnumerable<ClienteModel> GetCliente();
        ClienteModel GetClientePorID(int clienteID);
        void InserirCliente(ClienteModel clienteModel);
        void DeletarCliente(int clienteID);
        void AtualizarCliente(ClienteModel clienteModel);
    }
}

Agora vamos criar a classe concreta ClienteRepositorio que irá implementar essa interface.

Clique com o botão direito do mouse sobre a pasta Models e clique a seguir em Add -> Class;

Informe o nome ClienteRepositorio e clique no botão Add;

A seguir digite o código abaixo nesta classe:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace Mvc_Crud_LinqToSql.Models
{
    public class ClienteRepositorio : IClientesRepositorio
    {
        private ClientesDataContext cliente_DataContext;
        public ClienteRepositorio()
        {
            cliente_DataContext = new ClientesDataContext();
        }
        public IEnumerable<ClienteModel> GetCliente()
        {
            IList<ClienteModel> clienteLista = new List<ClienteModel>();
            var consulta = from q in cliente_DataContext.Clientes
                                 select q;
            try
            {
                var cliente = consulta.ToList();
                foreach (var clienteDados in cliente)
                {
                    clienteLista.Add(new ClienteModel()
                    {
                        ID = clienteDados.Id,
                        Nome = clienteDados.nome,
                        Endereco = clienteDados.endereco,
                        Telefone = clienteDados.telefone,
                        Email = clienteDados.email,
                        Observacao = clienteDados.observacao
                    });
                }
                return clienteLista;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        public ClienteModel GetClientePorID(int clienteID)
        {
            var query = from cli in cliente_DataContext.Clientes
                             where cli.Id == clienteID
                            select cli;
            try
            {
                var clienteDados = query.FirstOrDefault();
                var model = new ClienteModel()
                {
                    ID = clienteDados.Id,
                    Nome = clienteDados.nome,
                    Endereco = clienteDados.endereco,
                    Telefone = clienteDados.telefone,
                    Email = clienteDados.email,
                    Observacao = clienteDados.observacao
                };
                return model;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        public void InserirCliente(ClienteModel clienteModel)
        {
            try
            {
                var clienteDados = new Cliente()
                {
                    Id = clienteModel.ID,
                    nome = clienteModel.Nome,
                    endereco = clienteModel.Endereco,
                    telefone = clienteModel.Telefone,
                    email = clienteModel.Email,
                    observacao = clienteModel.Observacao
                };
                cliente_DataContext.Clientes.InsertOnSubmit(clienteDados);
                cliente_DataContext.SubmitChanges();
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        public void DeletarCliente(int clienteID)
        {
            try
            {
                Cliente cliente = cliente_DataContext.Clientes.Where(cli => cli.Id == clienteID).SingleOrDefault();
                cliente_DataContext.Clientes.DeleteOnSubmit(cliente);
                cliente_DataContext.SubmitChanges();
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        public void AtualizarCliente(ClienteModel clienteModel)
        {
            try
            {
                Cliente clienteDados = cliente_DataContext.Clientes.Where(cli => cli.Id == clienteModel.ID).SingleOrDefault();
                clienteDados.nome = clienteModel.Nome;
                clienteDados.endereco = clienteModel.Endereco;
                clienteDados.telefone = clienteModel.Telefone;
                clienteDados.email = clienteModel.Email;
                clienteDados.observacao = clienteModel.Observacao;
                cliente_DataContext.SubmitChanges();
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
    }
}

No código acima iniciamos com a declaração do contexto onde o banco de dados é mapeado em um DataContext permitindo acesso a tabelas de forma transparente sem nos preocuparmos com conexão. O DataContext utiliza a interface IDbConnection do ADO.NET para acessar o armazenamento e pode ser inicializado tanto com um objeto de conexão ADO.NET estabelecido ou com uma string de conexão que possa ser utilizada para criar a conexão.

O DataContext é o mecanismo usado para que seja feita a seleção no banco de dados ficando responsável por traduzir as seleções e alterações executando-as no banco de dados e transformando o resultado em objetos.

Assim podemos escrever consultas como abaixo:

Método Consulta LINQ
GetCliente()  var consulta = from q in cliente_DataContext.Clientes
                     select q;

 

GetClientePorID

 

var consulta = from cli in cliente_DataContext.Clientes
                    where cli.Id == clienteID
                    select cli;

 

A consulta LINQ To SQL inicia com a cláusula From e em seguida o operador de condição Where  e no final usa o operador de seleção Select.

Um dos motivos desta inversão de ordens é  o uso recurso IntelliSense, pois quando você indica primeiro a origem dos dados ele pode mostrar as listas de membros de tipos nos objetos em sua coleção. Outro motivo , segundo Anders Hejlsberg , seria que esta ordem esta mais próxima da nossa lógica de pensamento. Quando você digita uma instrução SQL iniciando com Select na verdade você já esta pensando na origem dos dados , condições , agrupamentos. etc.

A cláusula From é a mais importante do LINQ To SQL pois é usada em todas as consultas. Uma consulta deve sempre começar com From. (O Select pode estar implícito o From não.)

A persistência dos dados é feita pelo método SubmitChanges  do Contexto:

 cliente_DataContext.SubmitChanges();

Definindo o Controller

Vamos agora definir o controlador na pasta Controllers do projeto MVC .

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

Informe o nome ClienteController e clique no botão Add;

A seguir define o código abaixo neste controlador:

using System.Web.Mvc;
using Mvc_Crud_LinqToSql.Models;
using System.Data;
namespace Mvc_Crud_LinqToSql.Controllers
{
    public class ClienteController : Controller
    {
        private IClientesRepositorio _repositorio;
        public ClienteController()
            : this(new ClienteRepositorio())
        { 
        }
        public ClienteController(IClientesRepositorio repositorio)
        {
            _repositorio = repositorio;
        }

        public ActionResult Index()
        {
            var cliente = _repositorio.GetCliente();
            return View(cliente);
        }

        public ActionResult Details(int id)
        {
            ClienteModel model = _repositorio.GetClientePorID(id);
            return View(model);
        } 
        public ActionResult Create()
        {
            return View(new ClienteModel());
        } 
        [HttpPost]
        public ActionResult Create(ClienteModel cliente)
        {
            try
            {
                if (ModelState.IsValid)
                {
                    _repositorio.InserirCliente(cliente);
                    return RedirectToAction("Index");
                }
            }
            catch (DataException)
            {
                ModelState.AddModelError("", "Problemas ao salvar os dados...");
            }
            return View(cliente);
        } 
        public ActionResult Edit(int id)
        {
            ClienteModel model = _repositorio.GetClientePorID(id);
            return View(model);
        } 
        [HttpPost]
        public ActionResult Edit(ClienteModel cliente)
        {
            try
            {
                if (ModelState.IsValid)
                {
                    _repositorio.AtualizarCliente(cliente);
                    return RedirectToAction("Index");
                }
            }  
            catch (DataException)
            {
                ModelState.AddModelError("", "Problemas ao salvar os dados...");
            }
            return View(cliente);
        }
        public ActionResult Delete(int id, bool? saveChangesError)
        {
            if (saveChangesError.GetValueOrDefault())
            {
                ViewBag.ErrorMessage = "Problema ao deletar dados";
            }
            ClienteModel cliente = _repositorio.GetClientePorID(id);
            return View(cliente);
        } 
        [HttpPost, ActionName("Delete")]
        public ActionResult DeleteConfirmed(int id)
        {
            try
            {
                //ClienteModel cliente = _repositorio.GetClientePorID(id);
                _repositorio.DeletarCliente(id);
            }
            catch (DataException)
            {
                return RedirectToAction("Delete",new System.Web.Routing.RouteValueDictionary {{ "id", id },{ "saveChangesError", true } });
            }
            return RedirectToAction("Index");
        }
    }
}

No código do controlador estamos usando os métodos do repositório para interagir com o Model e gerar a apresentação para as Views.

Na continuação deste artigo iremos crias as views da camada de apresentação.

Mat 7:15 Guardai-vos dos falsos profetas, que vêm a vós disfarçados em ovelhas, mas interiormente são lobos devoradores.

Mat 7:16 Pelos seus frutos os conhecereis. Colhem-se, porventura, uvas dos espinheiros, ou figos dos abrolhos?

Mat 7:17 Assim, toda árvore boa produz bons frutos; porém a árvore má produz frutos maus.

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

Quer migrar para o VB .NET ?

Quer aprender C# ??

Quer aprender os conceitos da Programação Orientada a objetos ?

Quer aprender o gerar relatórios com o ReportViewer no VS 2013 ?

 

             Gostou ?   Compartilhe no Facebook   Compartilhe no Twitter
 

Referências:


José Carlos Macoratti