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

Anúncios

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.