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á.
Relacionado: Guia Completa de Mestre Detalhe
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:
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:
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");
}
}
- 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:
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.