.NET - Passando dados entre camadas : Usando uma coleção/lista Genérica (List(Of T)/Collection(Of T)


Você já deve saber que usar uma arquitetura em camadas é uma boa prática que deve ser seguida.

Quando você divide sua aplicação em camadas esta separando as responsabilidades de forma que a camada de apresentação(UI) seja responsável apenas pela interação com o usuário, a camada de negócios(BLL) pelas regras de negócios e a camada de acesso a dados(DAL) apenas pelo acesso e persistência dos dados.

Nota:
  • Camada de Apresentação - UI - Presentantion Layer
  • Camda de Negócios - BLL - Business Logic Layer
  • Camada de Acesso aos Dados - DAL - Data Access Layer
  • Fonte de dados - Data Source

Então o fluxo da informação nesta abordagem pode ser visto na figura abaixo:

Agora vamos pensar em termos práticos. Se você precisa exibir em um formulário as informações do cliente tem que chamar a camada de negócios (BLL) que por sua vez chama a camada de acesso a dados (DAL).

Se você procurar na internet verá muitos exemplos onde a camada de acesso a dados retorna um objeto DataTable ou DataReader que será usado na camada de apresentação. Mas essa prática não é recomendada. É melhor usar uma coleção genérica do tipo Collection(Of T)/Collection<T>.

Então a extração dos dados é feita na camada de acesso a dados e depois é feita a conversão do DataTable/DataReader obtido para uma coleção genérica. Essa conversão pode ser feita ou na camada de negócios ou na camada de acesso a dados.

A prática mais indicada é definir uma entidade que representa os dados que serão retornados definido em uma camada de transferência que seja referenciada por todas as demais camadas. Essa camada pode ter muitos nomes mas o mais conhecido é DTO ou Data Transfer Object.

Com a definição das entidades podemos realizar o acesso aos dados e converter o resultado de DataTable/DataReader para uma Collection(Of T)/Collection<T> onde T é um tipo da nossa entidade.

Nota: Em muitos exemplos vemos a utilização de List(Of T)/List<T> mas nesse link vemos uma recomendação de não usá-las.

List<T> não é projetado para ser estendido. ou seja, você não pode substituir todos os membros. 
Isso significa que um objeto ao retornar List<T> de uma propriedade não será capaz de ser notificado quando a coleção for modificada. 
Já Collection<T> permite substituir o membro protegido SetItem de forma  a ser  "notificado" quando um novo item for adicionado ou um item existente for alterado.

List<T> tem muitos membros que não são relevantes em muitos cenários. Dizemos que List<T> é muito "ocupado" para modelos de objetos públicos. 

Visual Studio 2012 Express for desktop - Exemplo Prático

Vou dar um exemplo prático procurando ser bem objetivo.

Objetivo: Exibir as informações dos clientes existente em uma tabela Clientes de um banco de dados SQL Server chamado Cadastro.mdf em um controle DataGridView de um formulário Windows Forms.

A estrutura da tabela Clientes e seus dados são vistos abaixo:

Neste exemplo eu vou criar as camadas bem enxutas; nelas eu só vou definir as funcionalidades que precisaremos para ilustrar o exemplo.

Então nosso projeto terá as seguintes camadas :

  1. Camada de apresentação(UI) - Onde irei exibir os dados dos clientes em um controle DataGridView;
  2. Camada de Negócios (BLL) - Onde irei chamar o método da camada de acesso a dados;
  3. Camada de acesso a dados(DAL) onde faremos a conversão de DataTable e DataReader para Collection(Of T)/Collection<T>;
  4. Camada de Transferência (DTO) - Onde irei definir a classe Cliente que representa uma entidade cliente do nosso domínio;

Teremos assim uma solução com 4 projetos.

Criando a solução e os projetos

Abra o Visual Studio 2012 Express for desktop e clique em New Project e selecione Visual Studio Solutions ->Blank Solution informando o nome PassandoDadosEntreCamadas e clique em OK;

Isso irá criar uma solução vazia , sem projetos. Vamos agora criar os projetos.

1- Criando a camada de apresentação - O projeto Windows Forms

No menu FILE clique em Add -> New Project;

Selecione o template Visual Basic -> Windows Forms e informe o nome CamadaApresentacao.

No formulário form1.vb inclua um controle DataGridView (name=dgvClientes) e 3 Buttons conforme a leiaute da figura abaixo:

Definindo as referências da camada

Clique com o botão direito do mouse sobre o projeto CamadaApresentação e clique em Add Reference;

Na janela Add Reference clique em Projects e marque as referências a CamadaDeNegocios e CamadaDeTransferencia conforme figura abaixo:

2- Criando a camada de transferência - A classe Cliente

No menu FILE clique em Add -> New Project;

Selecione o template Visual Basic ->Class Library e informe o nome Cliente.vb.

A seguir inclua o código abaixo na classe Cliente:

Public Class Cliente

    Public Property Id As Integer
    Public Property Nome As String
    Public Property Endereco As String
    Public Property Telefone As String
    Public Property Email As String

End Class
public class Cliente
{
    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; }
}

Se você observar a estrutura da tabela Clientes verá que existe uma correspondência entre as propriedades da classe Cliente e os campos da tabela.

Definindo as referências da camada

Esta camada não possui referência a nenhuma camada mas é referenciada por todas.

3- Criando a camada de Acesso aos Dados- A classe ClienteDAL

No menu FILE clique em Add -> New Project;

Selecione o template Visual Basic ->Class Library e informe o nome ClienteDAL.vb.

A seguir vamos definir os dois métodos que acessam a tabela Clientes e retornam uma lista de objetos Cliente.

Os métodos são :

  1. CarregaDadosDataReader - Retorna uma lista (List<Of T) de clientes;
  2. CarregaDadosDataTable - Retorna uma coleção (Collection(Of T) de clientes;

Eu optei por criar um método retornando um List(Of T) mesmo não sendo recomendado para efeito de comparação com Collection(Of T). Como vocês poderão notar quase não há diferenças. A principal diferença é que para usar a classe Collection(Of T) temos que declarar o namespace Imports System.Collections.ObjectModel.

Abaixo vemos o código da classe ClienteDAL:

Imports System.Data
Imports System.Data.SqlClient
Imports System.Collections.ObjectModel
Imports CamadaDeTransferencia

Public Class ClienteDAL

    Private connStr As String = Nothing

    Sub New()
        connStr = "Data Source=.\sqlexpress;Initial Catalog=Cadastro;Integrated Security=True"
    End Sub

    Public Function CarregaDadosDataReader() As List(Of Cliente)

        Dim lista = New List(Of Cliente)()
        Using conn As New SqlConnection(connStr)
            Using cmd As New SqlCommand("Select * from Clientes", conn)
                cmd.CommandType = CommandType.Text
                conn.Open()
                Using reader As SqlDataReader = cmd.ExecuteReader()
                    While reader.Read()
                        Dim p As New Cliente() With { _
                             .Id = reader.GetInt32(reader.GetOrdinal("id")), _
                             .Nome = reader.GetString(reader.GetOrdinal("nome")), _
                             .Endereco = reader.GetString(reader.GetOrdinal("endereco")), _
                             .Telefone = reader.GetString(reader.GetOrdinal("telefone")), _
                             .Email = reader.GetString(reader.GetOrdinal("email")) _
                        }
                        lista.Add(p)
                    End While
                End Using
                conn.Close()
            End Using
            Return lista
        End Using
    End Function

    Public Function CarregaDadosDataTable() As Collection(Of Cliente)
        Dim colecao = New Collection(Of Cliente)()
        Using conn As New SqlConnection(connStr)
            Using cmd As New SqlCommand("Select * from Clientes", conn)
                cmd.CommandType = CommandType.Text
                Using ad As New SqlDataAdapter(cmd)
                    Dim table As New DataTable()
                    'abre a conexao
                    conn.Open()
                    ad.Fill(table)
                    conn.Close()
                    ' percorre todas as linhas
                    For Each row As DataRow In table.Rows
                        Dim p As New Cliente() With { _
                             .Id = Integer.Parse(row("id").ToString()), _
                             .Nome = row("nome").ToString(), _
                             .Endereco = row("endereco").ToString(), _
                             .Telefone = row("telefone").ToString(), _
                             .Email = row("email").ToString() _
                        }
                        colecao.Add(p)
                    Next
                End Using
            End Using
            Return colecao
        End Using
    End Function
End Class
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Collections.ObjectModel;
using CamadaTransferencia;

public class ClienteDAL
{

    private string connStr = null;
    public ClienteDAL()
    {
        connStr = "Data Source=.\\sqlexpress;Initial Catalog=Cadastro;Integrated Security=True";
    }

    public List<Cliente> CarregaDadosDataReader()
    {
        var lista = new List<Cliente>();
        using (SqlConnection conn = new SqlConnection(connStr))
        {
            using (SqlCommand cmd = new SqlCommand("Select * from Clientes", conn))
            {
                cmd.CommandType = CommandType.Text;
                conn.Open();
                using (SqlDataReader reader = cmd.ExecuteReader())
                {
                    while (reader.Read())
                    {
                        Cliente p = new Cliente
                        {
                            Id = reader.GetInt32(reader.GetOrdinal("id")),
                            Nome = reader.GetString(reader.GetOrdinal("nome")),
                            Endereco = reader.GetString(reader.GetOrdinal("endereco")),
                            Telefone = reader.GetString(reader.GetOrdinal("telefone")),
                            Email = reader.GetString(reader.GetOrdinal("email"))
                        };
                        lista.Add(p);
                    }
                }
                conn.Close();
            }
            return lista;
        }
    }

    public Collection<Cliente> CarregaDadosDataTable()
    {
        var colecao = new Collection<Cliente>();
        using (SqlConnection conn = new SqlConnection(connStr))
        {
            using (SqlCommand cmd = new SqlCommand("Select * from Clientes", conn))
            {
                cmd.CommandType = CommandType.Text;
                using (SqlDataAdapter ad = new SqlDataAdapter(cmd))
                {
                    DataTable table = new DataTable();
                    //abre a conexao
                    conn.Open();
                    ad.Fill(table);
                 //fecha a conexão
                    conn.Close();
                    // percorre todas as linhas
                    foreach (DataRow row in table.Rows)
                    {
                        Cliente p = new Cliente
                        {
                            Id = int.Parse(row["id"].ToString()),
                            Nome = row["nome"].ToString(),
                            Endereco = row["endereco"].ToString(),
                            Telefone = row["telefone"].ToString(),
                            Email = row["email"].ToString()
                        };
                        colecao.Add(p);
                    }
                }
            }
            return colecao;
        }
    }
}
VB .NET C#

Definindo as referências da camada

Clique com o botão direito do mouse sobre o projeto CamadaAcessoDados e clique em Add Reference;

Na janela Add Reference clique em Projects e marque a referência a CamadaDeTransferencia conforme figura abaixo:

4 - Criando a camada de Negócios- A classe ClienteBLL

No menu FILE clique em Add -> New Project;

Selecione o template Visual Basic ->Class Library e informe o nome ClienteBLL.vb.

A classe ClienteBLL é responsável pela lógica de negócio e validações. No nosso exemplo criaremos dois métodos que acesso os métodos definidos na camada de acesso a dados:

  1. CarregaDadosdoDataReader - retorna um List(Of Cliente)
  2. CarregaDadosdoDataTable - retorna um Collection(Of Cliente)

A seguir temos o código da classe ClienteBLL:

Imports CamadaAcessoDados
Imports CamadaDeTransferencia
Imports System.Collections.ObjectModel

Public Class ClienteBLL

    Public Function CarregaDadosdoDataReader() As List(Of Cliente)
        Return New ClienteDAL().CarregaDadosDataReader()
    End Function

    Public Function CarregaDadosdoDataTable() As Collection(Of Cliente)
        Return New ClienteDAL().CarregaDadosDataTable()
    End Function

End Class
using System.Collections.Generic;
using System.Collections.ObjectModel;
using CamadaTransferencia;

namespace CamadaDeNegocios
{
    public class ClienteBLL
    {
        public List<Cliente> CarregaDadosdoDataReader()
        {
            return new ClienteDAL().CarregaDadosDataReader();
        }

        public Collection<Cliente> CarregaDadosdoDataTable()
        {
            return new ClienteDAL().CarregaDadosDataTable();
        }
    }
}

Definindo as referências da camada

Clique com o botão direito do mouse sobre o projeto CamadaDeNegocios e clique em Add Reference;

Na janela Add Reference clique em Projects e marque as referências a CamadaAcessoDados e CamadaDeTransferencia conforme figura abaixo:

Observe em cada classe de cada camada estamos declarando os namespaces com referências a outras camadas. Para que isso funcione temos que definir as referências entre os projetos.

Você pode visualizar as referências para cada projeto clicando com o botão direito do mouse sobre a solução e clicar a seguir em Properties;

Na janela a seguir clique em Project Dependencies e selecione o projeto na guia Projects para visualizar a respectiva referência:

Definindo o código da Camada de Apresentação

Na camada de apresentação vamos definir o código no evento Click de cada botão de comando conforme mostrado a seguir:

Imports CamadaDeNegocios
Imports CamadaDeTransferencia

Public Class Form1

    Private Sub btnSair_Click(sender As Object, e As EventArgs) Handles btnSair.Click
        Me.Close()
    End Sub

    Private Sub btnCarregaDadosDataReader_Click(sender As Object, e As EventArgs) Handles btnCarregaDadosDataReader.Click
        dgvClientes.DataSource = New ClienteBLL().CarregaDadosdoDataReader
    End Sub

    Private Sub btnCarregaDadosDataTable_Click(sender As Object, e As EventArgs) Handles btnCarregaDadosDataTable.Click
        dgvClientes.DataSource = New ClienteBLL().CarregaDadosdoDataTable
    End Sub
End Class
using System;
using System.Windows.Forms;
using CamadaDeNegocios;


namespace CamadaApresentacao
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void btnDataReader_Click(object sender, EventArgs e)
        {
            dgvClientes.DataSource =  new ClienteBLL().CarregaDadosdoDataReader();
        }

        private void btnDataTable_Click(object sender, EventArgs e)
        {
            dgvClientes.DataSource = new ClienteBLL().CarregaDadosdoDataTable();
        }
    }
}

Em cada botão estamos criando uma instância da classe ClienteBLL e chamando o respectivo método que retornará a lista/coleção de objetos Cliente que serão exibidos no controle DataGridView dgvClientes através da propriedade DataSource.

O Resultado da execução do projeto é visto a abaixo:

Pegue o projeto completo aqui: PassandoDadosEntreCamadasVBNET.zip (VS 2012) e PassandoDadosEntreCamadasCSharp.zip (VB 2010)

João 8:34 Replicou-lhes Jesus: Em verdade, em verdade vos digo que todo aquele que comete pecado é escravo do pecado.

João 8:35 Ora, o escravo não fica para sempre na casa; o filho fica para sempre.

João 8:36 Se, pois, o Filho vos libertar, verdadeiramente sereis livres.

 

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