ASP .NET- Uma simples aplicação em 3 camadas


O objetivo deste artigo é mostrar como usar alguns recursos da ASP .NET em uma aplicação simples que persiste dados em um banco de dados SQL Server e utiliza Stored Procedures.

Então neste artigo você vai aprender ou rever os seguintes tópicos:

Apesar de tudo isso que veremos este artigo é um artigo para iniciantes.

A primeira coisa a fazer é 'ver' as principais telas da aplicação em execução:

Apresentando a aplicação ASP .NET

1- A tela de apresentação da aplicação - Default.aspx - que usa a Master Page Site.Master e permite incluir registros e ir para a página de exibição dos registros:

2- A página - ListarRegistros.aspx - exibe os registros no controle GridView e permite a edição e exclusão de registros;

3 - A edição de registros utiliza o recurso dos templateFields permitindo alterar um registro existente;

4- O link Deletar exibe uma caixa de mensagem solicitando a confirmação do usuário antes de realizar a exclusão:

E é isso ai tudo que a aplicação faz. Parece pouco mas envolve um monte de conceitos básicos.

Definindo o banco de dados, tabela e stored procedures

A definição do banco de dados, da tabela e das stored procedures pode ser feita no SQL Server Management Studio Express que é uma ferramenta gratuita da Microsoft.

A seguir vemos o banco de dados Escola e a tabela Contatos e sua estrutura:

A tabela contato possui a seguinte estrutura:
  • codigo
  • nome
  • email
  • idade

Onde codigo é uma chave primária do tipo identity
significando que é um campo com numeração automática
controle pelo SGBD SQL Server.

Agora temos que criar as nossas stored procedures ou procedimentos armazenados no banco de dados Escola.mdf.

Abra o DataBase Explorer e após expandir os objetos do banco de dados Contatos.mdf clique com o botão direito do mouse sobre o objeto Stored Procedures e selecione a opção Add New Stored Procedure;

No editor do SQL Server 2005/2008 vamos criar a stored procedure exibeContatos que irá retornar todos os contatos cadastrados na tabela Contatos

Digite o comando conforme ao lado e clique no botão Save para salvar a
stored procedure no banco de dados;

stored procedure : CarregarDados

A instrução SQL usada é: SELECT * from Contatos

CREATE PROCEDURE dbo.CarregarDados
AS
      SELECT * from contatos
RETURN

A seguir repita o procedimento para as demais stored procedures:

stored procedure : AtualizarDados    
CREATE PROCEDURE dbo.AtualizarDados
(
	@codigo int,
	@nome nvarchar(50),
	@email nvarchar(100),
	@idade int
)
AS
    Update Contatos set nome=@nome, email=@email, idade=@idade where codigo=@codigo
	RETURN
stored procedure : InserirDados
CREATE PROCEDURE dbo.InserirDados
(
	@nome nvarchar(50),
	@email nvarchar(100),
	@idade int
)
AS
    Insert into Contatos(nome,email,idade) values (@nome,@email,@idade)
RETURN
stored procedure : DeletarDados
CREATE PROCEDURE dbo.DeletarDados
(
	@codigo int
)
AS
    DELETE
    FROM dbo.Contatos
    WHERE  
    codigo = @codigo
	RETURN

Ao final poderemos ver as stored procedures criadas na janela DataBase Explorer:

Ao lado vemos as stored Procedures criadas e os parâmetros usados
pelas mesmas

Somente a stored procedure CarregarDados não usa parâmetros.

Definindo as referências nos projetos

Vamos definir as referências usadas pelos projetos da solução da seguinte forma:

Clique com o botão direito do mouse sobre o projeto TresCamadadasAdoNet e no menu suspenso selecione Add Reference;

A seguir selecione a aba Projects e selecione o projeto BAL e clique em OK;

Clique com o botão direito do mouse sobre o projeto BAL e no menu suspenso selecione Add Reference;

A seguir selecione a aba Projects e selecione o projeto DAL e clique em OK;

Criando a aplicação ASP .NET

Abra o Visual Web Developer 2010 Express Edition e no menu File -> New Project e selecione o template ASP .NET Web Application informando o nome TresCamadasAdoNet e clicando em OK;

Isso criará uma solução Web contendo uma estrutura com uma master page a página Default.aspx a página Home e a página About. Vamos excluir a página Home.aspx e a pasta Account e o arquivo Global.asax;

Vamos aproveitar e já incluir um novo Web Form no menu Project -> Add New Item selecionando o template Web Form e informando o nome ListarRegistros.aspx;

Agora vamos incluir um novo projeto no menu File -> Add -> New Project e selecione o template Class Library informando o nome DAL e clicando em OK;

Aproveite e já altere o nome do arquivo Class1.cs para DAL.cs;

O projeto DAL conterá as nossas classes de acesso a dados.

Repita o procedimento anterior e adicione também um novo projeto do tipo Class Library com o nome BAL; Em seguida altere o nome do arquivos Class1.cs para BAL.cs; Este projeto conterá as nossas regras de negócio.

Ao final desta etapa a janela Solution Explorer deverá exibir uma solução com 3 projeto conforme a figura abaixo:

Estrutura da solução TresCamadasAdoNet:
  • projeto Class Library - BAL - Camada de negócios
  • projteo Class Library - DAL - Camada de Acesso a dados
  • projeto ASP .NET - TresCamadasAdoNet - Interface

Definindo a camada de acesso a dados no projeto : DAL

Agora vamos incluir o código abaixo no arquivo DAL.cs do projeto DAL que atuará como a nossa camada de acesso a dados:

using System.Data.SqlClient;
using System.Data;
using System.Configuration;

namespace DAL
{
    public class AcessoDados
    {

        /// <summary>
        /// inserir registros no banco de dados
        /// </summary>
        /// <param name="nome"></param>
        /// <param name="email"></param>
        /// <param name="idade"></param>
        /// <returns></returns>
        /// 
        string connStr = ConfigurationManager.ConnectionStrings["EscolaSqlServer"].ConnectionString;

        public int Insert(string nome, string email, int idade)
        {
            SqlConnection conn = new SqlConnection(connStr);
            conn.Open();
            SqlCommand dCmd = new SqlCommand("InserirDados", conn);
            dCmd.CommandType = CommandType.StoredProcedure;
            try
            {
                dCmd.Parameters.AddWithValue("@nome", nome);
                dCmd.Parameters.AddWithValue("@email", email);
                dCmd.Parameters.AddWithValue("@idade", idade);
                return dCmd.ExecuteNonQuery();
            }
            catch
            {
                throw;
            }
            finally
            {
                dCmd.Dispose();
                conn.Close();
                conn.Dispose();
            }
        }


        /// <summary>
        /// atualiza registro do banco de dados
        /// </summary>
        /// <param name="codigo"></param>
        /// <param name="nome"></param>
        /// <param name="email"></param>
        /// <param name="idade"></param>
        /// <returns></returns>
        public int Update(int codigo, string nome, string email, int idade)
        {
            SqlConnection conn = new SqlConnection(connStr);
            conn.Open();
            SqlCommand dCmd = new SqlCommand("AtualizarDados", conn);
            dCmd.CommandType = CommandType.StoredProcedure;
            try
            {
                dCmd.Parameters.AddWithValue("@nome", nome);
                dCmd.Parameters.AddWithValue("@email", email);
                dCmd.Parameters.AddWithValue("@idade", idade);
                dCmd.Parameters.AddWithValue("@codigo", codigo);
                return dCmd.ExecuteNonQuery();
            }
            catch
            {
                throw;
            }
            finally
            {
                dCmd.Dispose();
                conn.Close();
                conn.Dispose();
            }
        }

        /// <summary>
        /// carrega todos os registros do banco de dados
        /// </summary>
        /// <returns></returns>
        public DataTable Load()
        {
            SqlConnection conn = new SqlConnection(connStr);
            SqlDataAdapter dAd = new SqlDataAdapter("CarregarDados", conn);
            dAd.SelectCommand.CommandType = CommandType.StoredProcedure;
            DataSet dSet = new DataSet();
            try
            {
                dAd.Fill(dSet, "Contatos");
                return dSet.Tables["Contatos"];
            }
            catch
            {
                throw;
            }
            finally
            {
                dSet.Dispose();
                dAd.Dispose();
                conn.Close();
                conn.Dispose();
            }
        }

        /// <summary>
        /// Exclui o registro do banco de dados
        /// </summary>
        /// <param name="codigo"></param>
        /// <returns></returns>
        public int Delete(int codigo)
        {
            SqlConnection conn = new SqlConnection(connStr);
            conn.Open();
            SqlCommand dCmd = new SqlCommand("DeletarDados", conn);
            dCmd.CommandType = CommandType.StoredProcedure;
            try
            {
                dCmd.Parameters.AddWithValue("@codigo", codigo);
                return dCmd.ExecuteNonQuery();
            }
            catch
            {
                throw;
            }
            finally
            {
                dCmd.Dispose();
                conn.Close();
                conn.Dispose();
            }
        }
    }
}

A classe AcessoDados define os métodos que atuam na tabela Contatos :

Estes métodos utilizam instruções SQL e as stored procedures criadas para realizar as operações CRUD na tabela.

Nesta classe temos também a utilização dos namespaces:

using System.Data.SqlClient;
using System.Data;
using System.Configuration;

Onde os dois primeiros são usados para o acesso a dados no SQL Server e o System.Configuration para acessar o arquivo web.config e obter a string de conexão com o banco de dados:

string connStr = ConfigurationManager.ConnectionStrings["EscolaSqlServer"].ConnectionString;

Neste projeto deveremos copiar o arquivo Web.Config que tem o código exibido a seguir referente a seção <connectionStrings>:

<configuration>
<connectionStrings>
<add name="EscolaSqlServer"
        connectionString="Data Source=.\SQLEXPRESS;database=Escola;Integrated Security=True;"
        providerName="System.Data.SqlClient"/>
</connectionStrings>

Definindo a camada de negócios do projeto : BAL

A classe Negocios representa a nossa camada de negócios que neste exemplo apenas instancia e acessa a camada de acesso a dados para realizar as operações CRUD;

Temos definidos nesta classe os seguintes métodos:

using System.Data;
using DAL;

namespace BAL
{
    public class Negocios
    {

        /// <summary>
        /// inserir registro no banco de dados
        /// </summary>
        /// <param name="nome"></param>
        /// <param name="email"></param>
        /// <param name="idade"></param>
        /// <returns></returns>
        public int Insert(string nome, string email, int idade)
        {
            AcessoDados pDAL = new AcessoDados();
            try
            {
                return pDAL.Insert(nome, email, idade);
            }
            catch
            {
                throw;
            }
            finally
            {
                pDAL = null;
            }
        }

        /// <summary>
        /// atualizar registro do banco de dados
        /// </summary>
        /// <param name="codigo"></param>
        /// <param name="nome"></param>
        /// <param name="email"></param>
        /// <param name="idade"></param>
        /// <returns></returns>
        public int Update(int codigo, string nome, string email, int idade)
        {
            AcessoDados pDAL = new AcessoDados();
            try
            {
                return pDAL.Update(codigo, nome, email, idade);
            }
            catch
            {
                throw;
            }
            finally
            {
                pDAL = null;
            }
        }

        /// <summary>
        /// carregar todos os registros
        /// </summary>
        /// <returns></returns>
        public DataTable Load()
        {
            AcessoDados pDAL = new AcessoDados();
            try
            {
                return pDAL.Load();
            }
            catch
            {
                throw;
            }
            finally
            {
                pDAL = null;
            }
        }

        /// <summary>
        /// Deletar registro do banco de dados
        /// </summary>
        /// <param name="codigo"></param>
        /// <returns></returns>
        public int Delete(int codigo)
        {
            AcessoDados pDAL = new AcessoDados();
            try
            {
                return pDAL.Delete(codigo);
            }
            catch
            {
                throw;
            }
            finally
            {
                pDAL = null;
            }
        }
    }
}

Esta classe não deveria ter uma referência ao namespace System.Data pois ela não deve saber nada sobre acesso a dados pois isso deveria ser uma responsabilidade da camada de acesso a dados. O método Load retorna um DataTable mas deveria estar retornando objetos do domínio.

Definindo a camada de Interface : TresCamadasAdoNet

Nesta camada vamos fazer alguns ajustes no arquivo Site.Master que é uma master page e que será usada pelo arquivo Default.aspx.

O arquivo Default.aspx possui o seguinte leiaute:

O código fonte do arquivo é visto a seguir:

<%@ Page Title="Home Page" Language="C#" MasterPageFile="~/Site.master" AutoEventWireup="true"
    CodeBehind="Default.aspx.cs" Inherits="TresCamadasAdoNet._Default" %>

<asp:Content ID="HeaderContent" runat="server" ContentPlaceHolderID="HeadContent">
</asp:Content>
<asp:Content ID="BodyContent" runat="server" ContentPlaceHolderID="MainContent">
    <h2>
       Exemplo de aplicação em 3 Camadas 
    </h2>
    <p>
        <asp:HyperLink ID="hplkListarRegistros" runat="server" 
            NavigateUrl="~/ListarRegistros.aspx">Listar Registros</asp:HyperLink>
    </p>
    <asp:Label ID="lblMessage" runat="Server" ForeColor="red" EnableViewState="False"></asp:Label>
        <table style="border:2px solid #cccccc;">
            <tr style="background-color:#507CD1;color:White;">
                <th colspan="3">Incluir Registros</th>
            </tr>
            <tr>
                <td>
                    Nome:
                </td>
                <td>
                    <asp:TextBox ID="txtNome" runat="Server" Width="227px"></asp:TextBox>
                </td>
                <td>
                    <asp:RequiredFieldValidator ID="req1" runat="Server" Text="*" ControlToValidate="txtNome" 
                         Display="dynamic"></asp:RequiredFieldValidator>
                </td>
            </tr>
            <tr>
                <td>
                    Email:
                </td>
                <td>
                    <asp:TextBox ID="txtEmail" runat="Server" Width="223px"></asp:TextBox>
                </td>
                <td>
                    <asp:RequiredFieldValidator ID="req2" runat="Server" Text="*" ControlToValidate="txtEmail" 
                      Display="dynamic"></asp:RequiredFieldValidator>
                </td>
            </tr>
            <tr>
                <td>
                    Idade:
                </td>
                <td>
                    <asp:TextBox ID="txtIdade" runat="Server" Columns="4" Width="42px"></asp:TextBox>
                </td>
                <td>
                    <asp:RequiredFieldValidator ID="req3" runat="Server" Text="*" ControlToValidate="txtIdade" 
                        Display="dynamic"></asp:RequiredFieldValidator>
                    <asp:CompareValidator ID="Comp1" runat="Server" Text="Somente Inteiros" ControlToValidate="txtIdade" 
                       Operator="DataTypeCheck" Type="Integer"></asp:CompareValidator>
                </td>
            </tr>
            <tr>
                <td>&nbsp;</td>
                <td>
                    <asp:Button ID="btnSubmit" runat="server" Text="Submeter" OnClick="IncluirRegistros" 
                        Width="80px" />
                </td>
            </tr>
        </table>
</asp:Content>

Vemos uma tabela contendo os controles TextBox e Label para entrada de dados bem como os controles de validação ASP .NET : RequiredFieldValidator e CompareValidator que faz a validação da entrada do usuário.

Vemos também um controle Hyperlink que acessa a página ListarRegistros.aspx e um Button - Submeter - que define no evento OnClick a rotina IncluirRegistros;

O código da rotina IncluiRegistros contido no arquivo code-behind Default.aspx.cs é dado abaixo:

using System;
using System.Web.UI;
using BAL;

namespace TresCamadasAdoNet
{
    public partial class _Default : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
        }

        protected void IncluirRegistros(object sender, EventArgs e)
        {
            //valida pagina
            if (!Page.IsValid)
                return;

            int intResult = 0;
            // Para pagina valida continua a inserir
            // instancia um objeto BAL
            Negocios pBAL = new Negocios();
            // define os valores que serão incluídos
            string nome = txtNome.Text;
            string email = txtEmail.Text;
            int idade = Int32.Parse(txtIdade.Text);

            try
            {
                intResult = pBAL.Insert(nome, email, idade);
                if (intResult > 0)
                    lblMessage.Text = "Novo registro incluído com sucesso.";
                else
                    lblMessage.Text = "Nome [<b>" + txtNome.Text + "</b>] já existe, tente outro nome";

            }
            catch (Exception ee)
            {
                lblMessage.Text = ee.Message.ToString();
            }
            finally
            {
                pBAL = null;
            }
        }
    }
}

Este código recebe a entrada do usuário e chama o método Insert da camada de negócios BAL: intResult = pBAL.Insert(nome, email, idade);

A página IncluirRegistros.aspx possui o seguinte leiaute:

Ela contém um controle GridView através do qual realizamos a exclusão e edição de registros, um controle Hyperlink que permite retornar à página Default.aspx e um Label o- lblMensagem - que exibe as mensagens ao usuário.

O código fonte desta página é mostrado a seguir:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="ListarRegistros.aspx.cs" Inherits="TresCamadasAdoNet.ListarRegistros" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>Exibir Registros</title>
</head>
<body>
    <form id="form1" runat="server">
    <p>
        <asp:HyperLink ID="HyperLink1" runat="server" NavigateUrl="~/Default.aspx" 
            style="font-family: Calibri">Incluir Registros</asp:HyperLink>
    </p>
    <div>
    <asp:GridView ID="GridView1" runat="server" CellPadding="4" ForeColor="#333333" GridLines="None"
         DataKeyNames="codigo" AutoGenerateEditButton="True" AutoGenerateColumns="False"
          OnRowEditing="EditRecord" OnRowUpdating="UpdateRecord" OnRowCancelingEdit="CancelRecord"
           OnRowDeleting="DeleteRecord" PageSize="5" Font-Names="Trebuchet MS" 
            Height="233px" Width="523px" >
            <FooterStyle BackColor="#507CD1" Font-Bold="True" ForeColor="White" />
            <RowStyle BackColor="#EFF3FB" />
            <EditRowStyle BackColor="#2ff1BF" />
            <SelectedRowStyle BackColor="#D1DDF1" Font-Bold="True" ForeColor="#333333" />
            <PagerStyle BackColor="#2461BF" ForeColor="White" HorizontalAlign="Center" />
            <HeaderStyle BackColor="#507CD1" Font-Bold="True" ForeColor="White" />
            <AlternatingRowStyle BackColor="White" />
            <Columns>
                <asp:BoundField DataField="codigo" HeaderText="Codigo" ReadOnly="True"  SortExpression="codigo" />
                <asp:TemplateField HeaderText="Nome" SortExpression="nome">
                    <ItemTemplate>
                        <%# Eval("nome") %>
                    </ItemTemplate>
                    <EditItemTemplate>
                        <asp:TextBox ID="txtNome" runat="Server" Text='<%# Eval("nome") %>' 
                            Height="22px"  Width="202px"></asp:TextBox>
                    </EditItemTemplate>
                </asp:TemplateField>
                <asp:TemplateField HeaderText="Email" SortExpression="email">
                    <ItemTemplate>
                        <%# Eval("email") %>
                    </ItemTemplate>
                    <EditItemTemplate>
                        <asp:TextBox ID="txtEmail" runat="Server" Text='<%# Eval("email") %>' 
                            Height="24px" Width="203px"></asp:TextBox>
                    </EditItemTemplate>
                </asp:TemplateField>
                <asp:TemplateField HeaderText="Idade" SortExpression="idade">
                    <ItemTemplate>
                        <%# Eval("idade") %>
                    </ItemTemplate>
                    <EditItemTemplate>
                        <asp:TextBox ID="txtIdade" runat="Server" Text='<%# Eval("idade") %>' 
                            Height="19px" Width="56px"></asp:TextBox>
                    </EditItemTemplate>
                </asp:TemplateField>
                <asp:TemplateField HeaderText="Deletar?">
                    <ItemTemplate>
                        <span onclick="return confirm('Deseja realmente Excluir este item ?')">
                            <asp:LinkButton ID="lnBD" runat="server" Text="Deletar" CommandName="Delete"></asp:LinkButton>
                        </span>
                    </ItemTemplate>
                </asp:TemplateField>
            </Columns>
        </asp:GridView>
        <br />
        <asp:Label ID="lblMensagem" runat="server" Font-Bold="True" ForeColor="#CC0000" 
            style="font-family: Aharoni"></asp:Label>
    </div>
    </form>
</body>
</html>

Neste código temos a definição das rotinas que serão executadas nos eventos: OnRowEditing, OnRowUpdating e OnRowCancelingEdit:

OnRowEditing="EditRecord" OnRowUpdating="UpdateRecord" OnRowCancelingEdit="CancelRecord"

Temos tambéma definição da propriedade DataKeyNames="codigo".

A propriedade DataKeyNames obtém ou define uma matriz que contém os nomes dos campos da chave primária para os itens exibidos em um controle GridView.

Quando definimos a propriedade DataKeyNames o controle GridView preenche de forma automática a coleção DataKeys com os valores a partir do campo ou campos especificados, e dessa forma, temos uma maneira conveniente de acessar as chaves primárias de cada linha.

Você pode definir um ou mais campos separados por vírgula na propriedade DataKeyNames.

Vemos também as definições dos TemplateFields para cada campo e para o linkButton Deletar onde definimos que ao clicar (onclick) no link uma mensagem de confirmação será exibida ao usuário:

<asp:TemplateField HeaderText="Deletar?">
<ItemTemplate>
<span onclick="return confirm('Deseja realmente Excluir este item ?')">
<asp:LinkButton ID="lnBD" runat="server" Text="Deletar" CommandName="Delete"></asp:LinkButton>

</span>
</ItemTemplate>
</asp:TemplateField>

No arquivo code-behind ListarRegistros.aspx.cs temos o código definido para os eventos do controle GridView conforme abaixo:

using System;
using System.Web.UI.WebControls;
using BAL;
using System.Data;

namespace TresCamadasAdoNet
{
    public partial class ListarRegistros : System.Web.UI.Page
    {
        DataTable tabela = null;

        protected void Page_Load(object sender, EventArgs e)
        {
            if (!IsPostBack)
                BindGrid();
        }
        /// <summary>
        /// Disparado quando o botão Cancel for clicado
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void CancelRecord(object sender, GridViewCancelEditEventArgs e)
        {
            GridView1.EditIndex = -1;
            BindGrid();
        }
        /// <summary>
        /// Disparado quando o botão Edit for clicado
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void EditRecord(object sender, GridViewEditEventArgs e)
        {
            GridView1.EditIndex = e.NewEditIndex;
            BindGrid();
        }

        private DataTable BindGrid()
        {
            Negocios p = new Negocios();

            try
            {
                tabela = p.Load();
                GridView1.DataSource = tabela;
                GridView1.DataBind();
            }
            catch (Exception ee)
            {
                lblMensagem.Text = ee.Message.ToString();
            }
            finally
            {
                p = null;
            }
            return tabela;
        }

        protected void DeleteRecord(object sender, GridViewDeleteEventArgs e)
        {
            int personID = Int32.Parse(GridView1.DataKeys[e.RowIndex].Value.ToString());

            // instancia uma BAL
            Negocios pBAL = new Negocios();
            try
            {
                pBAL.Delete(personID);

                lblMensagem.Text = "Registro deletado com sucesso.";
            }
            catch (Exception ee)
            {
                lblMensagem.Text = ee.Message.ToString();
            }
            finally
            {
                pBAL = null;
            }

            GridView1.EditIndex = -1;
            // atualiza a lista
            BindGrid();
        }

        protected void UpdateRecord(object sender, GridViewUpdateEventArgs e)
        {
            int codigo = Int32.Parse(GridView1.DataKeys[e.RowIndex].Value.ToString());
            int resultado = 0;
            GridViewRow row = GridView1.Rows[e.RowIndex];

            TextBox tNome = (TextBox)row.FindControl("txtNome");
            TextBox tEmail = (TextBox)row.FindControl("txtEmail");
            TextBox tIdade = (TextBox)row.FindControl("txtIdade");

            // instancia uma BAL
            Negocios pBAL = new Negocios();

            try
            {
                resultado = pBAL.Update(codigo, tNome.Text, tEmail.Text, int.Parse(tIdade.Text));
                if (resultado > 0)
                    lblMensagem.Text = "Registro atualizado com sucesso.";
                else
                    lblMensagem.Text = "Registro não pode ser atualizado.";
            }
            catch (Exception ee)
            {
                lblMensagem.Text = ee.Message.ToString();
            }
            finally
            {
                pBAL = null;
            }

            GridView1.EditIndex = -1;
            // atualiza a lista
            BindGrid();
        }

        /// <summary>
        /// Disparado quando um link for clicado
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void ChangePage(object sender, GridViewPageEventArgs e)
        {
            GridView1.PageIndex = e.NewPageIndex;
            // atualiza a lista
            BindGrid();
        }

        /// <summary>
        /// Pega o GridView DataSource
        /// </summary>
        private DataTable GridDataSource()
        {
            Negocios p = new Negocios();
            DataTable tabela = new DataTable();
            try
            {
                tabela = p.Load();
            }
            catch (Exception ee)
            {
                lblMensagem.Text = ee.Message.ToString();
            }
            finally
            {
                p = null;
            }

            return tabela;
        }
    }
}

Neste código vemos que o código usa a camada de negócios BAL para acessar a camada de acesso a dados obtendo e persistindo informações no banco de dados.

O código não deveria ter uma referência ao namespace System.Data pois a camada de interface não deve saber nada sobre acesso a dados pois isso deveria ser uma responsabilidade da camada de acesso a dados. O método GridDataSource retorna um DataTable mas deveria estar retornando objetos do domínio.

Apesar dessas considerações o projeto é funcional e pode até mesmo ser usado em pequenas projetos ou protótipos.

Pegue o projeto completo aqui: TresCamadasAdoNet.zip

"Se alguém me serve, siga-me, e, onde eu estiver, ali estará também o meu servo. E, se alguém me servir, meu Pai o honrará." João 12:26

Referências:


José Carlos Macoratti