ASP .NET - Salvando e recuperando Imagens no SQL Server usando o EF6


 Neste artigo eu vou mostrar como podemos salvar e recuperar imagens em um banco de dados SQL Server usando o Entity Framework em uma aplicação ASP .NET Web Forms e a linguagem C#.

O Entity Framework é atualmente a estratégia de acesso a dados recomendada pela Microsoft e oferece recursos para realizar praticamente todas as operações para consulta e manutenção de dados em um banco de dados relacional. Se você ainda usa a ADO .NET em seus projetos, ao migrar para o Entity Framework vai perceber o ganho de produtividade que ele oferece.

Ocorre que muitas tarefas as quais um programador ADO .NET tira de letra podem não ser assim tão simples de realizar com o Entity Framework, não pela complexidade, mas pela nova abordagem que deve ser dada ao problema.

Armazenar e recuperar imagens de um banco de dados é uma dessas tarefas. Como você já deve saber, podemos armazenar as imagens diretamente no banco de dados ou podemos optar por guardar somente a referência à imagem. Você deve considerar bem qual solução vai adotar pois cada uma tem suas vantagens e desvantagens.

Guardar a referência da imagem no banco de dados, é mais simples em termos de código e tem a vantagem de ocupar muito menos espaço do seu banco de dados. Você cria um campo no banco de dados onde guarda o caminho e o nome da imagem. Para exibir a imagem basta recuperar o caminho e nome da imagem exibindo-a em um controle PictureBox. A desvantagem, é que você terá que gerenciar a localização das imagens externamente a sua aplicação.

A maneira mais usada para armazenar dados binários é no sistema de arquivos de Windows, ou seja, armazenar os dados binários como um arquivo no disco local e a outra, a que irei mostrar neste artigo, é armazenar os dados binários diretamente no SQL Server.

Cada opção possui seus prós e seus contras, a seguir eu relaciono alguns motivos que podem justificar cada opção:

1 - Armazenar os dados binários como um arquivo no disco local é uma boa opção se :

O grande problema com esta solução que os dados estarão fora do banco de dados e podem perder a sincronia com os demais dados em operações de exclusão, atualização, inclusão e transferência de dados. Outro fator a considerar é que o backup deverá ser feito separado.

2 - Armazenar os dados binários diretamente no banco de dados SQL Server possui as seguinte vantagens:

Usando o tipo de dados varbinary  do SQL Server podemos armazenar arquivos com até 2GB de tamanho.

Para estes casos específicos o SQL Server fornece um tipo de dados especial apropriados para um grande volume de dados e neste artigo eu vou mostrar como podemos ler e gravar BLOBs - Binary Large Objects usando o SQL Server e ADO .NET.

 Nota: BLOB é um acrônimo para binary large object , uma coleção de dados binários armazenados em um identidade única no SQL Server.

Estes tipos de dados, Large Objects , podem ser classificados em CLOBs - Character Large Objects ou BLOBs - Binary Large Objects e o SQL Server possui um tipo diferente de dados para cada um destes objetos. Vejamos na tabela abaixo os tipos de dados que podemos usar neste caso:

LOB Type Tipo de dadaos SQL  Server Tamanho Máximo Os tipos de dados (*) Text, NText e Image já existiam em versões anteriores do SQL Server. É recomendado que você use os novos tipos de dados : varchar(MAX), nvarchar(MAX) e  varbinary(MAX)

Observando a tabela vemos que o tipo de dados  varbinary(MAX) é o que permite tratar com imagens ou Large Binary Data.

BLOB varbinary(MAX) 
Image(*)
2.147.483.647
CLOB varchar(MAX)
Text(*)
2.147.483.647
CLOB - Unicode nvarchar(MAX)
NText(*)
1.073.741.823
dados XML xml 2.147.483.647

Neste artigo eu procuro mostrar como salvar e recuperar imagens em um banco de dados SQL Server usando o Entity Framework em um projeto ASP .NET Web Forms.

Recursos usados:

Definindo o modelo de dados

Vamos criar uma tabela chamada MinhasFotos no banco de dados Cadastro.mdf com a seguinte estrutura:

Observe que o campo Foto é do tipo varbinary(MAX) e irá armazenar as imagens que iremos salvar e recuperar do banco de dados.

Criando o projeto no Visual Studio 2013 Express for web

Abra o VS 2013 Express for web e clique em New Project;

Selecione a linguagem Visual C# e o template ASP .NET Web Application;

Informe o nome EF_SalvarImagem_BD e clique no botão OK;

A  seguir selecione o template Empty e marque a opção Web Forms pois vamos criar um projeto vazio :

Vamos incluir uma nova página em nosso projeto. Para isso clique no menu PROJECT ->Add New Item e selecione o template Web -> Web Form e informe o nome Default.aspx e clique no botão Add;

Vamos criar um Entity Data Model no projeto Console. Selecione o projeto e Clique em  PROJECT -> Add New Item;

Selecione a guia Data e o template ADO .NET Entity Data Model, informe o nome MinhasFotos e clique no botão Add;    

No assistente selecione a opção EF Designer from database e clique no botão Next>;

Selecione a conexão com o banco de dados Cadastro.mdf (Se ele ainda não existir clique em New Connection e defina a conexão);

Aceite as configurações do assistente que salva a string de conexão no arquivo App.Config e cria o contexto CadastroEntities;

Clique no botão Next>;

Selecione a opção Entity Framework 6.x e clique no botão Next>;

A seguir selecione as tabelas do banco de dados e marque as opções conforme a figura abaixo clicando no botão Finish para concluir essa etapa:

Definindo o leiaute da página Default.aspx

Agora abra a página Default.aspx no modo Source e a partir da ToolBox inclua os seguintes controles:

Disponha os controles conforme o leiaute da figura abaixo:

Agora vamos ao código definido no code-behind.

No evento Click do botão de comando Incluir Foto temos o código abaixo:

protected void btnIncluiImagem_Click(object sender, EventArgs e)
{
            if (fup1.HasFile)
            {
                try
                {
                    string filename = fup1.PostedFile.FileName;
                    int tamanho = fup1.PostedFile.ContentLength;
                    Stream arquivoStream = fup1.PostedFile.InputStream;
                    if (SalvarImagem(arquivoStream, filename, tamanho))
                    {
                        lblStatus.Text += "Imagem salva com sucesso no banco de dados";
                    }
                    else
                    {
                        lblStatus.Text += "FALHA ao salvar a imagem no Banco de dados";
                    }
                }
                catch (Exception ex)
                {
                    lblStatus.Text = " Erro " + ex.Message;
                }
            }
}

Este código verifica se um arquivo de imagem foi selecionado e enviado usando o controle FileUpload (fup1), e obtém o nome do arquivo , seu tamanho e gera um Stream com a imagem selecionada.

A seguir usamos o método SalvarImagem() passando , o stream, o nome do arquivo e seu tamanho.

O código do método SalvarImagem() é visto a seguir:

      private bool SalvarImagem(Stream arquivoStream, string filename, int tamanho)
        {
            bool ret = false;
            try
            {
                byte[] documentBytes = new byte[arquivoStream.Length];
                arquivoStream.Read(documentBytes, 0, documentBytes.Length);
                MinhaFoto foto = new MinhaFoto()
                {
                    Nome = filename,
                    Descricao = txtDescricao.Text,
                    Foto = documentBytes,
                    Tamanho = tamanho
                };
                using (CadastroEntities ctx = new CadastroEntities())
                {
                    ctx.MinhasFotos.Add(foto);
                    ctx.SaveChanges();
                    ret = true;
                }
            }
            catch (Exception ex)
            {
                lblStatus.Text = " Erro : " + ex.Message;
            }
           return ret;
     }   

O código acima cria um array de bytes a partir do stream do arquivo imagem , lê esses bytes e cria um instância da entidade MinhaFoto atribuindo os valores para a imagem definidos na página ASP .NET.

A seguir criamos uma instância do contexto (CadastroEntitites), adicionamos a entidade no contexto e persistimos as informações usando o método SaveChanges() do contexto.

Para exibir os dados gravados na tabela usando o evento Click do botão Exibir Dados com o código abaixo:

 protected void btnExibirDados_Click(object sender, EventArgs e)
        {
            try
            {
                using (CadastroEntities ctx = new CadastroEntities())
                {
                    gdvFotos.DataSource = from reg in ctx.MinhasFotos.ToList() select reg;
                    gdvFotos.DataBind();
                }
            }
            catch(Exception ex)
            {
                lblStatus.Text = " Erro : " + ex.Message;
            }
        }

 

O código acima apenas cria uma instância do contexto e realiza uma consulta  retornando as informações e atribuindo ao controle DataGridView (gdvFotos).

Para exibir uma foto selecionada no controle DataGridView usamos o código abaixo no evento Click do botão Exibir Foto :

  protected void btnExibirFoto_Click(object sender, System.EventArgs e)
  {
            try
            {
                int codigo = Convert.ToInt32(gdvFotos.SelectedRow.Cells[1].Text);
                byte[] bytes = (byte[])carregaImagem(codigo);
                string base64String = Convert.ToBase64String(bytes, 0, bytes.Length);
                imgFoto.ImageUrl = "data:image/png;base64," + base64String;
            }
            catch(Exception ex)
            {
                lblStatus.Text = " Erro " + ex.Message;
            }
   }

Neste código obtemos o código da imagem selecionada no DataGridView e usando o método CarregaImagem() passamos esse código e retornamos um array de bytes que é convertido para String e exibido em um controle Image.

O código da rotina carregaImagem() é vista a seguir:

 private byte[] carregaImagem(int id)
  {   
            try
            {
                byte[] fileBytes = null;
                using (CadastroEntities ctx = new CadastroEntities())
                {   
                    var dbInfo = ctx.MinhasFotos.FirstOrDefault(doc => doc.Id == id);
                    if (dbInfo != null)
                    {
                        fileBytes = dbInfo.Foto;
                    }
                }
                return fileBytes;
            }           
            catch(Exception ex)
            {
                throw ex;
            }
 }

Este código recupera a imagem armazenada realizando uma consulta LINQ com uma expressão lambda e retorna um array de bytes da imagem armazenada.

Executando o projeto, salvando algumas imagens e selecionando uma imagem para recuperar e exibir iremos obter o seguinte resultado:

Pegue o projeto completo aqui:  EF_SalvarImage_BD.zip (sem as referências)

Porque os judeus pedem sinal, e os gregos buscam sabedoria;
Mas nós pregamos a Cristo crucificado, que é escândalo para os judeus, e loucura para os gregos.
Mas para os que são chamados, tanto judeus como gregos, lhes pregamos a Cristo, poder de Deus, e sabedoria de Deus.

1 Coríntios 1:22-24

Veja os Destaques e novidades do SUPER DVD Visual Basic (sempre atualizado) : clique e confira !

Quer migrar para o VB .NET ?

Quer aprender C# ??

Quer aprender os conceitos da Programação Orientada a objetos ?

Quer aprender o gerar relatórios com o ReportViewer no VS 2013 ?

  Gostou ?   Compartilhe no Facebook   Compartilhe no Twitter

Referências:


José Carlos Macoratti