Faremos um programa de cadastro de produtos seguindo orientação a objetos, fazendo o máximo isolamento possível e a menor quantidade de código também :)
Vamos conhecer também os componentes ObjectDataSource, GridView e FormView entre outros.
Banco de dados: Usarei o MS SQL Server mas qualquer banco de dados suportado pela tecnologia ADO.NET pode ser usado.
Nossa tabela será chamada Produtos e terá os seguintes campos:
ProdutoID - int - not null - Chave Primária
Descricao - varchar(50) - not null
PrecoCompra - decimal(18, 2) - not null
Saldo - int - not null
O campo ProdutoID não é auto incrementado; para isso usaremos uma tabela chamada Contaores.
Tabela - varchar(50) - not null - Chave Primária
Contador - int - not null
Você até poderia usar um campo to tipo autoinc ou criar trigger, mas o objetivo aqui não é esse.
Teremos um registro nesta tabela onde o campo Tabela será Produtos e ele será incrementado a cada registro que for inserido na tabela.
Então vamos lá. Iniciaremos um novo WebSite no VS2005 em C#
Agora vamos em File > New > File e selecione DataSet. Chame de DataSetProduto.xsd
O VS irá pedir para criar uma pasta chamada App_Code e colocar o recém criado DataSet nesta pasta. Escolha sim.
No assistente do TableAdapter vamos escolher uma conexão com o banco de dados. Se ainda não tiver crie uma. Dê preferência em usar o driver OLEDB em vez do driver direto para SQL Server, porque o driver direto tem diferenças nos parâmetros e você fica acoplado ao banco, e isso não é o que queremos. Assim que criar a conexão o VS vai perguntar se você quer salvar esta string de conexão no arquivo Web.Config. Responda que sim e deixe o nome padrão de ConnectionString.
Agora selecione Use SQL statements e avance; defina o comando SQL para trazer a tabela de produtos:
SELECT ProdutoID, Descricao, PrecoCompra, Saldo
FROM Produtos
WHERE ProdutoID = ?
deixe a próxima tela como está e avance.
Nesta última tela o assistente mostra as operações que foram feitas. Clique Finish.
Com isso temos nosso TableAdapter que representa a tabela Produtos e os métodos Fil, GetData que representam a query que digitamos. No TypedDataSet temos o TableAdapter que é composto do DataTable (Produtos) e as várias queries que terão diferentes parâmetros para trazer os resultados.
Agora vamos criar a query para consultar produtos por descrição. Clique com o botão direito em ProdutosTableAdapter e escolha a opção Add Query. Deixe SQL marcado e avance. Select with return rows (select que retorna várias linhas); avance. Segue o comando:
SELECT ProdutoID, Descricao, PrecoCompra, Saldo
FROM Produtos
WHERE Descricao LIKE ?
ORDER BY Descricao
Avance. Troque os nomes dos métodos de FillBy e GetDataBy para FillByDescricao e GetDataByDescricao e avance. Finalize.
Devido a um pequeno BUG(!) na ferramente este parâmetro string não é mapeado corretamente. Então clique em FillByDescricao,GetDataByDescricao (Descricao) e abra a janela Properties.
Na propriedade Parameters clique nas reticências e procure a propriedade ProviderType do Parâmetro Descricao e troque de Char para VarChar. Dê Ok.
Aaaaarrrrrrggghghghghh BUGGGG!!!!
Sempre que você fizer uma consulta com o operador LIKE faça esta verificação com os parâmetros String que você tiver.
Agora temos nosso DataTable Produtos com duas queries: Fill/GetData e FillByDescricao/GetDataByDescricao.
Tá legal, mas qual é a diferença? Ok, eu explico: os Métodos Fill aceitam como parâmetro um objeto do tipo DataTable e o preenchem com dados; já os GetData retornam o DataTable para serem usados em métodos de objetos de negócio por exemplo. Como usaremos objetos de negócio aqui nós veremos os GetData no nosso código.
Uma vez que criamos a representação da tabela Produtos na nossa aplicação faremos agora a representação da tabela Contadores. Clique em qualquer área livre do DataSet com o botão direito e escolha Add > TableAdapter. O assistente é igual ao da criação do DataTable Produtos. Agora faremos o select na tabela Contadores. O comando SQL é:
SELECT Tabela, Contador
FROM Contadores
WHRE Tabela = ?
Deixe o resto como padrão e prossiga até terminar. Agora nós já definimos toda a nossa representação do banco de dados. Iremos agora criar o objeto de negócio para manipulação destes dados e interação com a aplicação.
É uma ótima prática separar logicamente (fisicamente também é até melhor!) as camadas de dados e apresentação (interface) para manter as partes mais isoladas e independentes e tornar as mudanças nas regras de negócios um processo mais suave.
Salve o DataSet e na janela Solution Explorer clique com o botão direito na pasta App_Code e escolha Add New Item. Selecione o ícone Class e chame o arquivo de Produto.cs.
Esta classe será responsável pela manipulação de dados na interface da aplicação. O objetivo desta classe é prover acesso e manipulação dos dados representados no DataSet, mas mantendo um isolamento e encapsulamento para que a interface tenha que somente fazer o necessário: selecionar a operação e passar os parâmetros para o objeto de negócio para este realizar as ações.
primeiro vamos fazer referência ao namespace que contém os objetos TableAdapter do nosso DataSet para não termos que digitar o seu nome toda hora. logo no começo do documento onde há várias cláusulas using vamos adicionar uma:
using DataSetProdutoTableAdapters;
Entenda namespace como um espaço onde são declarados objetos para serem usados de forma organizada. O namespace acima engloba os nossos objetos TableAdapter que estão no DataSet. É semelhante a cláusula uses do Delphi.
Agora nesta classe vamos implementar os métodos para utilizar na nossa aplicação.
Primeiro os de consulta:
public DataTable ConsultarPorID(int ProdutoID) {
ProdutosTableAdapter ta = new ProdutosTableAdapter();
return ta.GetData(ProdutoID);
}
public DataTable ConsultarPorDescricao(string Descricao) {
ProdutosTableAdapter ta = new ProdutosTableAdapter();
return ta.GetDataByDescricao(Descricao);
}
Agora os de cadastro:
public void Incluir(int ProdutoID, string Descricao, decimal PrecoCompra, int Saldo) {
ProdutosTableAdapter ta = new ProdutosTableAdapter();
ta.Insert(ProdutoID, Descricao, PrecoCompra, Saldo);
}
public void Alterar(int ProdutoID, string Descricao, decimal PrecoCompra, int Saldo) {
ProdutosTableAdapter ta = new ProdutosTableAdapter();
ta.Update(ProdutoID, Descricao, PrecoCompra, Saldo, ProdutoID);
}
public void Excluir(int ProdutoID) {
ProdutosTableAdapter ta = new ProdutosTableAdapter();
ta.Delete(ProdutoID);
}
Finalmente o método para gerar o contador:
public int GerarID() {
int novoID;
string Tabela = "Produtos";
ContadoresTableAdapter ta = new ContadoresTableAdapter();
DataTable dt = ta.GetData(Tabela);
if (dt.Rows.Count > 0) {
novoID = Convert.ToInt32(dt.Rows[0]["Contador"]) + 1;
ta.Update(Tabela, novoID, Tabela);
}
else {
novoID = 1;
ta.Insert(Tabela, novoID);
}
return novoID;
}
Este método GerarID acessa a tabela contadores e incrementa o contador caso já exista algum ou inclui novo registro caso ainda não exista.
Agora nossa classe está pronta; vamos implementar as interfaces. No nosso Default.aspx vamos colocar os links para as páginas que farão o cadastro. Abra o Default.aspx. Dentro do nosso form inclua os links para as operações:
<h1 style="border-bottom: solid 1px black">Cadastro de Produtos</h1>
<a href="Incluir.aspx">Incluir</a><br />
<a href="Consular.aspx">Consultar - Alterar e excluir</a>
segue o HTML completo:
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<h1 style="border-bottom: solid 1px black">Cadastro de Produtos</h1>
<a href="Incluir.aspx">Incluir</a><br />
<a href="Consultar.aspx">Consultar - Alterar e excluir</a>
</div>
</form>
</body>
</html>
No Solution Explorer clique com o botão direito no Default.aspx e clique em Set as Start Page. Salve e feche Default.aspx.
Criando a página Incluir.aspx
Agora vamos criar o formulário de inclusão de registro. Clique com o botão direito no WebSite e escolha Add New Item. Escolha WebForm e chame de Incluir.aspx.
Para facilitar um pouco as coisas vamos para a visualização Design. Na parte inferior do editor há dois botões: Design e Code; clique em Design.
O Editor de HTML do VS é muito bom. Eu uso o editor até para colocar componentes ASP.NET, e ainda dá para alterar as propriedades na janela Properties clicando dentro ta tag na visualização HTML.
Na janela Toolbox na seção Data há um componente chamado ObjectDatasource. Dê um duplo clique nele para adicionar ao WebForm.
Na janela Properties mude a propriedade ID de ObjectDataSource1 para ObjDsProduto. No rodapé da janela Properties ainda há um link 'Configure Data Source...'. Clique nele.
No campo Choose your business object temos que escolher a classe Produto que nós codificamos; porém ele não aparece na lista. Devemos desmarcar a caixa ao lado 'Show only data components'. Agora, no meio de várias opções aparecerá Produto. Selecione e dê next.
Nesta página vamos incluir; então só precisamos definir os métodos de SELECT e INSERT. Na aba SELECT escolha o método ConsultarPorID e na aba INSERT escolha Incluir. Dê next.
Na próxima página o objeto nos pergunta sobre o valor padrão do parâmetro ProdutoID do método Select (nós podemos passar valores dinamicamente também). Entre com -1 para o valor. usamos este número para que a consulta não retorne registros, já que nossa operação é de INSERT e para isso não precisamos de dados neste momento. Dê Finish.
Agora que a fonte de dados está configurada vamos colocar o objeto que mostrará os campos para fazer a inserção no banco de dados. Este componente é o FormView. Deixe o cursor abaixo do ObjDsProduto e na Toolbox novamente acesse a seção Data e dê um duplo clique no FormView. Abra a janela Properties e defina as propriedades:
ID: FvwProduto
DatasourceID: ObjDsProduto
DefaultMode: Insert
Este componente nos permite criar formulários com campos diretamente ligados ao nosso DataSource (ObjDsProduto). Então vamos criar um template para o form de Insert. Clique com o botão direito no componente e escolha Edit Template > InsertItem Template. Agora tem uma área editável dentro do FormView para colocarmos os campos. Nós precisamos de 4 caixas de texto para representar os campos da tabela e um botão para confirmar e outro para cancelar. vamos um a um:
Com o cursor dentro do InsertItemTemplate vá na Toolbox e insira um TextBox:
ID: TxtProdutoID
ReadOnly: True
Agora na parte inferior da janela clique em 'Edit Databindings...'
No campo aberto para editar entre com Bind('ProdutoID') (o campo do DataSource que ele representará)
Abaixo insira outra TextBox:
ID: TxtDescricao
No 'Edit Databindings...' selecione Bind('Descricao')
Mais uma linha, mais uma TextBox:
ID: TxtPrecoCompra
'Edit Databinddings...' - Bind('PrecoCompra')
Último campo:
ID: TxtSaldo
'Edit DataBindings...' - Bind('Saldo')
Na linha de baixo insira dois botões, um ao lado do outro:
Botão 1:
ID: BtnConfirmar
Text: Confirmar
CommandName: Insert
Botão 2:
ID: BtnCancelar
Text: Cancelar
A propriedade CommandName do objeto Button serve para enviar um comando para o objeto que o está armazenando, no nosso caso o FormView. O FormView possui vários comandos para manipulação de registro, como Edit, New, Insert, Update, etc. O comando Insert chama o método de Insert do DataSource associado ao FormView (ObjDsProduto, que por sua vez chama o método Incluir definido na nossa classe Produto.
Agora digite os textos referentes a cada campo no lado esquerdo de cada um. Se você quiser pode ir até a visualização HTML e editar o html para colocar table. Meu exemplo ficou assim:
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Incluir.aspx.cs" Inherits="Incluir" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:ObjectDataSource ID="ObjDsProduto" runat="server" InsertMethod="Incluir" SelectMethod="ConsultarPorID"
TypeName="Produto">
<SelectParameters>
<asp:Parameter DefaultValue="-1" Name="ProdutoID" Type="Int32" />
</SelectParameters>
<InsertParameters>
<asp:Parameter Name="ProdutoID" Type="Int32" />
<asp:Parameter Name="Descricao" Type="String" />
<asp:Parameter Name="PrecoCompra" Type="Decimal" />
<asp:Parameter Name="Saldo" Type="Int32" />
</InsertParameters>
</asp:ObjectDataSource>
</div>
<asp:FormView ID="FvwProduto" runat="server" DataSourceID="ObjDsProduto" DefaultMode="Insert">
<InsertItemTemplate>
<table border="0" cellpadding="0" celllspacing="0">
<tr>
<td>ID:</td>
<td><asp:TextBox ID="TxtProdutoID" runat="server" Text="<%# Bind('ProdutoiD') %>"></asp:TextBox></td>
</tr>
<tr>
<td>Descrição:</td>
<td><asp:TextBox ID="TxtDescricao" runat="server" Text="<%# Bind('Descricao') %>"></asp:TextBox></td>
</tr>
<tr>
<td>Preço:</td>
<td><asp:TextBox ID="TxtPrecoCompra" runat="server" Text="<%# Bind('PrecoCompra') %>"></asp:TextBox></td>
</tr>
<tr>
<td>Saldo:</td>
<td><asp:TextBox ID="TxtSaldo" runat="server" Text="<%# Bind('Saldo') %>"></asp:TextBox></td>
</tr>
<tr>
<td colspan="2" align="center"><asp:Button ID="BtnConfirmar" runat="server" CommandName="Insert" Text="Confirmar" /> <asp:Button
ID="BtnCancelar" runat="server" Text="Cancelar" /></td>
</tr>
</table>
</InsertItemTemplate>
</asp:FormView>
</form>
</body>
</html>
Agora vamos codificar. Lembra como era em ASP para fazer um formulário de Inclusão? Lembra como é em JAVA? VB? Delphi? Blá? Blá???? Muito bem, aqui o modo é bem fácil. Se você rodar o programa para testar ele já funciona. Funciona? Sim, funciona!
A partir de agora vamos fazer um pequeno polimento nele. Do jeito que ele está nós temos que passar o valor do campo ProdutoID na mão; e já que ele é ReadOnly nós não conseguimos inserir. E, assim que a inclusão é realizada ele volta o formulário em branco para outra inserção. A idéia aqui é gerar um novo ID através do método GerarID da classe Produto e assim que terminar a inclusão retornar à página Default.aspx. Vamos nessa.
Vamos cuidar do mais fácil primeiro: dê um duplo clique no botão Cancelar para fazer logo o redirecionamento para a página inicial (certifique-se de que está no modo de EditTemplate):
protected void BtnCancelar_Click(object sender, EventArgs e) {
Response.Redirect("Default.aspx");
}
Ainda na página de código vamos codificar o evento Page_Load, que dispara sempre que a página carrega:
protected void Page_Load(object sender, EventArgs e)
{
TextBox txt = (TextBox)FvwProduto.FindControl("TxtProdutoID");
if (txt.Text == "") {
Produto p = new Produto();
txt.Text = p.GerarID().ToString();
}
}
Aqui recuperamos o objeto TextBox TxtProdutoID dentro do FormView e geramos um novo ID para ele caso ainda não tenha sido definido.
Agora faremos o código para redirecionar para a página inicial quando a operação for finalizada:
Volte para o design da interface - Botão direito na página de código - View Designer e selecione o ObjDsProduto. Na janela de propriedades
há um botão que é um raio: este lista os eventos do componente. Vamos codificar o evento Inserted, que dispara depois que um item é inserido. Dê um duplo clique na área do valor:
protected void ObjDsProduto_Inserted(object sender, ObjectDataSourceStatusEventArgs e) {
Response.Redirect("Default.aspx");
}
Por incrível que pareça, está pronto. Agora para a etapa final da nossa pequena aplicação: Tela para consultar, alterar e excluir.
Mas tudo na mesma página? Meu amigo haja código hein... Nem sempre. Temos no ASP.NET um componente muito legal: GridView. Ele em conjunto com o ObjectDataSource faz todas as operações totalmente sem código. Sem código? Sem código. :)
Salve o Incluir.aspx e feche. Agora com o botão direito no site Add New Item; WebForm e chame de Consultar.aspx.
Vamos direto para o Design e assim como na anterior insira um ObjectDataSource e defina as prorpriedades:
ID: ObjDsProduto
Clique 'Configure Data Source...' na parte inferior.
Desmarque 'Show only data components' e no campo anterior selecione Produto
Avançar
Na aba SELECT escolha ConsultarPorDescricao
Na aba UPDATE escolha Alterar
Na aba DELETE escolha Excluir
Avançar
Deixe o parâmetro em branco e Finish.
Primeiro insira um link para retornar abaixo do ObjDsProduto:
<a href="Default.aspx">Voltar</a>
Agora vamos inserir e configurar nosso GridView: Na Toolbox na parte Data duplo clique em GridView. Selecione ele e abra a janela Properties:
ID: GvwProduto
CellPadding: 4
CellSpacing: 0
DataSourceID: ObjDsProduto
DataKeyNames: ProdutoID (tem que digitar)
Columns: Clique nas reticências
Agora vamos configurar as colunas:
Selecione BoundField e clique Add
HeaderText: ID
DataField: ProdutoID
ReadOnly: True
Selecione novamente BoundField e clique Add
HeaderText: Descrição
DataField: Descricao
Outro BoundField:
HeaderText: Preço
DataField: PrecoCompra
Último BoundField:
HeaderText: Saldo
DataField: Saldo
Agora expanda CommandField e selecione Edit, Update, Cancel. Clique Add
CancelText: Cancelar
EditText: Editar
UpdateText: Atualizar
Por fim, dentro de CommandField selecione Delete e clique Add
DeleteText: Excluir.
Na parte inferior da janela desmarque a caixa 'Auto-generate fields' e dê Ok.
Rode a aplicação com Ctrl+F5. Parabéns!
Não sei vocês, mas se eu tentar fazer este grid "boladão" em PHP acho que vai ser uma boa diversão de fim de semana. Imagina em JAVA! Hehe.
É isso aí. Boa diversão para todos.
Felipe, parabéns pelo artigo!!!
ResponderExcluirAinda não tinha encontrado nada tão arrojado sobre este assunto. Digo arojado so sentido de tentar um exemplo pratico visando buscar um grau elevado da complexidade de uma situação real, sem minizar tanto a inteligência do leitor, nem tratar com reducionismo os principais problemas quando construimos um CRUD.
Parabéns!!!
Veja, se for possível pesso que me esclareça algumas dúvidas a respeito do seu arigo:
1) Vc wm dado momento referencia uma tabela contadores, inclusive cria um tableadapter com comando sql para consultar, entretato não entendi como esta tabela é atualizada. Se ela não for atualizada como o incremento do próximo ID poderá ser um valor adequado?
2) Quando criei o tableadapter de produtos passei a receber uma exceção com a serguinte mensagem: "Could not find schema information for the element' urn:schemas-microsoft-com:xml-msdatasource-layout:DiagramaLauyout'".
file = DataSetProdutos.
3)Outra coisa, aonde fica o check sintax no MSVS2008??
Socorro!!!!!
Agradeceria a ajuda pois estou dando meus primeiros passos com C#/MSVS2008.
Galera alguem sabe pq ta dando esse erro, pois fiz tudo como o Felipe mandou. Espero que possam me ajudar.
ResponderExcluirMensagem de erro:
-----------------
Server Error in '/WebSite2' Application.
--------------------------------------------------------------------------------
Value cannot be null.
Parameter name: Descricao
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.ArgumentNullException: Value cannot be null.
Parameter name: Descricao
Source Error:
Line 1434: this.Adapter.SelectCommand = this.CommandCollection[1];
Line 1435: if ((Descricao == null)) {
Line 1436: throw new global::System.ArgumentNullException("Descricao");
Line 1437: }
Line 1438: else {
Source File: c:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files\website2\b7818db0\72a3e352\App_Code.s8dx1myu.1.cs Line: 1436
Stack Trace:
[ArgumentNullException: Value cannot be null.
Parameter name: Descricao]
DataSetProdutoTableAdapters.ProdutosTableAdapter.GetDataByDescricao(String Descricao) in c:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files\website2\b7818db0\72a3e352\App_Code.s8dx1myu.1.cs:1436
Produto.ConsultarPorDescricao(String Descricao) in c:\Documents and Settings\User\Meus documentos\Visual Studio 2008\WebSites\WebSite2\App_Code\Produto.cs:35
[TargetInvocationException: Exception has been thrown by the target of an invocation.]
System.RuntimeMethodHandle._InvokeMethodFast(Object target, Object[] arguments, SignatureStruct& sig, MethodAttributes methodAttributes, RuntimeTypeHandle typeOwner) +0
System.RuntimeMethodHandle.InvokeMethodFast(Object target, Object[] arguments, Signature sig, MethodAttributes methodAttributes, RuntimeTypeHandle typeOwner) +71
System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks) +261
System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture) +29
System.Web.UI.WebControls.ObjectDataSourceView.InvokeMethod(ObjectDataSourceMethod method, Boolean disposeInstance, Object& instance) +488
System.Web.UI.WebControls.ObjectDataSourceView.ExecuteSelect(DataSourceSelectArguments arguments) +1247
System.Web.UI.DataSourceView.Select(DataSourceSelectArguments arguments, DataSourceViewSelectCallback callback) +19
System.Web.UI.WebControls.DataBoundControl.PerformSelect() +142
System.Web.UI.WebControls.BaseDataBoundControl.DataBind() +73
System.Web.UI.WebControls.GridView.DataBind() +4
System.Web.UI.WebControls.BaseDataBoundControl.EnsureDataBound() +82
System.Web.UI.WebControls.CompositeDataBoundControl.CreateChildControls() +72
System.Web.UI.Control.EnsureChildControls() +87
System.Web.UI.Control.PreRenderRecursiveInternal() +44
System.Web.UI.Control.PreRenderRecursiveInternal() +171
System.Web.UI.Control.PreRenderRecursiveInternal() +171
System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +842
--------------------------------------------------------------------------------
Version Information: Microsoft .NET Framework Version:2.0.50727.3053; ASP.NET Version:2.0.50727.3053
Olá Marcelo. Desculpe por demorar a responder. Lá no trabalho o link do blog é bloqueado (dá para acreditar?)
ResponderExcluirPara corrigir este erro você deve configurar o ObjectDataSource que contém o método de select e avançar até os parâmetros de entrada. Lá tem um link chamado Show advanced properties. Clique neste link e aparecerão mais opções. Na grade que vai aparecer procure a configuração ConvertEmptyStringToNull e coloque como false. Aí vai funcionar legal.
Para explicar o problema: Na query nós definimos que ela aceita um parâmetro do tipo String, e quando nenhum valor é passado é padrão do componente converter String vazia ("") em null. Mas no nosso caso queremos a String vazia mesmo.
Espero ter ajudado e muito obrigado por acessar e deixar comentário no nosso Blog. Um abraço.
Caso você esteja estudando .Net e não esteja em um projeto pela metade, vale a pena conferir o Linq. Veja neste post: Linq to SQL - Trabalhando com bancos de dados. É a tecnologia mais recente de acesso e manipulação de dados.
ResponderExcluir