Neste artigo veremos como realizar uma exibição mestre-detalhe de registros, em Windows Forms com a linguagem C# e o banco SQL Server. Acompanhem:

Introdução Registros Mestre-Detalhe

O objetivo deste artigo é mostrar como exibir facilmente um registro e seus respectivos detalhes, usando assim três tabelas. Poderíamos usar facilmente até mais tabelas, mais nesse exemplo usaremos apenas três. Como este exemplo é feito usando como base uma videoaula do Luiz Maia, seguirei à risca o que é descrito lá.

Dito isto, usaremos o banco de dados de exemplo da Microsoft Northwind. Se você não o tem instalado em seu SQL Server, baixe por aqui. Depois de baixado e instalado, você deve anexar o Northwind à sua instância local do SQL Server. Para isso, abra seu SQL, clique com o botão direito em Databases e clique em Attach...;agora clique em Add e vá na pasta C:\SQL Server 2000 Sample Databases, escolha o arquivo NORTHWND.MDF, clique em OK duas vezes e aguarde. Note que o banco foi criado:

Exibição Mestre-Detalhe de Registros
Banco de dados da Microsoft Northwind.

Aproveite para “fuçar” o banco, visualizando suas Tabelas, Procedures e Views. Esse banco é muito útil, assim como o AdventureWorks, também de exemplo da Microsoft.

Neste tipo de artigo, poderíamos facilmente fazer todo esse processo via Wizard, sem usar uma linha sequer de código, mais como o objetivo neste artigo é o de aprender alguns conceitos de ADO.NET, vamos fazer tudo no braço!

Antes de criar o projeto, devemos criar a conexão entre o Visual Studio e o Northwind. Para quem usa Windows 7 (como é o meu caso) o Visual Studio deve ser executado como administrador. Ainda sem projeto criado, abra a janela Server Explorer, clique com o botão direito em Data Connections e clique em Add Connection. Na nova tela, selecione seu servidor SQL, escolha o database Northwind e clique em OK.

Crie um projeto do tipo Windows Forms, dando a ele o nome de Exibição Mestre-Detalhe. No form que se abrir, adicione alguns controles para que o mesmo fique da seguinte forma:

Exibição Mestre-Detalhe de Registros
Exibição Mestre-Detalhe no Windows Forms.

Veja abaixo a sugestão dos ID’s de cada controle que usarei neste exemplo:

  • GroupBox: gpbCliente, gpbPedidos, gpbDetalhesPedido;
  • Button: btnAvancar, btnRetroceder;
  • ComboBox: cboNome;
  • TextBox: txtContato, txtTelefone;
  • Label: lblNome, lblContato, lblTelefone;
  • DataGridView: dgvPedidos, dgvDetalhesPedido;

A ideia é a seguinte: usaremos três tabelas, como já dito anteriormente: Customers, Orders e OrderDetails, traduzindo serão as tabelas de Clientes, Pedidos e Detalhes do Pedido, respectivamente.

Vá à página de códigos e declare o namespace System.Data.SqlClient, responsável pelas classes do SQL Server:


using System.Data.SqlClient;

Agora faremos a codificação e veremos o resultado final do projeto da exibição mestre-detalhe de registros, em Windows Forms com a linguagem C# e o banco SQL Server.

Voltando de onde paramos, crie o método CarregarDados() e o codifique acompanhando abaixo os comentários com as explicações pertinentes:


public DataViewManager dvManager;
public void CarregarDados()
{
 string strConexao = @ "Data Source=WELLINGTON-PC\SQLEXPRESS;Initial 
 Catalog=Northwind;Integrated Security=True";
 using(SqlConnection objConexao = new SqlConnection(strConexao))
 {
  DataSet ds = new DataSet("CustOrders");
  SqlDataAdapter daCustomers = new SqlDataAdapter("SELECT * 
  FROM CUSTOMERS", objConexao);
  daCustomers.TableMappings.Add("Table", "Customers");
  daCustomers.Fill(ds);
  SqlDataAdapter daOrders = new SqlDataAdapter("SELECT * 
  FROM ORDERS", objConexao);
  daOrders.TableMappings.Add("Table", "Orders");
  daOrders.Fill(ds);
  SqlDataAdapter daOrdersDetails = new SqlDataAdapter("SELECT * 
  FROM [ORDER DETAILS]", objConexao); 
  daOrdersDetails.TableMappings.Add("Table", "OrderDetails");
  daOrdersDetails.Fill(ds);



  DataRelation relCustOrder;
  DataColumn colMaster1;
  DataColumn colDetail1;
  colMaster1 = ds.Tables["Customers"].Columns["CustomerID"];
  colDetail1 = ds.Tables["Orders"].Columns["CustomerID"];
  relCustOrder = new DataRelation("RelCustomerOrder", 
  colMaster1, colDetail1);
  ds.Relations.Add(relCustOrder);



  DataRelation relOrdDetail;
  DataColumn colMaster2;
  DataColumn colDetail2;
  colMaster2 = ds.Tables["Orders"].Columns["OrderID"];
  colDetail2 = ds.Tables["OrderDetails"].Columns["OrderID"];
  relOrdDetail = new DataRelation("RelOrderDetail", 
  colMaster2, colDetail2);
  ds.Relations.Add(relOrdDetail);



  dvManager = ds.DefaultViewManager;



  dgvPedidos.DataSource = dvManager;
  dgvPedidos.DataMember = "Customers.RelCustomerOrder";



  dgvDetalhesPedido.DataSource = dvManager;
  dgvDetalhesPedido.DataMember = "Customers.RelCustomerOrder
  .RelOrderDetail";



  cboNome.DataSource = dvManager;
  cboNome.DisplayMember = "Customers.CompanyName";
  cboNome.ValueMember = "Customers.CustomerID";


  txtContato.DataBindings.Add("Text", dvManager, 
  "Customers.ContactName");
  txtTelefone.DataBindings.Add("Text", dvManager, 
  "Customers.Phone");
 }

}
Nota: Foi criada uma variável pública fora do método, será explicado o porquê disso mais tarde.O
  • Começo atribuindo à minha variável strConexao a string de conexão com o Database Northwind, conexão esta feita no artigo anterior.
  • Abro uma chave using para garantir que a conexão seja fechada automaticamente após eu usá-la, instancio minha conexão SQL, passando a strConexao como parâmetro.
  • Instancio o DataSet, dando a ele o nome CustOrders.
  • Instancio o SqlDataAdapter, que serve para “preencher” de dados meu DataSet. Passo como parâmetro para ele a instrução SELECT, para retornar todos os registros da tabela e passo o objeto de conexão instanciado, também como parâmetro.
  • Por meio do método TableMappings, adiciono um mapeamento da minha tabela, passando o nome Table como parâmetro para o nome, e o nome da tabela.
  • Uso o método Fill, do DataAdapter, para preencher o DataSet.
  • Faço o mesmo para as tabelas Orders e OrderDetails.
  • Por meio de DataRelation, defino os relacionamentos entre as tabelas. Dito isto, instancio um objeto da classe DataRelation, crio dois objetos da classe DataColumn, que serão minhas chaves primária e estrangeira, respectivamente. Esses objetos recebem os respectivos ID’s, adiciono eles ao objeto relCustOrder, definindo assim um relacionamento, e adiciono esse relacionamento ao meu DataSet, já criado anteriormente. Faço o mesmo para a chave da tabela OrderDetails.
  • Crio um objeto da classe DataViewManager, responsável pela criação de definições customizadas de cada DataTable em meu DataSet, assim posso manipulá-los com precisão. Esse objeto recebe a propriedade DefaultViewManager.
  • Finalizando atribuo os DataSources dos controles ao DataViewManager.

{
 InitializeComponent();
 CarregarDados();

}

Lembra que criamos uma variável pública fora do método? A usaremos agora. Pra terminar nosso artigo, dê dois cliques nos botões do form e use os seguintes códigos:


private void btnAvancar_Click(object sender, EventArgs e)

{
    CurrencyManager cm = (CurrencyManager)this.BindingContext[dvManager, "Customers"];
    if (cm.Position < cm.Count - 1)
    {
        cm.Position++;
    }
}

private void btnRetroceder_Click(object sender, EventArgs e)
{
  if (this.BindingContext[dvManager, "Customers"].Position > 0)
    {
        this.BindingContext[dvManager, "Customers"].Position--;
    }
}

Dica: Não irei explicar esta parte, já que o intuito deste artigo é o de aprendizado, e quero que vocês corram atrás e estudem sobre o CurrencyManager e o BindingContext, muito úteis para aplicações deste tipo.

Assim podemos avançar e retroceder em nossos registros. Aperte F5 para compilar e veja o resultado:

Exibição Mestre-Detalhe de Registros
Aperte F5 para compilar e veja o resultado.

Assim temos uma exibição detalhada do registro e suas respectivas ligações, já que, para cada cliente temos um ou mais pedidos e o detalhe dos respectivos pedidos.


Saiu na DevMedia!

  • Guia de UML: Você planeja suas aplicações antes de começar a programar? Ou é daqueles que pensa enquanto escreve? Cuidado, você corre o risco de chegar no meio do projeto sem saber para onde ir. Para evitar isso descubra neste Guia a UML.
  • Curso de HTML5: Formulários são uma parte fundamental da web, pois são a forma mais básica de interação com o usuário. Isso porque permitir o envio de dados para um servidor. Nesse curso criaremos um formulário de cadastro da pizzaria Hello Pizza, permitindo assim aprender sobre os elementos que o compõem e seus sistemas de validação.
  • Curso de C#: Este curso é voltado aos iniciantes na programação, principalmente na linguagem C#. Criaremos uma aplicação voltada a calcular o gasto de tinta necessário para pintar um cômodo utilizando conceitos básicos do C#, a principal linguagem de programação da plataforma .NET.

Saiba mais sobre PHP ;)

  • É tudo ou nada: gravando múltiplos registros de uma vez: Já pensou pagar por 10 itens, mas no final a aplicação só registrar a compra de 5 deles? Tem horas que não dá pra falhar. Fique por dentro dos problemas que podem ocorrer ao gravar múltiplos registros de uma só vez. Assista!
  • Mestre Detalhe em detalhes: Você provavelmente já se deparou com um formulário do tipo mestre detalhe enquanto fazia compras, selecionava suas matérias do semestre, etc. Mas você conhece todas as pequenas armadilhas que a programação dessa rotina esconde? Descubra neste DevCast
  • Construindo uma aplicação mestre detalhe em PHP: Ao longo deste curso veremos como implementar um formulário "mestre detalhe", nos concentrando nos aspectos principais desse relacionamento e como ele é representado no código, na interface do sistema e no banco de dados.