Uma coisa essencial que um desenvolvedor precisa saber para criar uma aplicação comercial é o CRUD (Create, Read, Update e Delete) que é composto pelas operações básicas de banco de dados. E como uma aplicação comercial é baseada em cadastros sua função é muito importante nesse tipo de aplicação.
Nesse artigo será apresentado um CRUD utilizando parâmetros, mas antes é preciso conhecer o CRUD sem a utilização de parâmetros para entender por que é melhor a utilização deles.
Normalmente em uma tela de cadastro de uma aplicação são utilizadas os seguintes comandos SQL:
- INSERT - para inserir dados.
- SELECT - para selecionar e consultar dados.
- UPDATE - para atualizar os dados de um cadastros.
- DELETE - para excluir dados.
A Listagem 1 contém o código que executará um INSERT no banco de dados com os dados de um formulário sem a utilização de parâmetros, não se preocupe com o formulário agora, o importante e entender como está sendo feito a execução do INSERT.
private void btnSalvar_Click(object sender, EventArgs e)
{
string sql = "INSERT INTO CLIENTE (NOME,ENDERECO,CEP,BAIRRO,CIDADE,
UF,TELEFONE) "
+ "VALUES ('" + txtNome.Text + "', '" + txtEndereco.Text + "', '"
+ mskCep.Text + "', '" + txtBairro
+ "', '" + txtCidade.Text + "', '" + txtUf.Text + "', '"
+ mskTelefone.Text + "')";
SqlConnection con = new SqlConnection(connectionString);
SqlCommand cmd = new SqlCommand(sql, con);
cmd.CommandType = CommandType.Text;
con.Open();
try
{
int i = cmd.ExecuteNonQuery();
if (i > 0)
MessageBox.Show("Cadastro realizado com sucesso!");
}
catch (Exception ex)
{
MessageBox.Show("Erro: " + ex.ToString());
}
finally
{
con.Close();
}
}
Ao observar o código é possível notar que ele está utilizando os dados do formulário para montar a instrução SQL a ser executada e assim inseri-los no banco. A utilização de parâmetros traz proteção para uma prática chamada SQL Injection que consiste em um usuário mal intencionado digitar um código SQL no TextBox, como uma instrução de DELETE e prejudicar o banco de dados, já que o código da aplicação está utilizando o texto no TextBox para montar a instrução SQL o que o usuário digitar fará parte desta instrução.
Quando se utiliza parâmetros a instrução SQL, esta fica mais segura contra SQL Injection e por isso é a maneira recomendável de se trabalhar.
Agora será desenvolvido uma tela de cadastro para a demonstração da utilização de parâmetros.
Será usado uma tela de cadastro e um banco de dados de exemplo para entendimento e para o desenvolvimento, será usado C# com Visual Studio 2012 e SQL Server 2012 do mesmo. Para melhor compreensão deste artigo será necessário um conhecimento prévio de SQL, C#.
A Listagem 2 contém o código necessário para a criação do banco de dados e tabela do exemplo.
/* CRIAR BANCO DE DADOS */
CREATE DATABASE BDCADASTRO
/* SELECIONA O BANCO DE DADOS */
USE BDCADASTRO
/* CRIACÇÃO DA TABELA */
CREATE TABLE CLIENTE (
ID INT NOT NULL IDENTITY,
NOME VARCHAR(50) NOT NULL,
ENDERECO VARCHAR(50),
CEP VARCHAR(9),
BAIRRO VARCHAR(50),
CIDADE VARCHAR(50),
UF VARCHAR(2),
TELEFONE VARCHAR(15),
CONSTRAINT PK_CLIENTE PRIMARY KEY(ID)
)
Crie um formulário conforme a Figura 1.
Crie os campos conforme a Tabela 1.
Campos | Propriedades |
---|---|
Cadastro de cliente | Tipo: Form Name: frmCadastroCliente StartPosition: CenterScreen |
Id | Tipo: TextBox Name: txtId ReadOnly: True |
Nome | Tipo: TextBox Name: txtNome CharacterCasing: Upper MaxLength: 50 |
Endereço | Tipo: TextBox Name: txtEndereco CharacterCasing: Upper MaxLength: 50 |
CEP | Tipo: MaskedTextBox Name: mskCEP Mask: 00000-999 |
Bairro | Tipo: TextBox Name: txtBairro CharacterCasing: Upper MaxLength: 50 |
Cidade | Tipo: TextBox Name: txtCidade CharacterCasing: Upper MaxLength: 50 |
UF | Tipo: TextBox Name: txtUf CharacterCasing: Upper MaxLength: 2 |
Telefone | Tipo: MaskedTextBox Name: mskTelefone Mask: (99) 0000-0000 |
Barra de botões | Tipo: ToolStrip Name: toolStrip1 |
Novo | Tipo: ToolStripButton Name: tsbNovo Text: Novo |
Salvar | Tipo: ToolStripButton Name: tsbSalvar Text: Salvar |
Cancelar | Tipo: ToolStripButton Name: tsbCancelar Text: Cancelar |
Excluir | Tipo: ToolStripButton Name: tsbExcluir Text: Excluir |
Separador | Tipo: ToolStripSeparator Name: toolStripSeparator1 |
Buscar por Id: | Tipo: ToolStripLabel Name: tsbBuscaPorId Text: Buscar por Id: |
Tipo: ToolStripTextBox Name: tstId |
|
Buscar | Tipo: ToolStripButton Name: tsbBuscar Text: Buscar |
As imagens para os botões podem ser encontradas no site IconFider, basta apenas procurar pelo nome.
Dê dois cliques em uma área vazia do formulário, será mostrado o arquivo frmCadastroCliente.cs e será criado o método frmCadastroCliente_Load. Logo acima do método frmCadastroCliente_Load existe o construtor da classe que é o frmCadastroCliente e acima deste, crie as seguintes variáveis conforme a Listagem 3.
string connectionString = @"Server=.;Database=bdcadastro;Trusted_Connection=True;";
bool novo;
public frmCadastroCliente()
{
InitializeComponent();
}
private void frmCadastroCliente_Load(object sender, EventArgs e)
{
}
A variável connectionString armazena a string de conexão com o banco de dados e a variável novo será usada para quando salvar saber se o que será salvo é um novo registro ou uma atualização de um registro existente.
Quando o programa for executado alguns campos deverão aparecer desabilitados e só serão habilitados ao clicar no botão Novo, permitindo assim digitar as informações, e também alguns botões da barra também estarão inacessíveis e serão habilitados conforme a situação. Essas mudanças de estado ocorrerão a cada evento, o método frmCadastroCliente_Load é executado ao carregar o formulário e para obter a configuração inicial do formulário insira o seguinte código no método, conforme mostra a Listagem 4.
private void frmCadastroCliente_Load(object sender, EventArgs e)
{
tsbNovo.Enabled = true;
tsbSalvar.Enabled = false;
tsbCancelar.Enabled = false;
tsbExcluir.Enabled = false;
tstId.Enabled = true;
tsbBuscar.Enabled = true;
txtNome.Enabled = false;
txtEndereco.Enabled = false;
mskCep.Enabled = false;
txtBairro.Enabled = false;
txtCidade.Enabled = false;
txtUf.Enabled = false;
mskTelefone.Enabled = false;
}
Agora a Listagem 5 mostra o código do botão Novo.
private void tsbNovo_Click(object sender, EventArgs e)
{
tsbNovo.Enabled = false;
tsbSalvar.Enabled = true;
tsbCancelar.Enabled = true;
tsbExcluir.Enabled = false;
tstId.Enabled = false;
tsbBuscar.Enabled = false;
txtNome.Enabled = true;
txtEndereco.Enabled = true;
mskCep.Enabled = true;
txtBairro.Enabled = true;
txtCidade.Enabled = true;
txtUf.Enabled = true;
mskTelefone.Enabled = true;
txtNome.Focus();
novo = true;
}
Pode-se notar que a última linha de código está sendo atribuído true para a variável novo, mais adiante será possível entender melhor que isso significa que ao clicar no botão Novo será incluído um novo registro.
A Listagem 6 contém com o código do botão Salvar.
private void tsbSalvar_Click(object sender, EventArgs e)
{
if (novo)
{
string sql = "INSERT INTO CLIENTE (NOME,ENDERECO,CEP,BAIRRO,CIDADE,
UF,TELEFONE) " +
"VALUES (@Nome, @Endereco, @Cep, @Bairro, @Cidade, @Uf, @Telefone)";
SqlConnection con = new SqlConnection(connectionString);
SqlCommand cmd = new SqlCommand(sql, con);
cmd.Parameters.AddWithValue("@Nome", txtNome.Text);
cmd.Parameters.AddWithValue("@Endereco", txtEndereco.Text);
cmd.Parameters.AddWithValue("@Cep", mskCep.Text);
cmd.Parameters.AddWithValue("@Bairro", txtBairro.Text);
cmd.Parameters.AddWithValue("@Cidade", txtCidade.Text);
cmd.Parameters.AddWithValue("@Uf", txtUf.Text);
cmd.Parameters.AddWithValue("@Telefone", mskTelefone.Text);
cmd.CommandType = CommandType.Text;
con.Open();
try
{
int i = cmd.ExecuteNonQuery();
if (i > 0)
MessageBox.Show("Registro incluido com sucesso!");
}
catch (Exception ex)
{
MessageBox.Show("Erro: " + ex.ToString());
}
finally
{
con.Close();
}
}
else
{
string sql = "UPDATE CLIENTE SET NOME=@Nome, ENDERECO=@Endereco,
CEP=@Cep, BAIRRO=@Bairro, " +
"CIDADE=@Cidade, UF=@Uf, TELEFONE=@Telefone WHERE ID=@Id";
SqlConnection con = new SqlConnection(connectionString);
SqlCommand cmd = new SqlCommand(sql, con);
cmd.Parameters.AddWithValue("@Id", txtId.Text);
cmd.Parameters.AddWithValue("@Nome", txtNome.Text);
cmd.Parameters.AddWithValue("@Endereco", txtEndereco.Text);
cmd.Parameters.AddWithValue("@Cep", mskCep.Text);
cmd.Parameters.AddWithValue("@Bairro", txtBairro.Text);
cmd.Parameters.AddWithValue("@Cidade", txtCidade.Text);
cmd.Parameters.AddWithValue("@Uf", txtUf.Text);
cmd.Parameters.AddWithValue("@Telefone", mskTelefone.Text);
cmd.CommandType = CommandType.Text;
con.Open();
try
{
int i = cmd.ExecuteNonQuery();
if (i > 0)
MessageBox.Show("Registro atualizado com sucesso!");
}
catch (Exception ex)
{
MessageBox.Show("Erro: " + ex.ToString());
}
finally
{
con.Close();
}
}
tsbNovo.Enabled = true;
tsbSalvar.Enabled = false;
tsbCancelar.Enabled = false;
tsbExcluir.Enabled = false;
tstId.Enabled = true;
tsbBuscar.Enabled = true;
txtNome.Enabled = false;
txtEndereco.Enabled = false;
mskCep.Enabled = false;
txtBairro.Enabled = false;
txtCidade.Enabled = false;
txtUf.Enabled = false;
mskTelefone.Enabled = false;
txtId.Text = "";
txtNome.Text = "";
txtEndereco.Text = "";
mskCep.Text = "";
txtBairro.Text = "";
txtCidade.Text = "";
txtUf.Text = "";
mskTelefone.Text = "";
}
Neste código há um if que testa o valor da variável novo para saber se é um registro novo e executa o código.
Quando novo=true a variável sql que é uma string recebe uma instrução SQL de INSERT que está sendo montada com seu parâmetros e depois cada parâmetro recebe o valor de um campo.
Logo após é criado um objeto com o tipo SqlConnection que é a conexão com o banco e que recebe como parâmetro no momento da instanciação a variável connectionString que foi criada anteriormente e que contém a string de conexão.
Depois é criado o objeto cmd que é um SqlCommand que recebe como parâmetro no seu construtor a variável sql que contém a instrução SQL e o objeto con que é a conexão. Depois é atribuído um valor para cada parâmetro da instrução SQL.
O objeto cmd será responsável por executar a instrução SQL.
Depois é definido o tipo de comando do objeto cmd, no caso Text, logo em seguida é aberta a conexão.
Dentro do bloco try é executada a instrução SQL do objeto cmd através do método ExecuteNonQuery que retorna o número de linha afetadas, que no caso é armazenada na variável inteira i.
Logo após testa-se se o valor de i é maior que 0, se sim o registro foi incluído com sucesso.
Voltando um pouco, se quando o if testa a variável novo e for false executa o código contido no bloco else o que significa que está fazendo uma atualização de um registro.
O código é praticamente o mesmo, a não ser pela instrução SQL que agora é um UPDATE.
Logo depois é alterado o estado dos controles do formulário novamente.
A Listagem 7 contém o código do botão Cancelar, que só é alterado o estado dos controles e limpa os TextBox’s.
private void tsbCancelar_Click(object sender, EventArgs e)
{
tsbNovo.Enabled = true;
tsbSalvar.Enabled = false;
tsbCancelar.Enabled = false;
tsbExcluir.Enabled = false;
tstId.Enabled = true;
tsbBuscar.Enabled = true;
txtNome.Enabled = false;
txtEndereco.Enabled = false;
mskCep.Enabled = false;
txtBairro.Enabled = false;
txtCidade.Enabled = false;
txtUf.Enabled = false;
mskTelefone.Enabled = false;
txtId.Text = "";
txtNome.Text = "";
txtEndereco.Text = "";
mskCep.Text = "";
txtBairro.Text = "";
txtCidade.Text = "";
txtUf.Text = "";
mskTelefone.Text = "";
}
A Listagem 8 mostra o código do botão Excluir, que é bem parecido ao do botão Salvar, só que agora com a instrução de DELETE.
private void tsbExcluir_Click(object sender, EventArgs e)
{
string sql = "DELETE FROM CLIENTE WHERE ID=@Id";
SqlConnection con = new SqlConnection(connectionString);
SqlCommand cmd = new SqlCommand(sql, con);
cmd.Parameters.AddWithValue("@Id", txtId.Text);
cmd.CommandType = CommandType.Text;
con.Open();
try
{
int i = cmd.ExecuteNonQuery();
if (i > 0)
MessageBox.Show("Registro excluído com sucesso!");
}
catch (Exception ex)
{
MessageBox.Show("Erro: " + ex.ToString());
}
finally
{
con.Close();
}
tsbNovo.Enabled = true;
tsbSalvar.Enabled = false;
tsbCancelar.Enabled = false;
tsbExcluir.Enabled = false;
tstId.Enabled = true;
tsbBuscar.Enabled = true;
txtNome.Enabled = false;
txtEndereco.Enabled = false;
mskCep.Enabled = false;
txtBairro.Enabled = false;
txtCidade.Enabled = false;
txtUf.Enabled = false;
mskTelefone.Enabled = false;
txtId.Text = "";
txtNome.Text = "";
txtEndereco.Text = "";
mskCep.Text = "";
txtBairro.Text = "";
txtCidade.Text = "";
txtUf.Text = "";
mskTelefone.Text = "";
}
A Listagem 9 mostra o código do botão Buscar.
private void tsbBuscar_Click(object sender, EventArgs e)
{
string sql = "SELECT * FROM CLIENTE WHERE ID=@Id";
SqlConnection con = new SqlConnection(connectionString);
SqlCommand cmd = new SqlCommand(sql, con);
cmd.Parameters.AddWithValue("@Id", tstId.Text);
cmd.CommandType = CommandType.Text;
SqlDataReader reader;
con.Open();
try
{
reader = cmd.ExecuteReader();
if (reader.Read())
{
tsbNovo.Enabled = false;
tsbSalvar.Enabled = true;
tsbCancelar.Enabled = true;
tsbExcluir.Enabled = true;
tstId.Enabled = false;
tsbBuscar.Enabled = false;
txtNome.Enabled = true;
txtEndereco.Enabled = true;
mskCep.Enabled = true;
txtBairro.Enabled = true;
txtCidade.Enabled = true;
txtUf.Enabled = true;
mskTelefone.Enabled = true;
txtNome.Focus();
txtId.Text = reader[0].ToString();
txtNome.Text = reader[1].ToString();
txtEndereco.Text = reader[2].ToString();
mskCep.Text = reader[3].ToString();
txtBairro.Text = reader[4].ToString();
txtCidade.Text = reader[5].ToString();
txtUf.Text = reader[6].ToString();
mskTelefone.Text = reader[7].ToString();
novo = false;
}
else
MessageBox.Show("Nenhum registro encontrado com o Id informado!");
}
catch (Exception ex)
{
MessageBox.Show("Erro: " + ex.ToString());
}
finally
{
con.Close();
}
tstId.Text = "";
}
No código do botão Buscar contém uma instrução de SELECT que retorna o registro com o Id informado.
Uma diferença é que além do objeto cmd agora também há um objeto reader do tipo SqlDataReader que armazena o conteúdo retornado da consulta, como é mostrado na Listagem 10.
reader = cmd.ExecuteReader();
Em seguida o if testa se há registro no reader com o método Read, se sim, executa o bloco.
O que há de diferente é que logo após alterar os estados dos controles o foco do cursor é posicionado no campo txtNome através do método Focus e é atribuído a cada campo o valor correspondente que está no reader.
Para acessar os campos no reader é utilizado o índice do campo, esse índice é a ordem dos campos, para poder vê-los basta executar um SELECT no SQL Server Management Studio e verificar o retorno, o primeiro campo inicia no índice 0.
Foi demonstrado neste artigo como criar um CRUD utilizando parâmetros ao invés de concatenar os valores dos campos com as string de instrução SQL, esta é uma maneira mais segura e otimizada de executar instruções SQL.
Qualquer dúvida é só entrar em contato.