Imagens no banco de dados – Resumo

Nestes três anos, trabalhei várias formas de utilizar imagens armazenadas em banco de dados com C# e SQL Server, eu espero que tenham gostado:

Imagens no banco de dados 1 – ASP.NET Web Forms

Imagens no banco de dados 2 – ASP.NET MVC

Imagens no banco de dados 3 – Windows Forms

Imagens no banco de dados 4.1 – Relatórios em RDLC

Imagens no banco de dados 4.2 – Relatórios em RDLC

Imagens no banco de dados 5 – Importando arquivos por T-SQL

Imagens no banco de dados 4.2 – Relatórios em RDLC

No caso de aplicações Windows Forms, também utilizaremos o ReportViewer:

E clicando sobre a seta indicada:

Definiremos o relatório a ser utilizado, e automaticamente será gerada estrutura para ligar o ReportViewer à fonte de dados:

Por fim, a aplicação em execução e a visualização do relatório:

Imagens no banco de dados 4.1 – Relatórios em RDLC

Uma funcionalidade muito útil do Visual Studio é a criação de relatórios em RDLC (Report Definition Language Client-side).

Estes relatórios em RDLC podem ser utilizando tanto em aplicações Web ou Windows Forms.

O primeiro passo para criação de um relatório em RDLC é adicionar um item Report ao projeto:

Neste relatório, vamos adicionar uma imagem estática, que nos servirá de “logo”:

Neste caso, importaremos uma imagem do computador, com o botão “Import”:

Agora temos nosso relatório com uma logo simples:

Para recuperar informações do banco de dados, precisaremos definir a nossa fonte de dados criando um Dataset:

Configuramos o banco de dados a ser utilizado por este Dataset:

E as tabelas a serem utilizadas:

Por fim, temos nosso Dataset configurado:

Adicionamos uma tabela ao nosso relatório:

Tabela adicionada e ajustada no layout do relatório:

Definimos o Dataset utilizado pela tabela:

E adicionamos uma imagem na área “Data” da tabela:

Para esta imagem que será “dinâmica”, definimos que ela virá da fonte “Database”, utilizando a campo “Bytes”, que no caso é a coluna onde estão armazenados os bytes das imagens em nossa tabela:

Por fim, adicionamos o campo “Nome” da imagem à tabela do relatório:

E ajustamos mais um pouco o layout:

No caso de aplicações Web, adicionaremos uma página simples ao projeto:

E nesta página adicionamos um ReportViewer:

Selecionando o ReportViewer, clicamos sobre a flecha indicada:

Definimos qual o relatório a ser utilizado:

Neste passo, será automaticamente criado um ObjectDataSource e já ligado ao nosso Dataset.

Por fim, adicionamos um ScriptManager a esta página:

Então teremos a página configurada com o ScriptManager, e o ReportViewer já ligado a um componente de fonte de dados (ObjectDataSource):

Agora, executar o projeto e ver o relatório com imagens do banco de dados:

Imagens no banco de dados 3 – Windows Forms

Não é somente em aplicações Web que se podem ter arquivos salvos em banco de dados, também é possível desenvolver aplicações com Windows Forms para salvar e recuperar imagens ou arquivos do banco de dados.

Para um breve exemplo, vamos criar uma aplicação Windows Forms no Visual Studio, com um formulário com um botão ‘Escolher’ para o “upload” da imagem/arquivo e um botão ‘Mostrar’ para exibir a imagem. Para a caixa de seleção do arquivo, precisaremos de um Open File Dialog e para exibição, um Picture Box:

Desta vez, estaremos utilizando Entity Framework para salvar a imagem/arquivo no banco de dados (ainda com a mesma modelagem do artigo anterior).

Ajustamos os eventos do formulário:

using System;
using System.ComponentModel;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using Microsoft.Win32;

namespace DemoApp.WinForms
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        public int ArquivoId { get; set; }

        /// <summary>
        /// Clique do botão Escolher abre OpenFileDialog
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnEscolher_Click(object sender, EventArgs e)
        {
            ofdEscolher.ShowDialog();
        }

        /// <summary>
        /// Retorno do OpenFileDialog
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ofdEscolher_FileOk(object sender, CancelEventArgs e)
        {
            var file = new FileInfo(ofdEscolher.FileName);

            var obj = new Arquivos
                          {
                              Nome = file.Name,
                              Extensao = file.Extension,
                              Tipo = GetMimeType(file.Extension)
                          };

            using (var stream = ofdEscolher.OpenFile())
            using (var reader = new BinaryReader(stream))
                obj.Bytes = reader.ReadBytes((int)stream.Length);

            using (var context = new DemoAppEntities())
            {
                context.AddObject("Arquivos", obj);
                context.SaveChanges();
            }

            // Regra somente para efeito de demonstração,
            // pois restrições devem ser criadas no Open File Dialog
            if (obj.Extensao == ".jpg")
                ArquivoId = obj.ArquivoId;
        }

        /// <summary>
        /// Recuperar Content Type do registro do Windows,
        /// por compatibilidade às aplicações Web
        /// Original.: http://www.codeproject.com/KB/dotnet/ContentType.aspx
        /// </summary>
        /// <param name="ext"></param>
        /// <returns></returns>
        public string GetMimeType(string ext)
        {
            var classesRoot = Registry.ClassesRoot;

            var typeKey = classesRoot.OpenSubKey(@"MIME\Database\Content Type");

            if (typeKey == null) return string.Empty;

            return (
                       from regExt in typeKey.GetSubKeyNames()
                       let path = @"MIME\Database\Content Type\" + regExt
                       let curKey = classesRoot.OpenSubKey(path)
                       where curKey != null
                       let value = curKey.GetValue("Extension")
                       where value != null && value.ToString().ToLower() == ext
                       select regExt
                   ).FirstOrDefault() ?? string.Empty;
        }

        /// <summary>
        /// Recuperando imagem do banco de dados e exibindo em um PictureBox
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnMostrar_Click(object sender, EventArgs e)
        {
            if (ArquivoId == 0) return;

            Arquivos obj;

            using (var context = new DemoAppEntities())
                obj = context.Arquivos.FirstOrDefault(a => a.ArquivoId == ArquivoId);

            if (obj == null) return;

            var stream = new MemoryStream(obj.Bytes);

            picImagem.Image = Image.FromStream(stream);
        }
    }
}

Agora na execução, clicamos no botão “Escolher”:

Escolhemos o arquivo para importação, no caso uma imagem JPG.

Por fim, com um clique sobre o botão Mostrar, teremos a imagem no Picture Box:

Em um cenário real, criem restrições dos tipos de arquivos no processo de importação/download da imagem/arquivo. No caso de aplicações Windows Forms, estas restrições serão no Open File Dialog.

Imagens no banco de dados 2 – ASP.NET MVC

Quem aderiu ao ASP.NET MVC também pode salvar imagens ou arquivos no banco de dados? Mas é claro e para provar isso, vamos ao exemplo.

Após criar a tabela no banco de dados (conforme o artigo anterior), o primeiro passo será definir a tecnologia de acesso aos dados. No caso utilizaremos LINQ to SQL:

Para a interface, a nossa Index.cshml necessitará somente do seguinte código:

@using (Html.BeginForm(null, null, FormMethod.Post, new { enctype = "multipart/form-data" }))
{
    <div>
        <input id="file" name="file" type="file" />
    </div>
    <div>
        <button type="submit">
            Enviar</button>
    </div>
}

No caso, estou utilizando Razor, mas é fácil adequar para ASPX.

E na Controller, teremos os métodos Index para salvar o arquivo no banco de dados e o método Viewer para recuperar o arquivo do banco de dados:

using System.IO;
using System.Linq;
using System.Web.Mvc;

namespace DemoApp.AspMvc.Controllers
{
    public class HomeController : Controller
    {
        //
        // GET: /Home/

        public ActionResult Index()
        {
            return View();
        }

        //
        // POST: /Home/

        [HttpPost]
        public ActionResult Index(FormCollection form)
        {
            if (Request.Files.Count != 1) return View();

            var post = Request.Files[0];

            if (post == null) return View();

            var obj = new Models.Arquivo();

            var file = new FileInfo(post.FileName);
            obj.Nome = file.Name;
            obj.Extensao = file.Extension;
            obj.Tipo = post.ContentType;

            using (var reader = new BinaryReader(post.InputStream))
                obj.Bytes = reader.ReadBytes(post.ContentLength);

            using (var context = new Models.DemoAppDataContext())
            {
                context.Arquivos.InsertOnSubmit(obj);
                context.SubmitChanges();
            }

            return RedirectToAction("Viewer", new { id = obj.ArquivoId });
        }

        //
        // GET: /Home/Viewer/id

        public ActionResult Viewer(int id)
        {
            ActionResult result;

            using (var context = new Models.DemoAppDataContext())
            {
                var obj = context.Arquivos.FirstOrDefault(a => a.ArquivoId == id);

                result = obj == null
                    ? (ActionResult)View("Error")
                    : new FileContentResult(obj.Bytes.ToArray(), obj.Tipo);
            }

            return result;
        }
    }
}

Por fim, a página de upload:

E a página de visualização do arquivo:

E ai Paulo, já acabou esta série de artigos? Não, ainda teremos outros exemplos, aguardem!

Imagens no banco de dados 1 – ASP.NET Web Forms

Atendendo ao pedido do Luiz H. S. Pereira, vamos ver um pouco como trabalhar com aplicações e imagens/arquivos salvos em banco de dados.

Neste primeiro artigo, veremos como fazer isso com ASP.NET Web Forms.

O primeiro passo é a tabela onde serão armazenados os arquivos:

USE DemoApp
GO
CREATE TABLE Arquivos (
	ArquivoId	INT IDENTITY	PRIMARY KEY,
	Nome		VARCHAR(250)	NOT NULL,
	Bytes		VARBINARY(MAX)	NOT NULL,
	Extensao	CHAR(5)			NOT NULL,
	Tipo		VARCHAR(250)	NOT NULL
)

O segundo passo é criar uma página com o componente FileUpload (fupArquivo) e um Button (btnEnvio) para o envio:

Trataremos o evento do Button de envio, salvando os dados do arquivo no banco de dados:

using System;
using System.Data.SqlClient;
using System.IO;
using System.Web.UI;

namespace DemoApp.WebForms
{
    public partial class Default : Page
    {
        protected void btnEnviar_Click(object sender, EventArgs e)
        {
            string url;

            const string connString =
                @"Data Source=localhost\SQLEXPRESS;Initial Catalog=DemoApp;Integrated Security=True";

            using (var conn = new SqlConnection(connString))
            {
                conn.Open();

                using (var cmd = conn.CreateCommand())
                {
                    cmd.CommandText =
                        "INSERT INTO [Arquivos] VALUES (@Nome, @Bytes, @Extensao, @Tipo)"
                        + " SELECT SCOPE_IDENTITY()";

                    var file = new FileInfo(fupArquivo.FileName);
                    cmd.Parameters.AddWithValue("@Nome", file.Name);
                    cmd.Parameters.AddWithValue("@Bytes", fupArquivo.FileBytes);
                    cmd.Parameters.AddWithValue("@Extensao", file.Extension);
                    cmd.Parameters.AddWithValue("@Tipo", fupArquivo.PostedFile.ContentType);

                    var codigo = cmd.ExecuteScalar();

                    url = string.Format("ImageHandler.ashx?id={0}", codigo);
                }
            }

            Response.Redirect(url);
        }
    }
}

Para exibição do arquivo salvo no banco de dados, criaremos um Generic Handler:

Com Handler criado:

Configuraremos o Handler para recuperar o arquivo do banco de dados:

using System.Data.SqlClient;
using System.Web;

namespace DemoApp.WebForms
{
    /// <summary>
    /// Summary description for ImageHandler
    /// </summary>
    public class ImageHandler : IHttpHandler
    {
        public bool IsReusable { get { return false; } }

        public void ProcessRequest(HttpContext context)
        {
            var codigo = context.Request.QueryString["id"];

            if (codigo == null) return;

            const string connString =
                @"Data Source=localhost\SQLEXPRESS;Initial Catalog=DemoApp;Integrated Security=True";

            using (var conn = new SqlConnection(connString))
            {
                conn.Open();

                using (var cmd = conn.CreateCommand())
                {
                    cmd.CommandText =
                        "SELECT Tipo, Bytes FROM [Arquivos] WHERE ArquivoId = @ArquivoId";

                    cmd.Parameters.AddWithValue("@ArquivoId", codigo);

                    var dr = cmd.ExecuteReader();

                    if (dr.Read())
                    {
                        context.Response.ContentType = dr.GetString(0);

                        context.Response.BinaryWrite((byte[])dr[1]);
                    }
                }
            }
        }
    }
}

Por fim, importamos o arquivo:

Se tudo der certo, o arquivo será exibido:

Modelagem com ADO.NET Entity Framework 4.0: Gerando o banco de dados a partir das classes

E ai pessoal!

Para quem já me conhece, sabe que sou fã de bancos de dados Orientados a Objetos (ex.: Caché), pelo simples fato de trabalhar diretamente com classe no banco de dados (e a forma de trabalhar com SQL do Caché é muito legal). Mesmo que a maioria dos bancos de dados são relacionais e outros hierárquicos, vale a pena pensar na Orientação a Objetos como uma forma de abstrair as entidades do banco.

Um dos melhores conceitos de abstração de banco de dados com a utilização de classes que tenho trabalhado é o ADO.NET Entity Framework, que teve uma evolução considerável na plataforma .NET 4.0.

Acho que falei muito, então vamos ver como utilizar o Visual Studio 2010, como uma ferramenta de abstração do banco de dados (pensando aqui em orientação a objetos) com o Entity Data Model!

First, eu criei um projeto “Console Application” bem simples, só para efeitos de demonstração:

Adiciono um “ADO.NET Entity Data Model” ao projeto:

Visto que estamos pensando em começar a modelagem do ZERO, vamos partir de um Empty Model:

Criado o modelo, podemos utilizar a Toolbox para acionar entidades, relacionamentos e heranças:

Assim, adicionei uma entidade (ou classe) e a nomeei na abstração de “Cliente”, que será para o meu banco de dados a entidade “Clientes”:

Adicionei também a propriedade Nome do tipo String:

Feito isso, vamos gerar o banco de dados! Então botão direito sobre o modelo e “Generate Database from Model”:

Na próxima tela, é necessário definir uma conexão válida, escolher ou dar um nome ao banco de dados:

No caso, informei o nome de banco de dados que não existe ainda, assim a aplicação vai perguntar se desejo criá-lo:

Nice! Agora você pode ver a string de conexão do Entity Framework que será gravada no arquivo “.Config” da aplicação:

Em seguida, o script de criação das tabelas no banco de dados. Informando um caminho válido na aplicação para salvar o script:

Se você der uma olhada no mapeamento da entidade que foi criada, verá que a partir de agora ela referencia uma tabela no banco de dados:

Para gerar a tabela no banco de dados, abrirei o arquivo de criação das tabelas:

Conectarei ao meu SQL Server:

Escolherei o banco de dados onde serão geradas as minhas tabelas:

Enfim, executar o script:

Se quiser conferir, no SQL Server Management Studio esta lá o banco de dados com toda a estrutura de tabelas que abstraí no modelo no Visual Studio 2010:

Então pessoal, agora temos uma ótima ferramenta para modelar as classe das aplicações .NET, que pode facilitar muito a modelagem do banco de dados. Não sei se vou escrever muita coisa sobre ADO.NET nas próximas semanas, mas sempre que possível vou dar uma palhinha do que existe para os desenvolvedores no mundo mais back-end.

ADO.NET: DataReader e Transações

Neste artigo trabalharei dois outros objetos muito importantes no ADO.Net, o DataReader e o Transaction, responsáveis pela leitura de dados no banco e pela ACID (Atomicidade, Consistência, Isolamento, Durabilidade) na manipulação de dados repectivamente.

Quando se espera o resultado de uma consulta SQL com mais de uma célula, pode ser utilizado objetos DataReader como forma de executar uma consulta no banco de dados retornando gradualmente o resultado, mantendo a conexão com o banco de dados até que a conexão seja encerrada.

DataReader: Recomendado em situações onde há a necessidade de ler o resultado de uma consulta. Abaixo dois exemplos típicos de como realizar consultas com o DataReader:

//Consulta de várias linhas.
Dictionary<int, string> dic = new Dictionary<int, string>();
string queryString = "SELECT id, nome FROM pessoa";
using (SqlConnection connection = new SqlConnection(connectionString))
{
  connection.Open();
  SqlCommand command = new SqlCommand(queryString, connection);
  using (SqlDataReader reader = command.ExecuteReader())
  {
    while (reader.Read())
    {
      dic.Add((int)reader[0], (string)reader[1]);
    }
  }
}
return dic;
//Consulta de uma única linha
string result = string.Empty;
string queryString = "SELECT id, nome FROM pessoa";
using (SqlConnection connection = new SqlConnection(connectionString))
{
  connection.Open();
  SqlCommand command = new SqlCommand(queryString, connection);
  using (SqlDataReader reader = command.ExecuteReader())
  {
    if (reader.Read())
    {
      result = String.Format("{0} - {1}", reader[0], reader[1]));
    }
  }
}
return result;

Visto a dependência da conexão com o banco de dados, o DataReader pode ser adaptado para fechar a conexão automaticamente ao finalizar a leitura, utilizando “CommandBehavior.CloseConnection”.

//Consulta de uma única linha
string queryString = "SELECT id, nome FROM pessoa";
SqlConnection connection = new SqlConnection(connectionString);
connection.Open();
SqlCommand command = new SqlCommand(queryString, connection);
return command.ExecuteReader(CommandBehavior.CloseConnection);

O DataReader pode retornar mais de uma consulta, que pode ser acessada facilmente com o método NextResult:

//Consulta de várias linhas
Dictionary<int, string> dic = new Dictionary<int, string>();
string queryString = "SELECT id, nome FROM pessoa1;\n"
  + "SELECT id, nome FROM pessoa2;";
using (SqlConnection connection = new SqlConnection(connectionString))
{
  connection.Open();
  SqlCommand command = new SqlCommand(queryString, connection);
  using (SqlDataReader reader = command.ExecuteReader())
  {
    while (reader.Read())
    {
      dic.Add((int)reader[0], (string)reader[1]);}
      reader.NextResult();
      while (reader.Read())
      {
        dic.Add((int)reader[0], (string)reader[1]);
      }
    }
  }
}
return dic;

ou

//Consulta de várias linhas
Dictionary<int, string> dic = new Dictionary<int, string>();
string queryString = "SELECT id, nome FROM pessoa1;\n"
  + "SELECT id, nome FROM pessoa2;";
using (SqlConnection connection = new SqlConnection(connectionString))
{
  connection.Open();
  SqlCommand command = new SqlCommand(queryString, connection);
  using (SqlDataReader reader = command.ExecuteReader())
  {
    do
    {
      while (reader.Read())
      {
        dic.Add((int)reader[0], (string)reader[1]);
      }
    } while(reader.NextResult());
  }
}
return dic;

Transaction: Para situações onde é necessário inserir ou alterar muitos registros no banco de dados de uma só vez e desfazer estas inserções ou alterações caso ocorra algum erro, é recomendado o uso de transação (Transaction).

Conforme o exemplo abaixo, é aberta uma conexão e criada uma transação pelo método “BeginTransaction”. Dentro da transação são executados dois métodos de inserção, caso algum deles dê erro será executado o método “RollBack” que desfará as inserções no banco de dados. Caso não haja erro, será necessário executar o método “Commit” para que as inserções tenham efeito.

using (SqlConnection connection = new SqlConnection(connectionString))
{
  connection.Open();
  using (SqlTransaction transaction = connection.BeginTransaction())
  {
    SqlCommand command = connection.CreateCommand();
    command.Connection = connection;
    command.Transaction = transaction;
    try
    {
      command.CommandText = "INSERT INTO tabela VALUES ('valor')";
      command.ExecuteNonQuery();
      command.CommandText = "INSERT INTO tabela VALUES ('valor')";
      command.ExecuteNonQuery();
      transaction.Commit();
    }
    catch
    {
      transaction.Rollback();
    }
  }
}

Transações não possuem “segredo”, são simples de serem utilizadas, mas em compensação, a execução dos comandos SQL podem demorar um pouco mais, afim de garantir atomicidade, consistência, isolamento, durabilidade do que esta sendo executado. Mas não se preocupe com situações simples, como a execução de um único comando de delete, insert ou update, pois o SQL Server possui transações implícitas nestes comandos, para evitar situações como alterar, deletar ou inserir “pela metade”.

ADO.NET: Introdução

Com o advento Framework.Net, se possibilitou novos recursos de acessos a dados, de forma a facilitar do desenvolvimento até migração entre plataformas de SGDB.

O ADO.Net, principal recurso de acesso a banco de dados na plataforma .Net, se popularizou por sua arquitetura orientada a objeto e o suporte as principais plataforma de SGDB do mercado, como Oracle e SQL Server, além de suporte a OleDb e ODBC, que possibilitam a integração com Excel, DB2, Interbase, PostGree, Firebird e MySQL, sem a necessidade de utilizar qualquer componente de terceiros.

Também existem outros recursos desenvolvidos que estendem ou reimplementam a arquitetura de acessos a SGDB de forma especializada, como no caso da Oracle, do Firebird e do MySQL, que desenvolvem suas próprias extensões do ADO.Net, afim de atender necessidade específicas de suas plataformas. Em relação ao SQL Server, a Framework.Net possui outros recursos exclusivos para prover integração com CLR.

Existem duas formas básicas de trabalhar com o ADO.Net, por meio de classes conectadas e desconectadas.

As classes conectadas permitem o acesso ao SGBD, por meio do .Net Data Provider, que constitui basicamente das seguintes entidades:

Connection: Responsável pela conexão ao SGDB, esta classe varia SGDB para SGDB (ex. SQLConnection, OracleConnection, OleDbConnection e OdbcConnection), possuindo métodos e propriedades que facilitam criar a conexão com cada um dos SGDB.

Por questões de arquitetura, para exigir que a conexão se feche depois de realizada a operação é recomendado o uso do bloco “Using”, exemplo:

// Criando o objeto de conexão ao banco de dados
using (SqlConnection conn = new SqlConnection("string de conexão"))
{
  // Chamando o método responsável pela abertura da conexão.
  conn.Open();
}

Recomendável não utilizar nenhum retorno de métodos dentro de blocos “Using”:

// Criando o objeto de conexão ao banco de dados
using (SqlConnection conn = new SqlConnection("string de conexão"))
{
  // Chamando o método responsável pela abertura da conexão.
  conn.Open();
  // Nunca faça isso:
  return true;

}

String de conexão: É responsável por identificar o endereço do SGDB, formas de autenticação e configurações de acesso.

Em aplicações Web, normalmente esta string é armazenada no arquivo web.config ou aplicações Windows e Windows Mobile no arquivo app.config, por questões de reaproveitamento e para facilitar alterações. Exemplo:

<!--web.config-->
<?xml version="1.0"?>
<configuration>
  <connectionStrings>
    <add name="nome" connectionString="Data Source=in;Initial Catalog=db;User=us;Password=sn;"/>
  </connectionStrings>
</configuration>

Método responsável por retornar a string de conexão do web.config, as vezes se faz necessário adicionar a referência a System.Configuration ao projeto.

ConfigurationManager.ConnectionStrings["nome"].ToString();
// Criando o objeto de conexão ao banco de dados
string connectionString = ConfigurationManager.ConnectionStrings["nome"].ToString()
using (SqlConnection conn = new SqlConnection(connectionString))
{
  // Chamando o método responsável pela abertura da conexão.
  conn.Open();
}

Também existem formas de gerar a connection string em tempo de execução.
(at. http://msdn.microsoft.com/en-us/library/ms254947(VS.80).aspx )

Alguns exemplos de string de conexão para SQL Server e outros bancos de dados:
https://sqlfromhell.wordpress.com/2009/08/04/connection-strings/
http://msdn.microsoft.com/en-us/library/ms254500.aspx

Command: Depois de estabelecida a conexão com o SGDB, esta classe é o responsável por executar comandos e consultas no banco de dados. Seus objetos podem ser instanciado da forma tradicional por meio de um construtor ou chamando o método CreateCommand de objetos de conexão.Exemplo:

using (SqlConnection conn= new SqlConnection(""))
{
  using (SqlCommand cmd = new SqlCommand())
  {
    cmd.Connection = conn;
  }
}

Ou

using (SqlConnection conn= new SqlConnection(""))
{
  using (SqlCommand cmd = conn.CreateCommand())
  {
  }
}

Estes comandos podem ser comandos em SQL, nomes de StoredProcedures ou nomes de tabelas, para define qual o tipo comando é possível definir por meio do enumerador CommandType. Ex.:

// Para comandos SQL
cmd.CommandType = CommandType.Text;
cmd.CommandText = "SELECT * FROM tabela";
// Para stored procedure
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "SpTabelaSel";
// Para tabela
cmd.CommandType = CommandType.TableDirect;
cmd.CommandText = "tabela";

Parâmetros: É a forma ideal de passar valores para comandos SQL e Stored Procedures. São eficazes para combater possíveis ataques de “SQL-Injection”. Exemplos:

//Forma de errada de passar valores para os comandos
cmd.CommandText = "INSERT INTO tabela (valor1) VALUES " + valor + ")";
//Utilizando parâmetros para inserir dados
cmd.CommandText = "INSERT INTO tabela (valor1) VALUES (@nome_parametro)";
cmd.Parameters.Add(new SqlParameter("@nome_parametro", valor);
//Utilizando parâmetros para excluir
cmd.CommandText = "DELETE FROM tabela WHERE valor1 = @nome_parametro";
cmd.Parameters.Add(new SqlParameter("@nome_parametro", valor);
//Utilizando parâmetros para alterar
cmd.CommandText = "UPDATE tabela SET valor1 = @nome_parametro1 WHERE valor2 = @nome_parametro2";
cmd.Parameters.Add(new SqlParameter("@nome_parametro1", valor1);
cmd.Parameters.Add(new SqlParameter("@nome_parametro2", valor2);
//Utilizando parâmetros para consultas
cmd.CommandText = "SELECT * FROM tabela WHERE valor1 = @nome_parametro";
cmd.Parameters.Add(new SqlParameter("@nome_parametro", valor);
//Utilizando parâmetros para StoreProcedures
cmd.CommandText = " SpTabelaSel";
cmd.Parameters.Add(new SqlParameter("@nome_parametro", valor);

A forma ideal de criar parâmetros é definir o tipo, tamanho e valor de forma separada.

//Forma ideal de criar um parâmetro
SqlParameter parameter = new SqlParameter();
parameter.ParameterName = "@nome_parametro";
parameter.SqlDbType = SqlDbType.VarChar;
parameter.Size = 90;
parameter.Value = valor;

ou

SqlParameter parameter = new SqlParameter("@nome_parametro", SqlDbType.VarChar, 90);
parameter.Value = valor;

Métodos de execução: Para comandos que não são esperados retornos é recomendado o uso do método ExecuteNonQuery, cujo o retorno é um inteiro especificando o número de linhas afetadas. Exemplo:

cmd.CommandText = "INSERT INTO tabela (coluna) VALUES ('valor')";
cmd.ExecuteNonQuery();

Para comandos que se espera uma única célula, exemplo a execução das funções SQL, COUNT, SUM, MAX, MIN ou qualquer outra consulta que ternar somente um valor, é recomendado o uso do método ExecuteScalar. Exemplo:

cmd.CommandText = "SELECT COUNT(*) FROM tabela";
int count = (int)cmd.ExecuteScalar();