Desenvolvimento - ADO.NET
Acesso a dados em aplicações ASP.NET – Conceitos básicos – parte 2
Neste artigo serão mostrados alguns conceitos básicos do ADO.NET, como os Data Providers, os modelos conectado e desconectado, DataSet tipado e TableAdapter.
por Ricardo OnedaNa primeira parte do artigo, o ambiente de desenvolvimento foi montado com a instalação e configuração do banco de dados de exemplo NorthWind. Também vimos como podemos acessar o banco de dados através da IDE do Visual Studio 2005. Agora, serão mostrados alguns conceitos básicos do ADO.NET, como os Data Providers, os modelos conectado e desconectado, DataSet tipado e TableAdapter.
ADO.NET
Data Providers
O ADO.NET é a tecnologia de acesso a dados do .NET Framework. Ele utiliza o conceito de Data Provider, que pode ser definido como um conjunto de classes que funciona como uma camada entre a aplicação e a fonte de dados, e é responsável por se conectar a ela, executar os comandos e obter os resultados. O ADO.NET 2.0 possui os seguintes Data Providers nativos:
· SQL Server Data Provider: fornece acesso à bancos de dados SQL Server a partir da versão 7. As classes desse provider encontram-se no namespace System.Data.SqlClient.
· Oracle Data Provider: para ser utilizado no acesso a bancos de dados Oracle. Localiza-se no namespace System.Data.OracleClient.
· OLE DB Data Provider: provider para fontes de dados OLE DB. Deve ser utilizado também no acesso a banco de dados SQL Server anteriores à versão 7. As classes podem ser encontradas em System.Data.OleDb.
·
ODBC Data Provider: fornece acesso a dados que suportem
o padrão ODBC. Utiliza o namespace System.Data.Odbc.
·
Connection: responsável por estabelecer
a conexão com a fonte de dados.
· Command: executa um determinado comando na fonte de dados.
· DataReader: fornece acesso seqüencial somente para frente (forward-only) e somente leitura a um conjunto de dados retornado.
·
DataAdapter: funciona como uma ponte entre
a fonte de dados e o objeto DataSet,
que será explicado na seção sobre modelo desconectado de acesso a dados.
Em nosso próximo exemplo, o
que iremos fazer, basicamente, é estabelecer uma conexão com o banco de dados Northwind que anexamos no
SQL Server 2005 Express
na primeira parte do artigo, executar um comando que retorne o conteúdo
da tabela Categories e exibir esses registros
em um controle DropDownList na nossa
página ASP.NET.
Modelo Conectado
Na janela
Solution Explorer do Visual Studio 2005,
clique com o botão direito do mouse sobre a página
Default.aspx do Web Site BancoDados,
e escolha a opção View Designer para
abrir o modo de design da página. Abra a janela
Toolbox através do menu View > Toolbox,
ou pelo atalho Ctrl + Alt + X, e arraste
um controle DropDownList para a página.
Selecione o controle e abra a janela de propriedades através do menu
View > Properties Window, ou pressionando a tecla
F4. Altere a propriedade ID
do DropDownList para
ddlCategorias. Dê um duplo clique em uma área livre da página para abrir
o editor de código. Primeiro, no início do arquivo, vamos declarar o namespace do
Data Provider que pretendemos utilizar:
using System.Data.SqlClient;
No evento
Page_Load, adicione o código abaixo. Nele, definimos um objeto do tipo
SqlConnection, passando como parâmetro a string de conexão com o banco
de dados. A string de conexão é um conjunto de propriedades e seus respectivos valores,
necessária para se estabelecer uma conexão com uma fonte de dados. Em nosso caso,
iremos utilizar três propriedades na string de conexão:
·
Data Source: indica o servidor ao qual a
aplicação irá se conectar
· Initial Catalog: o nome do banco de dados que iremos acessar
· Integrated Security: utiliza a autenticação integrada do Windows para se conectar ao servidor. Esse tipo de autenticação é considerado mais seguro, porque não é necessário passar um usuário e sua respectiva senha para se conseguir a conexão, já que é utilizado o contexto de segurança da conta de usuário que está executando o processo do ASP.NET. Isso funciona bem quando utilizamos o servidor web do Visual Studio 2005 na fase de desenvolvimento, porque o usuário utilizado para a autenticação é o que está logado no momento em que a aplicação é executada e, geralmente, ele tem as permissões necessárias para acesso ao banco de dados. Entretanto, pode haver problemas quando utilizarmos o IIS como servidor web, pois nesse caso, o usuário utilizado para executar o processo do ASP.NET tem menos privilégios. Para resolver esse problema, deve-se dar acesso ao banco de dados para esse usuário, ou então utilizar a autenticação do SQL Server. Neste caso, cria-se um usuário e senha no banco de dados, que devem ser passados na string de conexão, através dos atributos Uid e pwd, respectivamente.
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
SqlConnection conn = new SqlConnection(@"Data Source=.\SQLEXPRESS;Initial Catalog=Northwind;Integrated Security=True");
SqlCommand cmd = new SqlCommand("SELECT CategoryID, CategoryName FROM Categories ORDER BY CategoryName", conn);
SqlDataReader dr;
conn.Open();
dr = cmd.ExecuteReader();
this.ddlCategorias.DataSource = dr;
this.ddlCategorias.DataValueField = "CategoryID";
this.ddlCategorias.DataTextField = "CategoryName";
ddlCategorias.DataBind();
dr.Close();
conn.Close();
}
}
Em seguida,
definimos um objeto SqlCommand, contendo
a cláusula SQL SELECT que retorna os campos CategoyID
e CategoryName da tabela
Categories, ordenados por CategoryName,
e associamos este comando ao objeto de conexão instanciado anteriormente. Declaramos
então um objeto do tipo SqlDataReader
e logo em seguida abrimos a conexão com o banco de dados através da chamada do método
Open() do objeto de conexão. Através
do método ExecuteReader() do objeto SqlCommand, o comando é então executado
e associamos o seu retorno ao objeto SqlDataReader
criado anteriormente. O DataReader retorna
dados somente para leitura e de acesso seqüencial somente para frente, portanto,
é indicado quando queremos retornar dados que não vão sofrer alterações, como em
uma simples consulta, e nos quais não desejamos navegar em várias direções. Devido
a estas características, o uso de DataReader
aumenta a performance da aplicação. Além do método
ExecuteReader(), o objeto Command
possui alguns outros métodos que merecem ser citados:
·
ExecuteNonQuery(): executa uma instrução SQL que não retorna dados, como por exemplo,
um INSERT ou UPDATE
·
ExecuteScalar(): ideal para ser utilizado quando a query retorna uma única linha
com uma única coluna, ou seja, um campo único
Figura 1 - Categorias do Northwind
Quando utilizamos o DataReader para obter os dados, estamos utilizando o chamado modelo conectado de acesso a dados. Ele recebe esse nome porque é necessário manter uma conexão com o banco de dados aberta enquanto os registros retornados pela query são manipulados. Veja no código acima que a conexão só é fechada após os dados retornados pelo DataReader serem vinculados ao DropDownList, processo este que recebe o nome de DataBinding.
Modelo Desconectado
Conexões
com banco de dados são um recurso escasso. O ideal é mantê-las abertas durante o
menor tempo possível. Como foi visto, no modelo conectado, a conexão precisa estar
aberta enquanto a aplicação acessa os dados. Isso pode ser ruim, principalmente
em aplicações que precisam de alta disponibilidade e escalabilidade, pois a conexão
pode ficar aberta por um grande período de tempo, enquanto que outros usuários aguardam
por uma nova conexão. Para resolver problemas deste tipo, além do modelo conectado,
o ADO.NET também oferece um outro modelo de acesso a dados, chamado de modelo desconectado.
Neste modelo, após a conexão ser aberta, os dados são copiados para um objeto do
tipo DataSe através de um
DataAdapter, e logo em seguida a conexão é fechada. Com os dados armazenados
no DataSet, eles podem então ser manipulados
e, quando for o momento certo, são atualizados na fonte de dados, novamente através
do DataAdapter, seguindo o mesmo princípio
de manter a conexão aberta somente durante um período mínimo de tempo.
em memória. Assim
como um banco de dados, ele é formado por um conjunto de tabelas (representadas
por uma coleção de objetos DataTable),
que por sua vez são constituídas por linhas (coleção de objetos
DataRow) e colunas (coleção de objetos DataColumn).
As tabelas podem se relacionar umas com as outras, através de objetos
DataRelation. Outra característica importante do
DataSet é que ele é independente da fonte de dados. Ao contrário dos
objetos Command,
Connection, DataReader e
DataAdapter, cujas classes são específicas para cada
Data Provider, a classe DataSet
é a mesma para qualquer tipo de fonte de dados. Isso permite que tenhamos em um
mesmo DataSet, por exemplo, dados vindos de banco de dados SQL Server, do Access
e de um arquivo XML.
Figura 2 - Selecionando o GridView
O GridView é uma evolução do controle DataGrid do ASP.NET 1.X, e é ideal para apresentação de dados no formato tabular. Altere a propriedade ID do GridView para gvProdutos. Agora, selecione o DropDownList ddlCategorias e altere a propriedade AutoPostBack para True. Essa propriedade indica se a página deve sofrer um PostBack a cada vez que o item selecionado do DropDownList for alterado. Quando isso acontece, o conteúdo do evento SelectedIndexChanged do DropDownList é executado. Para termos acesso a este evento, dê um duplo clique no DropDownList ddlCategorias. Neste evento, adicione o seguinte código:
protected void ddlCategorias_SelectedIndexChanged(object sender, EventArgs e)
{
preencheGridView(ddlCategorias.SelectedValue);
}
Altere o evento Page_Load para que ele também chame o método preencheGridView, dentro do bloco de verificação do PostBack. Esse método será o responsável por preencher o controle GridView com os produtos de determinada categoria, que é passada como parâmetro para o método. Implemente esse método na classe, conforme listagem a seguir:
protected void preencheGridView(string parCategoria)
{
SqlConnection conn = new SqlConnection(@"Data Source=.\SQLEXPRESS;Initial Catalog=Northwind;Integrated Security=True");
SqlCommand cmd = new SqlCommand("SELECT ProductName, UnitPrice, UnitsInStock FROM Products WHERE CategoryID=@Categoria", conn);
cmd.Parameters.AddWithValue("Categoria", parCategoria);
SqlDataAdapter da = new SqlDataAdapter(cmd);
DataSet dsProdutos = new DataSet();
da.Fill(dsProdutos, "Produtos");
gvProdutos.DataSource = dsProdutos.Tables["Produtos"];
gvProdutos.DataBind();
}
Nesse método, primeiro definimos um objeto do tipo SqlConnection, que recebe como parâmetro a string de conexão. Ela é a mesma que utilizamos para preencher o DropDownList na seção anterior. Depois, definimos um objeto SqlCommand, que seleciona os campos ProductName (nome do produto), UnitPrice (preço unitário) e UnitsInStock (unidades em estoque) da tabela Produtcs. Note que o comando possui uma cláusula WHERE, que é responsável por filtrar os produtos pela categoria escolhida. Neste caso, estamos filtrando os registros cujo campo CategoryID é igual a @Categoria. Mas o que vem a ser o @Categoria? Essa notação indica um parâmetro. Esta é a parte dinâmica de nosso comando Transact-SQL. É comum encontrarmos sistemas que utilizam concatenação de strings para formar o comando SQL. Considerando-se o exemplo anterior, seria equivalente a seguinte expressão:
String comando = "SELECT ProductName, UnitPrice, UnitsInStock FROM Products WHERE CategoryID=" + parCategoria;
Apesar
de códigos assim serem comuns, eles não são recomendáveis. Sempre que houver necessidade
de incluir alguma parte dinâmica em uma instrução SQL, devemos optar pelo uso de
parâmetros, fazendo uso do conceito de query parametrizada. Entre as vantagens do
uso de queries parametrizadas, podemos citar:
·
Evita
erros que podem ocorrer caso o usuário insira caracteres especiais, como o apóstrofo
(‘), que interfeririam na formação do comando.
· Torna a aplicação mais segura, pois evita ataques do tipo SQL Injection. Esse tipo de ataque consiste em algum usuário mal-intencionado manipular os valores dos campos do formulário de maneira que sejam passados comandos SQL que não deveriam ser executados em condições normais, e que comprometem a segurança da aplicação.
·
Melhora
a legibilidade do código e facilita a manutenção do mesmo. Em nosso caso, só estamos
utilizando um parâmetro, mas se a query fosse mais complexa, ao não utilizarmos
parâmetros ficaria difícil entender como a query seria montada.
Figura 3 - Vinculando DataSet com o GridView
DataSet Tipado e TableAdapter
Até agora, vimos o uso do DataSet em sua forma mais simples. Nela, por ser a mais genérica, não temos como garantir, em tempo de desenvolvimento, a estrutura (também chamada de schema) que existe no DataSet. No nosso exemplo anterior, caso desejássemos acessar a coluna UnitsInStock da primeira linha do DataTable Produtos do DataSet dsProdutos, deveríamos escrever um código semelhante ao abaixo:
dsProdutos.Tables["Produtos"].Rows[0]["UnitsInStock"]
Enquanto escrevemos o código, não temos como garantir que realmente existirá uma tabela chamada Produtos e, que nela, realmente haverá a coluna UnitsInStock. Poderíamos escrever o nome do DataTable ou da coluna de forma errada. Ou então poderíamos tentar converter o seu valor para um tipo de dado diferente do verdadeiro. Esses erros poderiam ocorrer enquanto digitássemos o código e só seriam detectados em tempo de execução. Para evitar esses tipos de problemas, podemos utilizar o conceito de DataSet Tipado, que é uma classe derivada da classe DataSet e que possui as definições necessárias para que erros como estes sejam evitados já em tempo de desenvolvimento, ou seja, a aplicação nem é compilada se ocorrerem esses erros. Assim, os nomes das tabelas e colunas tornam-se propriedades do DataSet, que passa a ser personalizado. Outra vantagem do uso de DataSet Tipado é que podemos nos beneficiar do recurso de auto-completar do Visual Studio, também conhecido como IntelliSense. Se utilizássemos DataSet Tipado, para acessar a coluna UnitsInStock da primeira linha do DataTable Produtos do DataSet dsProdutos, poderíamos escrever um código semelhante ao seguinte:
dsProdutos.Produtos[0].UnitsInStock
Esse código é bem mais legível e fácil de enteder do que o seu correspondente utilizando DataSet não-Tipado. Além disso, componentes de vinculação de dados, como o GridView, também reconhecem automaticamente quais as tabelas e campos disponíveis em um DataSet Tipado. Para criar o DataSet Tipado, vá Solution Explorer, clique com o botão direito do mouse sobre o projeto e escolha a opção Add New Item. Na janela que se abre, escolha o template DataSet e nomei-o NorthwindDataSet.xsd, conforme figura 4.
Figura 4 - Adicionando um DataSet
Ao clicarmos no botão Add, aparecerá uma janela perguntando se gostaríamos de adicioná-lo na pasta App_Code. A pasta App_Code é uma novidade do ASP.NET 2.0, sendo o local onde ficam os códigos-fontes comuns a toda aplicação. O conteúdo desta pasta é compilado automaticamente quando a aplicação é executada pela primeira vez. Responda Yes para a pergunta. Ao fazermos isso, será executado um wizard que nos guiará no processo de configuração do TableAdapter. O TableAdapter também é uma novidade do ASP.NET 2.0, e pode ser entendido como um DataAdapter utilizado por um DataSet Tipado. Ou seja, o TableAdapter seria uma espécie de DataAdapter Tipado, responsável pela comunicação entre o DataSet e a fonte de dados. Entretanto, ao contrário do DataAdapter, o TableAdapter não é uma classe nativa do .NET Framework. A classe do TableAdapter é gerada automaticamente pelo Visual Studio, e é personalizada para cada DataTable do DataSet Tipado. A primeira configuração que devemos fazer refere-se a escolha da conexão que utilizaremos. Podemos criar uma nova conexão, através do botão New Connection, ou então utilizar alguma já existente. Como já havíamos criado uma conexão com o Northwind anteriormente, vamos reaproveitá-la, como na figura 5:
Figura 5 - Escolhendo a conexão do TableAdapter
Após clicar em Next, o wizard perguntará se desejamos salvar a string de conexão com o banco de dados no arquivo de configuração web.config. Armazenar a string de conexão no web.config é uma boa idéia, pois qualquer alteração nela não implica em mudança no código-fonte, o que facilita a manutenção. Além disso, estando em um local único, ela poderá ser reaproveitada em outros pontos do programa. Aceite a sugestão de salvá-la no arquivo de configuração e clique em Next.
Figura 6 - Salvando a string de conexão no web.config
Na próxima tela do wizard, escolheremos como acessaremos os dados: através de comandos SQL ou através de StoredProcedures já existentes ou novas. Nesse caso, vamos utilizar comandos SQL, portanto, escolha a opção Use SQL statements e clique em Next.
Figura 7 - Escolhendo a forma de acesso aos dados
Informaremos na tela seguinte qual é o comando SQL que deverá ser executado pela TableAdapter. Podemos informar diretamente o comando SQL ou então utilizar o editor gráfico de queries, através do botão Query Builder. Esse editor de queries é parecido com o que vimos anteriormente. Neste caso, podemos incluir a clásula SQL diretamente, pois trata-se de um simples SELECT, conforme figura 8.
Figura 8 - Informando o comando SQL
Na tela seguinte, escolheremos os métodos que o TableAdapter terá. Há duas maneiras de se obter os dados através do TableAdapter: através do método Fill() – opção Fill a DataTable, que como o método Fill() de um DataAdapter, preenche um DataTable passado como parâmetro; e através de um método que retorna um objeto do tipo DataTable – opção Return a DataTable. Note que podemos selecionar qualquer uma das opções e ainda alterar os nomes do métodos. Vamos manter as duas opções selecionadas e, no segundo caso, nomear o método como GetCategories. Desmarque a última opção, que é utilizada quando queremos criar métodos que façam as operações de inclusão, exclusão e alteração, pois elas não serão utilizadas neste exemplo. Sua tela deverá ficar parecida com a figura 9.
Figura 9 - Escolhendo os métodos do TableAdapter
Ao clicarmos em Next, o wizard completará o processo de criação do DataSet e exibirá uma tela mostrando o sucesso da operação. Clique em Finish. Será exibida a tela do DataSet Designer, na qual veremos que no nosso DataSet Tipado foi criado o DataTable Categories, bem como o TableAdapter CategoriesTableAdapter, com os métodos que definimos no wizard. Agora, vamos criar o DataTable da tabela Produtos e seu respectivo TableAdapter. No Server Explorer, expanda a treeview do banco de dados Northwind e arraste a tabela Products para o DataSet Designer. O Visual Studio cria automaticamente um DataTable, chamado Products, e um TableAdapter, chamado ProductsTableAdapter, com os métodos Fill() e GetData(). Note também que o Visual Studio detectou um relacionamento entre a tabela Categorie e Products, representado por uma linha que une as duas tabelas. Podemos configurar esses elementos se clicarmos com o botão direito do mouse TableAdapter e escolhermos a opção Configure. Para o nosso exemplo, vamos clicar com o botão direito do mouse sobre ProductsTableAdapter e escolher a opção Add Query, como mostrado na figura 10. No wizard que será iniciado, passaremos por praticamente os mesmos passos anteriores. Na primeira tela, escolheremos a opção Use SQL statements e clicamos em Next. Na próxima tela, optaremos pela opção SELECT which return rows e pressionamos novamente o botão Next. Na tela seguinte, iremos definir o comando SQL que será executado:
SELECT ProductID, ProductName, SupplierID, CategoryID, QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder, ReorderLevel, Discontinued FROM Products WHERE CategoryID=@Categoria
Figura 10 - Adicionando um novo método ao TableAdapter
Na tela onde definimos os métodos a serem adicionados, deixe marcada somente a opção Return a DataTable, cujo nome do método deverá ser ObtemProdutosPorCategoria. Clique em Next e depois em Finish para completar o wizard. O Visual Studio cria o método conforme especificado, percebendo, inclusive, que ele irá receber um parâmetro. A tela do DataSet Designer deverá ser semelhante à figura 11:
Figura 11 - Northwind DataSet
Até o momento, não precisamos escrever nenhum código. Tudo foi definido de forma gráfica e produtiva. O DataSet Tipado é representado por um arquivo com extensão .xsd, que significa XML Schema Definition. Esse arquivo contém a definição da estrutura do DataSet Tipado, e é utilizado para gerar o código C# automaticamente, em tempo de execução ou de desenvolvimento. Podemos visualizar o conteúdo do arquivo XML se clicarmos com o botão direito do mouse sobre uma área livre do DataSet Designer e escolhermos a opção View Code. Além disso, como marcamos a opção para armazenar a string de conexão no arquivo de configuração, haverá uma entrada parecida com a abaixo no arquivo web.config:
<connectionStrings>
<add name="NorthwindConnectionString" connectionString="Data Source=.\SQLEXPRESS;Initial Catalog=Northwind;Integrated Security=True" providerName="System.Data.SqlClient" />
</connectionStrings>
O elemento <connectionStrings> é uma novidade do ASP.NET 2.0, no qual devemos declarar quais as strings de conexões que iremos utilizar. Nos exemplos feitos anteriormente, repetíamos a string de conexão cada vez que acessávamos o banco de dados. Essa não é uma prática recomendada, pois duplica-se código e dificulta a manutenção. Com a string de conexão armazenada no web.config, poderíamos utilizar o seguinte código para recuperá-la:
String strConn = ConfigurationManager.ConnectionStrings["NorthwindConnectionString"].ConnectionString;
A classe ConfigurationManager foi introduzida no .NET Framework 2.0, e agora é, portanto, o meio indicado para se trabalhar com arquivos de configuração. Para concluir o exemplo, no Solution Explorer, clique com o botão direito sobre o projeto e escolha a opção Add New Item. Escolha o template Web Form e a linguagem C#. Dê o nome DSTipado.aspx para o novo Web Form. Monte um formulário parecido com o primeiro exemplo, ou seja, com um controle DropDownList com ID ddlCategorias e a propriedade AutoPostBack igual a True, e um controle GridView, cujo ID é gvProdutos. Abra o arquivo de código-fonte da página (DSTipado.aspx.cs) e adicione o código relativo ao método preencheGridView, conforme código abaixo. Nele, instanciamos o TableAdapter da tabela Products e executamos o método ObtemProdutosPorCategoria, passando o parâmetro parCategoria. Os TableAdapters criados ficam em um namespace específico, que nesse caso chama-se NorthwindDataSetTableAdapters.
protected void preencheGridView(string parCategoria)
{
NorthwindDataSetTableAdapters.ProductsTableAdapter taProducts = new NorthwindDataSetTableAdapters.ProductsTableAdapter();
gvProdutos.DataSource = taProducts.ObtemProdutosPorCategoria(Int32.Parse(parCategoria));
gvProdutos.DataBind();
}
Agora, no evento Page_Load, adicione o código para preencher o DropDownList com as categorias disponívies. Primeiro, instanciamos o TableAdapter da tabela Category e depois executamos o método GetCategories(), associando o seu retorno à propriedade DataSource do controle ddlCategorias:
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
NorthwindDataSetTableAdapters.CategoriesTableAdapter taCategories = new NorthwindDataSetTableAdapters.CategoriesTableAdapter();
ddlCategorias.DataSource = taCategories.GetCategories();
ddlCategorias.DataBind();
preencheGridView(ddlCategorias.SelectedValue);
}
}
Por fim, adicione o código relativo ao evento SelectedIndexChanged do controle ddlCategorias:
protected void ddlCategorias_SelectedIndexChanged(object sender, EventArgs e)
{
preencheGridView(ddlCategorias.SelectedValue);
}
Execute a aplicação e veja que o DropDownList contém as categorias disponíveis. Selecione outras categorias e veja os produtos relacionados serem exibidos no GridView. Perceba que temos a mesma funcionalidade do exemplo anterior. A diferença é que não precisamos escrever nenhum código que utilizasse os objetos do ADO.NET, como Connection, Command e DataAdapter. Eles continuam a serem utilizados de forma indireta, e automaticamente, através do TableAdapter, que abstrai e encapsula toda essa camada de acesso a dados, cujo padrão costuma ser repetitivo (abir conexão, executar comando, fechar conexão). Assim, passamos a trabalhar com métodos de mais alto nível, sem nos preocuparmos com o que ocorre por trás. Essa abstração facilita, por exemplo, a troca do banco de dados que acessamos. Caso isso ocorrese, bastaria que o DataSet Tipado fosse gerado novamente, para que o TableAdapter fosse atualizado, sem a necessidade de alterações na aplicação. Além disso, também temos o benefício de trabalhar com um modelo de dados fortemente tipado, que nos oferece uma série de vantagens de produtividade e qualidade do sistema.
Conclusão
Vimos como funciona, basicamente, o acesso a dados no .NET Framework através do ADO.NET. Foram mostrados os Data Providers, as principais diferenças entre o modelo conectado e o desconectado, e como o uso de DataSet Tipado e TableAdapter podem ajudar na produtividade a na melhora de qualidade da aplicação. O próximo artigo abordará os controles Data Source. Até lá!