Desenvolvimento - ADO.NET
Acesso a dados em aplicações ASP.NET – Conceitos básicos – parte 3
Este artigo mostra o que são os controles do tipo Data Source, como utilizá-los para acesso a dados em aplicações ASP.NET, suas vantagens e desvantagens.
por Ricardo OnedaControles Data Source
Os controles
Data Source do ASP.NET 2.0 não geram
nenhuma saída HTML na página, mas através deles é possível especificar informações
sobre a conexão com a fonte de dados, comandos para incluir, excluir, modificar
e consultar dados, parâmetros, entre outras configurações, tudo de forma declarativa,
como fazemos com qualquer outro controle do ASP.NET. Controles de vinculção de dados,
como o GridView ou o
FormView, podem então utilizar os serviços oferecidos pelo
Data Source para manipular os dados. Estão disponíveis os seguintes
tipos de controles Data Source:
·
SqlDataSource: fornece acesso a fontes de dados
que possuam um Data Provider no ADO.NET.
Apesar do nome, o acesso
não é limitado ao SQL Server da Microsoft. Podemos acessar outros bancos de dados,
como Oracle, ou qualquer um que tenha suporte a OLE DB ou ODBC.
· AccessDataSource: permite o acesso a banco de dados Access.
· ObjectDataSource: através dele podemos utilizar classes personalizadas como fonte de dados, como as da camada de acesso a dados ou de componentes de negócio. Este tipo de Data Source permite maior grau de personalização, mas em contrapartida, exige escrita de código, já que o acesso será feito por meio de objetos específicos.
· SiteMapDataSource: utilizado na navegação de sites ASP.NET
· XmlDataSource: permite o acesso a arquivos e documentos XML
Em nosso próximo exemplo, iremos aprender como utilizar o
SqlDataSource para vincular os dados a um
GridView. Permitiremos que o usuário filtre os produtos com preço maior
que um valor fornecido por ele. Além disso, também iremos explorar algumas características
mais avançadas do GridView. No
Solution Explorer, clique com o botão direito do mouse sobre o projeto
BancoDados e escolha a opção Add New Item.
Na janela que se abre, escolha o template Web
Form, nomeie-o GridViewDataSource.aspx
e escolha a linguagem Visual C#. Visualize
a página no modo Design. Adicione um
controle Label, um
TextBox e um Button. Altere a
propriedade Text do
Label para “Produtos com preço maior que:”.
Configure a propriedade Text do
Button para “Pesquisar”. Altere
também a propriedade ID do
TextBox para txtPreco.
Vá ao Toolbox e, na guia
Data, selecione o SqlDataSource,
arrastando-o sobre a página. Os controles Data
Source são representados como uma caixa cinza no Visual Studio. Como dito
anteriormente, esse controle não irá gerar nenhuma tag HTML quando a página for
processada. Na smart tag do SqlDataSource,
acessível pela pequena seta no canto superior direito do controle, clique no link
Configure Data Source, como mostrado
na figura 18. Isso irá iniciar o wizard de configuração do
Data Source. Na primeira tela do wizard, devemos escolher ou criar a conexão
que o Data Source irá utilizar. Nesse
caso, vamos reaproveitar a conexão NorthwindConnectionString
que já havíamos criado anteriormente e clicar em
Next.
Figura 1 - Smart tag do SqlDataSource
Na próxima tela do wizard, somos questionados sobre os dados com os quais o Data Source irá trabalhar. Podemos especificar uma cláusula SQL, através da opção Specify a custom SQL statement or stored procedure, ou então definirmos graficamente os campos que serão retornados de uma tabela ou view, através da opção Specify columns from a table or view. Como nesse exemplo utilizaremos dados de três tabelas, escolha a primeira opção e clique em Next. Na tela seguinte, devemos especificar os comandos SQL relativos às operações de SELECT, UPDATE, INSERT e DELETE. Utilize os comandos abaixo. A tela deverá se parecer com a figura 19.
SELECT Products.ProductID, Products.ProductName, Products.SupplierID, Suppliers.CompanyName, Products.CategoryID, Categories.CategoryName, Products.QuantityPerUnit, Products.UnitPrice, Products.UnitsInStock, Products.UnitsOnOrder, Products.ReorderLevel, Products.Discontinued
FROM Products INNER JOIN Suppliers ON Products.SupplierID = Suppliers.SupplierID INNER JOIN Categories ON Products.CategoryID = Categories.CategoryID
WHERE Products.UnitPrice > @Preco
ORDER BY Products.ProductName
UPDATE [Products] SET [ProductName] = @ProductName, [SupplierID] = @SupplierID, [CategoryID] = @CategoryID, [QuantityPerUnit] = @QuantityPerUnit, [UnitPrice] = @UnitPrice, [UnitsInStock] = @UnitsInStock, [UnitsOnOrder] = @UnitsOnOrder, [ReorderLevel] = @ReorderLevel, [Discontinued] = @Discontinued
WHERE [ProductID] = @ProductID
INSERT INTO [Products] ([ProductName], [SupplierID], [CategoryID], [QuantityPerUnit], [UnitPrice], [UnitsInStock], [UnitsOnOrder], [ReorderLevel], [Discontinued]) VALUES (@ProductName, @SupplierID, @CategoryID, @QuantityPerUnit, @UnitPrice, @UnitsInStock, @UnitsOnOrder, @ReorderLevel, @Discontinued)
DELETE FROM [Products] WHERE [ProductID] = @ProductID
Figura 2 - Configurando as queries do Data Source
Se houvéssemos escolhido a segunda opção na tela anterior, ou seja, se utilizássemos dados de uma única tabela, os comandos Transact SQL relativos às operações de INSERT, UPDATE e DELETE seriam gerados automaticamente pelo wizard, desde que optássemos por essa geração através do botão Advanced. Para que a geração automática dos comandos funcionasse corretamente, também seria necessário que a tabela em questão possuísse uma chave primária.
Ao clicarmos em Next, o wizard detecta que a query SELECT possui um parâmetro - @Preco, e permite-nos especificar qual a origem do valor deste parâmetro. Podemos obter o valor do parâmetro de várias origens, listadas no campo Parameter source, como cookies, controles da página, de parâmetros passados via QueryString, ou ainda de variáveis de sessão. Neste caso, obteremos o valor do parâmetro do controle TextBox txtPreco. Portanto, configure a origem do valor do parâmetro para Control e, em ControlID, selecione o controle txtPreco. Nesta tela, também podemos escolher qual o valor padrão do parâmetro, quando nada for especificado, através do campo Default Value. Coloque 0 para que, caso nenhum preço seja informado, todos os produtos com preço maior que 0 sejam retornados pela query.
Figura 3 - Definindo a origem do parâmetro
Após clicar no botão Next, podemos testar a query clicando em Test Query. Para finalizar, clique em Finish. Após o término do wizard, aparentemente nada mudou. Entretanto, se clicarmos no botão Source da página para acessarmos a parte HTML da mesma, veremos que vários parâmetros de configuração do Data Source foram adicionados, entre eles os comandos SQL SELECT, INSERT, DELETE e UPDATE, com os respectivos parâmetros. Note que os parâmetros foram deduzidos a partir das queries que informamos. Para finalizar a configuração do Data Source, selecione-o e, na janela de propriedades, altere o ID para dsProdutos. Outras duas propriedades do SqlDataSource merecem destaque: a propriedade ProviderName, através da qual é possível escolher qual Data Provider do ADO.NET vamos utilizar, e a DataSourceMode, que permite escolher se o Data Source irá retornar um DataSet ou um DataReader. Nesse caso, vamos trabalhar com os valores padrões destas propriedades, ou seja, utilizar o SqlClient Data Provider, já que estamos acessando um banco de dados SQL Server, retornando um DataSet, pois como veremos adiante, utilizaremos funcionalidades de paginação e ordenação do GridView, somente disponívies para uso com DataSet.
Arraste um controle GridView para a página e altere sua propriedade ID para gvProdutos. Através da smart tag do GridView, na opção Choose Data Source, escolha dsProtutos como a fonte de dados. Perceba que, mesmo em tempo de desenvolvimento, o GridView cria, automaticamente, colunas baseadas nos campos que o Data Source retorna, exibindo-as no editor do Visual Studio. Acesse novamente a smart tag do GridView e note que agora estão disponívies outras opções, como as que permitem paginação (Enable Paging), ordenação (Enable Sorting), edição (Enable Editing), exclusão (Enable Deleting) e seleção (Enable Selection). Isso só ficou disponível após a escolha do Data Source, pois o GridView detectou que essas operações seriam possíveis de acordo com o que havíamos configurado na fonte de dados. Selecione as opções Enable Paging, Enable Sorting, Enable Editing e Enable Deleting. No Solution Explorer, clique com o botão direito do mouse sobre a página GridViewDataSource.aspx e escolha a opção View in Browser. Veja que o GridView é montado, permitindo que seja ordenado por qualquer uma de suas colunas, além de podermos editar qualquer registro ou excluí-lo. Além disso, são exibidos no máximo 10 registros por página. Esse número pode ser configurado através da propriedade PageSize do GridView. Experimente digitar algum valor na caixa de texto de preço e clicar em Pesquisar. Serão mostrados somente os produtos que tenham preço maior que o valor informado. Tudo isso, sem escrever uma única linha de código e somente utilizando os recursos disponíveis no ambiente.
Podemos melhorar ainda mais nosso exemplo. Vamos começar pela aparência do GridView. Até o momento, estamos utilizando sua aparência padrão, que não é das mais atraentes. Temos duas alternativas para melhorar a aparência do GridView: a primeira é configurar as várias propriedades de estilo do controle, acessíveis através da janela de propriedades, como HeaderStyle, que se aplica ao cabeçalho, FooterStyle, relativo ao rodapé, RowStyle e AlternatingRowStyle, relacionadas às linhas dos registros. A outra alternativa é utilizar um dos formatos pré-definidos do GridView. Para utilizar essa segunda opção, na smart tag do GridView, selecione a opção Auto Format e escolha o formato que mais lhe agrada. Aqui foi escolhido o formato Professional.
Vamos agora configurar a coluna UnitPrice para que seu conteúdo seja exibido com o formato monetário. Para isso, acesse a opção Edit Columns na smart tag. Na tela que é aberta, podemos editar o formato dos vários campos que são exibidos no GridView. No canto inferior esquerdo da tela, em Selected Fields , selecione o campo UnitPrice. Na propriedade DataFormatString desse campo, digite {0:c} para que seja utilizado o formato monetário. Dentro da categoria ItemStyle, configure a propriedade HorizontalAlign para Right, assim o conteúdo do campo ficará alinhado à direita. Além disso, na propriedade HeaderText, vamos colocar um nome mais amigável para o cabeçalho da coluna, como por exemplo, “Preço Unitário”. Para completar, configure a propriedade HtmlEncode como False, para que a formatação seja feita.
Ainda na tela de edição de campos do GridView, selecione o campo CommandField. Este é o campo que contém os links para edição e exclusão dos registros. Nele podemos configurar textos mais amigáveis para esses links. Como os textos padrão estão em inglês, vamos configurá-los para palavras em português. Na propriedade CancelText, escreva Cancelar, em DeleteText, digite Excluir, em EditText, coloque Alterar e em UpdateText, Salvar. Altere a propriedade HeaderText dos demais campos para nomes mais intuitivos e clique em OK.
Se você executar a aplicação, perceberá que a página está bem mais apresentável, com textos mais amigáveis e formatação mais coerente. Clique no link Alterar de algum registro e note que os campos entram em modo de edição. Perceba que o campo ProductID não permite alteração. Isso acontece porque ele está definido como chave primária na tabela Products. Assim, o GridView configura a propriedade ReadOnly deste campo como True, ou seja, ele torna-se somente leitura. Veja também os campos SupplierID e CategoryID: eles são chaves das tabelas Suppliers e Categories, que indicam o fornecedor e a categoria do produto, respectivamente. Do jeito que está sendo apresentado, é difícil para o usuário saber qual o ID do fornecedor ou da categoria a qual o produto pertence. Essa é uma informação do sistema, utilizada para manter o relacionamento entre as tabelas, mas que não faz sentido do ponto de vista do usuário. Além disso, as colunas com os nomes dos fornecedores e das categorias devem ser limitadas a um conjunto pré-definido de valores. É muito mais interessante que o usuário possa escolher o fornecedor ou a categoria a partir de uma lista de nomes, ao invés de deixarmos que ele digite qualquer texto. Para isso, o primeiro passo é adicionarmos mais dois SqlDataSources, que serão responsáveis por retornar as listas de categorias e fornecedores diponíveis. Nomeie estes controles como dsCategorias e dsFornecedores, respectivamente. Altere a propriedade DataSourceMode para DataReader, já que neste caso só disponibilizaremos a lista para o usuário escolher um dos possíveis valores. Através da smart tag, configure os novos Data Sources, como foi feito no exemplo anterior, mas, neste caso, escolha a opção Specify columns from a table or view, já que utilizaremos dados de uma única tabela em cada SqlDataSource. Utilize as seguintes querys:
SELECT [CategoryID], [CategoryName] FROM [Categories] ORDER BY [CategoryName]
SELECT [SupplierID], [CompanyName] FROM [Suppliers] ORDER BY [CompanyName]
No GridView, vamos ocultar as colunas ProductID, SupplierID e CategoryID e transformar as colunas relativas aos campos CompanyName e CategoryName em TemplateFields, que são um tipo de campo especial que permite personalização. Acesse a smart tag do GridView e escolha a opção Edit Columns. Em Selected fields, selecione o campo ProductID e configure a propriedade Visible para False. Faça o mesmo procedimento para os campos SupplierID e CategoryID. Agora, selecione o campo relativo a CompanyName/Fornecedor e clique no link Convert this field into a TemplateField. Faça o mesmo com o campo CategoryName/Categoria e clique no botão OK. Acesse novamente a smart tag do GridView e escolha a opção Edit Templates. O editor do Visual Studio é alterado para o modo de edição de templates. Através da smart tag, podemos escolher qual template vamos customizar. Como queremos personalizar a interface de edição, selecione o template EditItemTemplate, da coluna Fornecedor, como mostrado na figura 20.
Figura 4 - Editando um campo do tipo TemplateField
Por padrão, a edição deste campo é feita através de um controle do tipo TextBox, que é apresentado quando escolhemos o template EditItemTemplate. Apague o TextBox e adicione em seu lugar um controle do tipo DropDownList. Abra a smart tag do DropDownList e escolha a opção Choose Data Source. Como fonte de dados, escolha o Data Source dsForncedores. Em Select a data field to display in the DropDownList, devemos escolher o campo do Data Source cujo valor será mostrado na página. Neste caso, escolha o campo CompanyName. Na última opção, Select a data field for the value of the DropDownList, definimos qual é o campo que será utilizado para recuperar o valor da opção escolhida na lista. Aqui escolhemos SupplierID. Ainda na smart tag do DropDownList, acesse a opção Edit DataBindings. Na janela que se abre, devemos escolher a qual campo do DataSource a propriedade SelectedValue do DropDownList estará vinculada. Em Bound to, escolha o campo SupplierID e clique no botão OK. Para personalizar o template de edição da coluna Categorias, acesse o respectivo EditItemTemplate e repita a operação, escolhendo o Data Source dsCategorias para o novo DropDownList, e os campos CategoyName e CategoryID. Acesse Edit DataBindings na smart tag e associe a propriedade SelectedValue ao campo CategoryID, clicando o botão OK em seguida. Para finalizar a edição dos templates, clique em End Template Editing na smart tag.
Execute a aplicação e clique no link Alterar. Veja que agora, no modo de edição do GridView, os campos SupplierID e CategoryID aparecem com o controle DropDownList, tornando a interface bem mais amigável que a versão anterior. Além disso, os campos ProductID, SupplierID e CategoryID não são mais exibidos.
Figura 5 - Controle DropDownList dentro de um GridView
Para concluir nosso exemplo, vamos desenvolver a interface para inclusão de novos produtos. O controle GridView não oferece suporte para inclusão de registros. Para essa finalidade, iremos utilizar o controle DetailsView. Esse novo controle do ASP.NET 2.0 apresenta os dados de um único registro por vez e também possui várias funcionalidades, como navegação entre registros, inclusão, exclusão e atualização dos mesmos. Neste caso, iremos somente utilizar a função de inclusão, pois as demais operações já são feitas pelo GridView.
Também iremos utilizar o novo controle MultiView, que por sua vez contém controles do tipo View. Esses controles permitem gerenciar partes da página que devem ser mostradas ou não, fornecendo visões diferentes para a mesma página de acordo com o contexto. A idéia é que a página tenha duas Views (ou visões): uma com o GridView gvProdutos e outra com o DetailsView, responsável pela inclusão de novos produtos. Enquanto uma estiver sendo exibida, a outra ficará oculta.
Na página GridViewDataSource.aspx, adicione um controle do tipo MultiView e, dentro dele, adicione dois controles View. Configure a propriedade ActiveViewIndex do MultiView para 0. Essa propriedade indica qual a View ativa, que neste caso, é a primeira View (aqui o número 0 representa o primeiro elemento). Arraste o GridView gvProdutos para dentro do primeiro View, chamado View1, juntamente com o Label, o TextBox txtPreco e o Button. Ainda dentro desta View, adicione um controle LinkButton e configure sua propriedade Text para “Incluir novo produto”. Na View2, adicione um controle DetailsView. Altere a propriedade ID para dvProdutos, e a propriedade DefaultMode para Insert. Assim, quando o DetailsView for mostrado, estará no modo de inclusão de registro. Através da smart tag do DetailsView, escolha o DataSource dsProdutos. Ainda na smart tag, selecione a opção Enable Inserting, para que a inclusão de registros seja permitida. A página, no Visual Studio 2005, deverá estar parecida com a imagem abaixo:
Figura 6 - Controles MultiView e View
Dê um duplo clique no controle LinkButton, para que sejamos levados para o evento click. Nele, adicione o código abaixo, que configura a segunda View, a que contém o DetailsView, como sendo a ativa.
protected void LinkButton1_Click(object sender, EventArgs e)
{
MultiView1.ActiveViewIndex = 1;
}
Volte para o design da página. Note que, abaixo do DetailsView dvProdutos, há dois links, Insert e Cancel, responsáveis por gravar os dados do registro no banco de dados e por cancelar a operação, respectivamente. Como no GridView, podemos personalizar esses textos, deixando-os mais amigáveis. Para isso, abra a smart tag do DetailsView e escolha a opção Edit Fields. É aberta então uma janela para edição dos campos, igual à janela Edit Columns do GridView. Em Selected Fields , selecione o campo New, Insert, Cancel, que representa os links mostrados abaixo do DetailsView. Na janela de propriedades à direita, altere as propriedades CancelText para Cancelar, e InsertText para Salvar. Também podemos configurar os títulos dos campos através da propriedade HeaderText. Faça as configurações que achar necessário.
Como no GridView, os campos Forncedor e Categoria são representados como controles TextBox. Para que sejam mostrados controles do tipo DropDownList, podemos fazer a mesma operação feita no GridView, ou seja, transformar esses campos em TemplateFields. A partir daqui, a operação é muito semelhante a que foi feita no GridView. Selecione os campos e, para cada um deles, clique no link Convert this field into a TemplateField. Além disso, vamos aproveitar para ocultar os campos ProdutctID, CategoryID e SupplierID, configurando a propriedade Visible deles para False. Volte para a smart tag do DetailsView e escolha a opção Edit Templates. Na smart tag, escolha InsertItemTemplate do campo Fornecedor. Este é o template que será utilizado quando o DetailsView for exibido em modo de inclusão de dados. Apague o TextBox e adicione um DropDownList, cujo DataSource deve ser configurado para dsFornecedores. Em Select a data field to display in the DropDownList, escolha o campo CompanyName. Na última opção, Select a data field for the value of the DropDownList, escolha SupplierID. Acesse a smart tag do DropDownList e escolha a opção Edit DataBindings. Na janela que se abre, devemos escolher a qual campo do DataSource a propriedade SelectedValue do DropDownList estará vinculada. Em Bound to, escolha o campo SupplierID e clique no botão OK. Agora, acesse o InsertItemTemplate do campo CategoryID e repita a operação, escolhendo o Data Source dsCategorias para o novo DropDownList, e os campos CategoyName e CategoryID. Na smart tag do DropDownList escolha a opção Edit DataBindings e em Bound to, escolha o campo CategoryID. Para finalizar a edição dos templates, clique em End Template Editing na smart tag da edição de templates.
Figura 7 - Configurando o DataBinding de um campo
Para dar um aspecto mais profissional ao DetailsView, vá para a opção Auto Format do DetailsView, acessível através da smart tag, e escolha um dos formatos disponíveis. Por fim, selecione o DetailsView e acesse a janela de propriedades. Em seguida, clique no ícone com o símbolo de um raio, para que seja exibida a lista dos eventos deste controle. Dê um duplo clique no evento ItemInserted. Este evento é chamado sempre que um novo registro é inserido. No momento em que isto acontecer, mudaremos a View ativa para a View1, ou seja, o GridView é novamente exibido.
protected void dvProdutos_ItemInserted(object sender, DetailsViewInsertedEventArgs e)
{
MultiView1.ActiveViewIndex = 0;
}
Volte para a janela de propriedades do DetailsView e dê um duplo clique no evento ItemCommand. Este é o evento disparado quando se clica no link Cancelar do DetailsView. Nele iremos escrever o mesmo código do evento ItemInserted, responsável por ativar a View que contém o GridView:
protected void dvProdutos_ItemCommand(object sender, DetailsViewCommandEventArgs e)
{
MultiView1.ActiveViewIndex = 0;
}
Execute a aplicação e clique no link Incluir novo produto. Nesse momento, a View que contém o DetailsView torna-se ativa, permitindo que possamos incluir um novo produto. Note que os campos Fornecedor e Categoria são exibidos como uma lista de nomes na qual podemos selecionar o fornecedor e a categoria, sem a necessidade de digitarmos os códigos que os representam. Forneça alguns dados fictícios e clique em Salvar. Nesse instante, as informações são salvas no banco de dados e a View que contém o GridView torna-se ativa novamente. Perceba que o novo produto já aparece no GridView.
Figura 8 - Controle DetailsView em modo de inclusão de dados
Conclusão
Como vimos, o uso do SqlDataSource nos permite criar aplicações sem a necessidade de escrever código para acessar o banco de dados. Os objetos do ADO.NET, como Connection, Command, DataAdapter, DataSet e DataReader continuam sendo usados, nos bastidores, através do controle Data Source, que é o responsável por criar e utilizar estes objetos automaticamente, de acordo com as configurações que fizemos. Apesar do ganho de produtividade, o uso do SqlDataSource traz algumas desvantagens. A primeira é que os comandos Transact SQL ficam armazenados no controle, que por sua vez, está na página. Em uma aplicação que utiliza o conceito de camadas, isso pode ser ruim, pois estaríamos misturando a camada de apresentação com a de acesso a dados. Outra desvantagem é que cada página utiliza seus próprios componentes SqlDataSource, o que dificulta o reaproveitamento de código e a manutenção. Para contornar esses problemas, pode-se utilizar o ObjectDataSource, que permite o uso de classes personalizadas para acesso a dados. Assim, desenvolvemos as classes necessárias para acesso a dados e as utilizamos para vincular os dados aos controles. Apesar dessa flexibilidade, o uso do ObjectDataSource exige que código seja escrito. Cabe ao desenvolvedor avaliar a relação custo/benefício de cada solução e escolher a abordagem que melhor atenda aos requisitos.