Share via


Criação de uma Camada de acesso a dados (C#)

por Scott Mitchell

Baixar PDF

Neste tutorial, começaremos desde o início e criaremos a DAL (Camada de Acesso a Dados), usando DataSets tipado, para acessar as informações em um banco de dados.

Introdução

Como desenvolvedores da Web, nossas vidas giram em torno de trabalhar com dados. Criamos bancos de dados para armazenar os dados, o código para recuperá-los e modificá-los e páginas da Web para coletar e resumi-los. Este é o primeiro tutorial de uma longa série que explorará técnicas para implementar esses padrões comuns no ASP.NET 2.0. Começaremos com a criação de uma arquitetura de software composta por uma DAL (Camada de Acesso a Dados) usando DataSets Tipados, uma BLL (Camada lógica de negócios) que impõe regras de negócios personalizadas e uma camada de apresentação composta por ASP.NET páginas que compartilham um layout de página comum. Depois que essa base de back-end for estabelecida, passaremos para relatórios, mostrando como exibir, resumir, coletar e validar dados de um aplicativo Web. Esses tutoriais são voltados para serem concisos e fornecem instruções passo a passo com muitas capturas de tela para orientá-lo no processo visualmente. Cada tutorial está disponível nas versões C# e Visual Basic e inclui um download do código completo usado. (Este primeiro tutorial é bastante longo, mas o restante é apresentado em partes muito mais digestíveis.)

Para estes tutoriais, usaremos uma versão SQL Server 2005 Express Edition da Microsoft do banco de dados Northwind colocada no diretório App_Data. Além do arquivo de banco de dados, a pasta App_Data também contém os scripts SQL para criar o banco de dados, caso você deseje usar uma versão de banco de dados diferente. Se você usar uma versão SQL Server diferente do banco de dados Northwind, precisará atualizar a configuração NORTHWNDConnectionString no arquivo Web.config do aplicativo. O aplicativo Web foi criado usando o Visual Studio 2005 Professional Edition como um projeto de site baseado em sistema de arquivos. No entanto, todos os tutoriais funcionarão igualmente bem com a versão gratuita do Visual Studio 2005, Visual Web Developer.

Neste tutorial, começaremos desde o início e criaremos a DAL (Camada de Acesso a Dados), seguida pela criação da BLL (Camada lógica de negócios) no segundo tutorial e o trabalho no layout e navegação da página no terceiro. Os tutoriais após o terceiro se basearão na base estabelecida nos três primeiros. Temos muito a abordar neste primeiro tutorial, então acione o Visual Studio e vamos começar!

Etapa 1: Criar um projeto Web e conectar-se ao banco de dados

Antes de podermos criar nossa DAL (Camada de Acesso a Dados), primeiro precisamos criar um site e configurar nosso banco de dados. Comece criando um novo site de ASP.NET baseado no sistema de arquivos. Para fazer isso, vá para o menu Arquivo e escolha Novo Site, exibindo a caixa de diálogo Novo Site. Escolha o modelo ASP.NET Site, defina a lista suspensa Local como Sistema de Arquivos, escolha uma pasta para colocar o site e defina o idioma como C#.

Criar um novo arquivo System-Based site

Figura 1: Criar um novo arquivo System-Based site (clique para exibir a imagem em tamanho real)

Isso criará um novo site com uma página ASP.NET Default.aspx e uma pasta App_Data .

Com o site criado, a próxima etapa é adicionar uma referência ao banco de dados no servidor do Visual Studio Explorer. Ao adicionar um banco de dados ao Servidor Explorer você pode adicionar tabelas, procedimentos armazenados, exibições e assim por diante de dentro do Visual Studio. Você também pode exibir dados de tabela ou criar suas próprias consultas manualmente ou graficamente por meio do Construtor de Consultas. Além disso, quando criarmos os Conjuntos de Dados Tipados para o DAL, precisaremos apontar o Visual Studio para o banco de dados do qual os Conjuntos de Dados Tipados devem ser construídos. Embora possamos fornecer essas informações de conexão nesse momento, o Visual Studio preenche automaticamente uma lista suspensa dos bancos de dados já registrados no servidor Explorer.

As etapas para adicionar o banco de dados Northwind ao servidor Explorer dependem se você deseja usar o banco de dados SQL Server 2005 Express Edition na pasta App_Data ou se você tem uma configuração de servidor de banco de dados do Microsoft SQL Server 2000 ou 2005 que deseja usar.

Usando um banco de dados na pasta App_Data

Se você não tiver um servidor de banco de dados SQL Server 2000 ou 2005 ao qual se conectar ou simplesmente quiser evitar a necessidade de adicionar o banco de dados a um servidor de banco de dados, poderá usar a versão SQL Server 2005 Express Edition do banco de dados Northwind localizado na pasta App_Data do site baixado (NORTHWND). MDF).

Um banco de dados colocado na pasta App_Data é adicionado automaticamente ao servidor Explorer. Supondo que você tenha SQL Server 2005 Express Edition instalado em seu computador, você deverá ver um nó chamado NORTHWND. MDF no servidor Explorer, que você pode expandir e explorar suas tabelas, exibições, procedimento armazenado e assim por diante (consulte a Figura 2).

A pasta App_Data também pode conter arquivos de .mdb do Microsoft Access, que, como seus equivalentes SQL Server, são adicionados automaticamente à Explorer do Servidor. Se você não quiser usar nenhuma das opções de SQL Server, sempre poderá instalar o banco de dados e os aplicativos da Northwind Traders e entrar no diretório App_Data. Tenha em mente, no entanto, que os bancos de dados do Access não são tão ricos em recursos quanto SQL Server e não foram projetados para serem usados em cenários de site. Além disso, alguns dos mais de 35 tutoriais utilizarão determinados recursos no nível do banco de dados que não são compatíveis com o Access.

Conectando-se ao banco de dados em um Servidor de Banco de Dados do Microsoft SQL Server 2000 ou 2005

Como alternativa, você pode se conectar a um banco de dados Northwind instalado em um servidor de banco de dados. Se o servidor de banco de dados ainda não tiver o banco de dados Northwind instalado, primeiro você deverá adicioná-lo ao servidor de banco de dados executando o script de instalação incluído no download deste tutorial.

Depois de instalar o banco de dados, acesse o Explorer servidor no Visual Studio, clique com o botão direito do mouse no nó Connections de Dados e escolha Adicionar Conexão. Se você não vir o servidor Explorer ir para a Explorer Exibir/Servidor ou pressione Ctrl+Alt+S. Isso abrirá a caixa de diálogo Adicionar Conexão, na qual você poderá especificar o servidor ao qual se conectar, as informações de autenticação e o nome do banco de dados. Depois de configurar com êxito as informações de conexão do banco de dados e clicar no botão OK, o banco de dados será adicionado como um nó abaixo do nó Connections dados. Você pode expandir o nó do banco de dados para explorar suas tabelas, exibições, procedimentos armazenados e assim por diante.

Adicionar uma conexão ao banco de dados Northwind do servidor de banco de dados

Figura 2: Adicionar uma conexão ao banco de dados Northwind do servidor de banco de dados

Etapa 2: Criando a camada de acesso a dados

Ao trabalhar com dados, uma opção é inserir a lógica específica de dados diretamente na camada de apresentação (em um aplicativo Web, as páginas ASP.NET compõem a camada de apresentação). Isso pode assumir a forma de escrever ADO.NET código na parte de código da página ASP.NET ou usando o controle SqlDataSource da parte de marcação. Em ambos os casos, essa abordagem casa fortemente a lógica de acesso a dados com a camada de apresentação. No entanto, a abordagem recomendada é separar a lógica de acesso a dados da camada de apresentação. Essa camada separada é conhecida como Camada de Acesso a Dados, DAL para abreviar e normalmente é implementada como um projeto separado da Biblioteca de Classes. Os benefícios dessa arquitetura em camadas estão bem documentados (confira a seção "Leituras adicionais" no final deste tutorial para obter informações sobre essas vantagens) e é a abordagem que adotaremos nesta série.

Todo o código específico para a fonte de dados subjacente, como criar uma conexão com o banco de dados, emitir comandos SELECT, INSERT, UPDATE e DELETE e assim por diante, deve estar localizado no DAL. A camada de apresentação não deve conter nenhuma referência a esse código de acesso a dados, mas deve, em vez disso, fazer chamadas para o DAL para qualquer e todas as solicitações de dados. As Camadas de Acesso a Dados normalmente contêm métodos para acessar os dados de banco de dados subjacentes. O banco de dados Northwind, por exemplo, tem tabelasProdutos e Categorias que registram os produtos à venda e as categorias às quais pertencem. Em nosso DAL, teremos métodos como:

  • GetCategories(), que retornará informações sobre todas as categorias
  • GetProducts(), que retornará informações sobre todos os produtos
  • GetProductsByCategoryID(categoryID), que retornará todos os produtos que pertencem a uma categoria especificada
  • GetProductByProductID(productID), que retornará informações sobre um produto específico

Esses métodos, quando invocados, se conectarão ao banco de dados, emitirão a consulta apropriada e retornarão os resultados. A forma como retornamos esses resultados é importante. Esses métodos podem simplesmente retornar um DataSet ou DataReader preenchido pela consulta de banco de dados, mas, idealmente, esses resultados devem ser retornados usando objetos fortemente tipados. Um objeto fortemente tipado é aquele cujo esquema é rigidamente definido em tempo de compilação, enquanto o oposto, um objeto de tipo flexível, é aquele cujo esquema não é conhecido até o runtime.

Por exemplo, o DataReader e o DataSet (por padrão) são objetos de tipo flexível, pois seu esquema é definido pelas colunas retornadas pela consulta de banco de dados usada para preenchê-los. Para acessar uma coluna específica de uma DataTable com tipo flexível, precisamos usar a sintaxe como: DataTable. Rows[index]["columnName"]. A digitação solta da DataTable neste exemplo é exibida pelo fato de que precisamos acessar o nome da coluna usando uma cadeia de caracteres ou um índice ordinal. Uma DataTable fortemente tipada, por outro lado, terá cada uma de suas colunas implementadas como propriedades, resultando em código semelhante a: DataTable. Linhas[índice].columnName.

Para retornar objetos fortemente tipados, os desenvolvedores podem criar seus próprios objetos de negócios personalizados ou usar Conjuntos de Dados Tipados. Um objeto de negócios é implementado pelo desenvolvedor como uma classe cujas propriedades normalmente refletem as colunas da tabela de banco de dados subjacente que o objeto de negócios representa. Um DataSet Tipado é uma classe gerada para você pelo Visual Studio com base em um esquema de banco de dados e cujos membros são fortemente tipado de acordo com esse esquema. O Próprio Conjunto de Dados Tipado consiste em classes que estendem as classes ADO.NET DataSet, DataTable e DataRow. Além dos DataTables fortemente tipados, os Conjuntos de Dados Tipados agora também incluem TableAdapters, que são classes com métodos para preencher as DataTables do DataSet e propagar modificações dentro das DataTables de volta para o banco de dados.

Observação

Para obter mais informações sobre as vantagens e desvantagens do uso de Conjuntos de Dados Tipados versus objetos de negócios personalizados, consulte Criando componentes da camada de dados e passando dados por camadas.

Usaremos Conjuntos de Dados fortemente tipado para a arquitetura desses tutoriais. A Figura 3 ilustra o fluxo de trabalho entre as diferentes camadas de um aplicativo que usa Conjuntos de Dados Tipados.

Todo o código de acesso a dados é relegado ao DAL

Figura 3: Todo o código de acesso a dados é relegado ao DAL (clique para exibir a imagem em tamanho real)

Criando um conjunto de dados tipado e um adaptador de tabela

Para começar a criar nosso DAL, começamos adicionando um Conjunto de Dados Tipado ao nosso projeto. Para fazer isso, clique com o botão direito do mouse no nó do projeto no Gerenciador de Soluções e escolha Adicionar um Novo Item. Selecione a opção DataSet na lista de modelos e nomeie-a como Northwind.xsd.

Escolha adicionar um novo conjunto de dados ao seu projeto

Figura 4: Escolha adicionar um novo conjunto de dados ao seu projeto (clique para exibir a imagem em tamanho real)

Depois de clicar em Adicionar, quando solicitado a adicionar o DataSet à pasta App_Code , escolha Sim. A Designer do Conjunto de Dados Tipado será exibida e o Assistente de Configuração de TableAdapter será iniciado, permitindo que você adicione seu primeiro TableAdapter ao Conjunto de Dados Tipado.

Um Conjunto de Dados Tipado serve como uma coleção fortemente tipada de dados; ele é composto por instâncias datatable fortemente tipada, cada uma das quais, por sua vez, é composta por instâncias DataRow fortemente tipada. Criaremos uma DataTable fortemente tipada para cada uma das tabelas de banco de dados subjacentes com as quais precisamos trabalhar nesta série de tutoriais. Vamos começar com a criação de uma DataTable para a tabela Products .

Tenha em mente que DataTables fortemente tipado não incluem nenhuma informação sobre como acessar dados de sua tabela de banco de dados subjacente. Para recuperar os dados para preencher a DataTable, usamos uma classe TableAdapter, que funciona como nossa Camada de Acesso a Dados. Para nossos Produtos DataTable, o TableAdapter conterá os métodos GetProducts(), GetProductByCategoryID(categoryID) e assim por diante, invocaremos da camada de apresentação. A função do DataTable é servir como os objetos fortemente tipados usados para passar dados entre as camadas.

O Assistente de Configuração do TableAdapter começa solicitando que você selecione com qual banco de dados trabalhar. A lista suspensa mostra esses bancos de dados no servidor Explorer. Se você não adicionou o banco de dados Northwind ao servidor Explorer, clique no botão Nova Conexão neste momento para fazer isso.

Escolha o Banco de Dados Northwind na Lista de Drop-Down

Figura 5: Escolher o Banco de Dados Northwind na Lista de Drop-Down (Clique para exibir a imagem em tamanho real)

Depois de selecionar o banco de dados e clicar em Avançar, você será perguntado se deseja salvar o cadeia de conexão no arquivo Web.config. Ao salvar o cadeia de conexão você evitará que ele seja embutido em código nas classes TableAdapter, o que simplifica as coisas se as informações cadeia de conexão forem alteradas no futuro. Se você optar por salvar o cadeia de conexão no arquivo de configuração, ele será colocado na <seção connectionStrings>, que pode ser criptografada opcionalmente para melhorar a segurança ou modificada posteriormente por meio da nova página de propriedades do ASP.NET 2.0 na Ferramenta de Administração de GUI do IIS, que é mais ideal para os administradores.

Salvar a cadeia de conexão em Web.config

Figura 6: Salvar a cadeia de conexão em Web.config (clique para exibir a imagem em tamanho real)

Em seguida, precisamos definir o esquema para o primeiro DataTable fortemente tipado e fornecer o primeiro método para nosso TableAdapter usar ao preencher o DataSet fortemente tipado. Essas duas etapas são realizadas simultaneamente criando uma consulta que retorna as colunas da tabela que queremos refletir em nossa DataTable. No final do assistente, forneceremos um nome de método para essa consulta. Depois que isso for feito, esse método poderá ser invocado de nossa camada de apresentação. O método executará a consulta definida e preencherá uma DataTable fortemente tipada.

Para começar a definir a consulta SQL, primeiro devemos indicar como queremos que o TableAdapter emita a consulta. Podemos usar uma instrução SQL ad hoc, criar um novo procedimento armazenado ou usar um procedimento armazenado existente. Para estes tutoriais, usaremos instruções SQL ad hoc.

Consultar os dados usando uma instrução SQL Ad Hoc

Figura 7: Consultar os dados usando uma instrução SQL Ad Hoc (clique para exibir a imagem em tamanho real)

Neste ponto, podemos digitar a consulta SQL manualmente. Ao criar o primeiro método no TableAdapter, você normalmente deseja que a consulta retorne as colunas que precisam ser expressas na DataTable correspondente. Podemos fazer isso criando uma consulta que retorna todas as colunas e todas as linhas da tabela Products :

Insira a consulta SQL na caixa de texto

Figura 8: Insira a consulta SQL na caixa de texto (clique para exibir a imagem em tamanho real)

Como alternativa, use o Construtor de Consultas e construa graficamente a consulta, conforme mostrado na Figura 9.

Criar a consulta graficamente por meio do Editor de Consultas

Figura 9: Criar a consulta graficamente por meio do Editor de Consultas (clique para exibir a imagem em tamanho real)

Depois de criar a consulta, mas antes de passar para a próxima tela, clique no botão Opções Avançadas. Em Projetos de Site, "Gerar instruções Inserir, Atualizar e Excluir" é a única opção avançada selecionada por padrão; se você executar esse assistente em uma Biblioteca de Classes ou em um Projeto do Windows, a opção "Usar simultaneidade otimista" também será selecionada. Deixe a opção "Usar simultaneidade otimista" desmarcada por enquanto. Examinaremos a simultaneidade otimista em tutoriais futuros.

Selecione Somente a opção Gerar instruções Inserir, Atualizar e Excluir

Figura 10: selecione apenas a opção Gerar instruções Inserir, Atualizar e Excluir (Clique para exibir a imagem em tamanho real)

Depois de verificar as opções avançadas, clique em Avançar para prosseguir para a tela final. Aqui, é solicitado que selecione quais métodos adicionar ao TableAdapter. Há dois padrões para preencher dados:

  • Preencha uma DataTable com essa abordagem, um método é criado que usa um DataTable como um parâmetro e o preenche com base nos resultados da consulta. O ADO.NET classe DataAdapter, por exemplo, implementa esse padrão com seu método Fill( ).
  • Retornar uma DataTable com essa abordagem, o método cria e preenche a DataTable para você e a retorna como o valor retornado pelos métodos.

Você pode fazer com que o TableAdapter implemente um ou ambos os padrões. Você também pode renomear os métodos fornecidos aqui. Vamos deixar as duas caixas de seleção marcadas, mesmo que usaremos apenas o último padrão ao longo desses tutoriais. Além disso, vamos renomear o método GetData bastante genérico para GetProducts.

Se marcada, a caixa de seleção final, "GenerateDBDirectMethods", cria os métodos Insert(), Update()e Delete() para o TableAdapter. Se você deixar essa opção desmarcada, todas as atualizações precisarão ser feitas por meio do único método Update() do TableAdapter, que usa o Typed DataSet, um DataTable, um único DataRow ou uma matriz de DataRows. (Se você tiver desmarcado a opção "Gerar instruções Insert, Update e Delete" das propriedades avançadas na Figura 9, a configuração dessa caixa de seleção não terá efeito.) Vamos deixar essa caixa de seleção marcada.

Alterar o nome do método de GetData para GetProducts

Figura 11: Alterar o nome do método de GetData para GetProducts (clique para exibir a imagem em tamanho real)

Conclua o assistente clicando em Concluir. Depois que o assistente for fechado, retornaremos ao DataSet Designer que mostra a DataTable que acabamos de criar. Você pode ver a lista de colunas em Produtos DataTable (ProductID, ProductName e assim por diante), bem como os métodos de ProductsTableAdapter (Fill() e GetProducts()).

Os Produtos DataTable e ProductsTableAdapter foram adicionados ao Conjunto de Dados Tipado

Figura 12: Os Produtos DataTable e ProductsTableAdapter foram adicionados ao Conjunto de Dados Tipado (Clique para exibir a imagem em tamanho real)

Neste ponto, temos um DataSet Tipado com uma única DataTable (Northwind.Products) e uma classe DataAdapter fortemente tipada (NorthwindTableAdapters.ProductsTableAdapter) com um método GetProducts(). Esses objetos podem ser usados para acessar uma lista de todos os produtos do código, como:

NorthwindTableAdapters.ProductsTableAdapter productsAdapter =
    new NorthwindTableAdapters.ProductsTableAdapter();
Northwind.ProductsDataTable products;
products = productsAdapter.GetProducts();
foreach (Northwind.ProductsRow productRow in products)
    Response.Write("Product: " + productRow.ProductName + "<br />");

Esse código não exigiu que escrevamos um bit de código específico de acesso a dados. Não foi necessário instanciar nenhuma ADO.NET classes, não precisamos nos referir a nenhuma cadeia de conexão, consultas SQL ou procedimentos armazenados. Em vez disso, o TableAdapter fornece o código de acesso a dados de baixo nível para nós.

Cada objeto usado neste exemplo também é fortemente tipado, permitindo que o Visual Studio forneça intelliSense e verificação de tipo em tempo de compilação. E o melhor de todos os DataTables retornados pelo TableAdapter pode ser associado a ASP.NET controles da Web de dados, como GridView, DetailsView, DropDownList, CheckBoxList e vários outros. O exemplo a seguir ilustra a associação da DataTable retornada pelo método GetProducts() a um GridView em apenas três linhas de código no manipulador de eventos Page_Load .

AllProducts.aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="AllProducts.aspx.cs"
    Inherits="AllProducts" %>
<!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>View All Products in a GridView</title>
    <link href="Styles.css" rel="stylesheet" type="text/css" />
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <h2>
            All Products</h2>
        <p>
            <asp:GridView ID="GridView1" runat="server"
             CssClass="DataWebControlStyle">
               <HeaderStyle CssClass="HeaderStyle" />
               <AlternatingRowStyle CssClass="AlternatingRowStyle" />
            </asp:GridView>
             </p>
    </div>
    </form>
</body>
</html>

AllProducts.aspx.cs

using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using NorthwindTableAdapters;
public partial class AllProducts : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        ProductsTableAdapter productsAdapter = new
         ProductsTableAdapter();
        GridView1.DataSource = productsAdapter.GetProducts();
        GridView1.DataBind();
    }
}

A lista de produtos é exibida em um GridView

Figura 13: a lista de produtos é exibida em um GridView (clique para exibir a imagem em tamanho real)

Embora este exemplo exija que escrevamos três linhas de código no manipulador de eventos Page_Load da página ASP.NET , em tutoriais futuros, examinaremos como usar o ObjectDataSource para recuperar declarativamente os dados do DAL. Com o ObjectDataSource, não precisaremos escrever nenhum código e também obteremos suporte para paginação e classificação!

Etapa 3: Adicionar métodos parametrizados à camada de acesso a dados

Neste ponto, nossa classe ProductsTableAdapter tem apenas um método, GetProducts(), que retorna todos os produtos no banco de dados. Embora a capacidade de trabalhar com todos os produtos seja definitivamente útil, há momentos em que queremos recuperar informações sobre um produto específico ou todos os produtos que pertencem a uma categoria específica. Para adicionar essa funcionalidade à camada de acesso a dados, podemos adicionar métodos parametrizados ao TableAdapter.

Vamos adicionar o método GetProductsByCategoryID(categoryID). Para adicionar um novo método ao DAL, retorne ao DataSet Designer, clique com o botão direito do mouse na seção ProductsTableAdapter e escolha Adicionar Consulta.

Clique com o botão direito do mouse no TableAdapter e escolha Adicionar Consulta

Figura 14: Right-Click no TableAdapter e escolha Adicionar Consulta

Primeiro, somos avisados sobre se queremos acessar o banco de dados usando uma instrução SQL ad hoc ou um procedimento armazenado novo ou existente. Vamos optar por usar uma instrução SQL ad hoc novamente. Em seguida, nos perguntam que tipo de consulta SQL gostaríamos de usar. Como queremos retornar todos os produtos que pertencem a uma categoria especificada, queremos escrever uma instrução SELECT que retorne linhas.

Escolha criar uma instrução SELECT que retorna linhas

Figura 15: Optar por criar uma instrução SELECT que retorna linhas (clique para exibir a imagem em tamanho real)

A próxima etapa é definir a consulta SQL usada para acessar os dados. Como queremos retornar apenas os produtos que pertencem a uma categoria específica, uso a mesma instrução SELECT de GetProducts(), mas adiciono a seguinte cláusula WHERE : WHERE CategoryID = @CategoryID. O parâmetro @CategoryID indica ao assistente TableAdapter que o método que estamos criando exigirá um parâmetro de entrada do tipo correspondente (ou seja, um inteiro anulável).

Insira uma consulta para retornar apenas produtos em uma categoria especificada

Figura 16: Insira uma consulta para retornar apenas produtos em uma categoria especificada (clique para exibir a imagem em tamanho real)

Na etapa final, podemos escolher quais padrões de acesso a dados usar, bem como personalizar os nomes dos métodos gerados. Para o padrão Fill, vamos alterar o nome para FillByCategoryID e, para retornar um padrão de retorno DataTable (os métodos GetX ), vamos usar GetProductsByCategoryID.

Escolher os nomes para os métodos TableAdapter

Figura 17: Escolher os nomes para os métodos TableAdapter (clique para exibir a imagem em tamanho real)

Depois de concluir o assistente, o Designer DataSet inclui os novos métodos TableAdapter.

Os produtos agora podem ser consultados por categoria

Figura 18: Os produtos agora podem ser consultados por categoria

Reserve um momento para adicionar um método GetProductByProductID(productID) usando a mesma técnica.

Essas consultas parametrizadas podem ser testadas diretamente no Designer DataSet. Clique com o botão direito do mouse no método em TableAdapter e escolha Visualizar Dados. Em seguida, insira os valores a serem usados para os parâmetros e clique em Visualizar.

Esses produtos pertencentes à categoria bebidas são mostrados

Figura 19: Esses produtos que pertencem à categoria bebidas são mostrados (clique para exibir imagem em tamanho real)

Com o método GetProductsByCategoryID(categoryID) em nosso DAL, agora podemos criar uma página ASP.NET que exibe apenas esses produtos em uma categoria especificada. O exemplo a seguir mostra todos os produtos que estão na categoria Bebidas, que têm uma CategoryID de 1.

Beverages.asp

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Beverages.aspx.cs"
    Inherits="Beverages" %>
<!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>
    <link href="Styles.css" rel="stylesheet" type="text/css" />
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <h2>Beverages</h2>
        <p>
            <asp:GridView ID="GridView1" runat="server"
             CssClass="DataWebControlStyle">
               <HeaderStyle CssClass="HeaderStyle" />
               <AlternatingRowStyle CssClass="AlternatingRowStyle" />
            </asp:GridView>
             </p>
    </div>
    </form>
</body>
</html>

Beverages.aspx.cs

using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using NorthwindTableAdapters;
public partial class Beverages : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        ProductsTableAdapter productsAdapter = new
         ProductsTableAdapter();
        GridView1.DataSource =
          productsAdapter.GetProductsByCategoryID(1);
        GridView1.DataBind();
    }
}

Esses produtos na categoria bebidas são exibidos

Figura 20: Esses produtos na categoria Bebidas são exibidos (clique para exibir imagem em tamanho real)

Etapa 4: Inserir, atualizar e excluir dados

Há dois padrões comumente usados para inserir, atualizar e excluir dados. O primeiro padrão, que chamarei de padrão direto do banco de dados, envolve a criação de métodos que, quando invocados, emitem um comando INSERT, UPDATE ou DELETE para o banco de dados que opera em um único registro de banco de dados. Esses métodos normalmente são passados em uma série de valores escalares (inteiros, cadeias de caracteres, boolianos, DateTimes e assim por diante) que correspondem aos valores a serem inseridos, atualizados ou excluídos. Por exemplo, com esse padrão para a tabela Products , o método delete assumiria um parâmetro inteiro, indicando o ProductID do registro a ser excluído, enquanto o método insert levaria uma cadeia de caracteres para ProductName, um decimal para UnitPrice, um inteiro para UnitsOnStock e assim por diante.

Cada solicitação de inserção, atualização e exclusão é enviada para o banco de dados imediatamente

Figura 21: cada solicitação de inserção, atualização e exclusão é enviada imediatamente ao banco de dados (clique para exibir a imagem em tamanho real)

O outro padrão, ao qual me referirei como o padrão de atualização em lote, é atualizar um DataSet inteiro, DataTable ou coleção de DataRows em uma chamada de método. Com esse padrão, um desenvolvedor exclui, insere e modifica os DataRows em uma DataTable e, em seguida, passa esses DataRows ou DataTable para um método de atualização. Esse método enumera os DataRows passados, determina se eles foram modificados, adicionados ou excluídos (por meio do valor da propriedade RowState do DataRow) e emite a solicitação de banco de dados apropriada para cada registro.

Todas as alterações são sincronizadas com o banco de dados quando o método update é invocado

Figura 22: Todas as alterações são sincronizadas com o banco de dados quando o método update é invocado (clique para exibir a imagem em tamanho real)

O TableAdapter usa o padrão de atualização em lote por padrão, mas também dá suporte ao padrão direto do BD. Como selecionamos a opção "Gerar instruções Inserir, Atualizar e Excluir" nas Propriedades Avançadas ao criar nosso TableAdapter, o ProductsTableAdapter contém um método Update(), que implementa o padrão de atualização em lote. Especificamente, o TableAdapter contém um método Update() que pode ser passado pelo Typed DataSet, um DataTable fortemente tipado ou um ou mais DataRows. Se você deixou a caixa de seleção "GenerateDBDirectMethods" marcada ao criar pela primeira vez o TableAdapter, o padrão direto do BD também será implementado por meio dos métodos Insert(), Update()e Delete().

Ambos os padrões de modificação de dados usam as propriedades InsertCommand, UpdateCommand e DeleteCommand do TableAdapter para emitir seus comandos INSERT, UPDATE e DELETE para o banco de dados. Você pode inspecionar e modificar as propriedades InsertCommand, UpdateCommand e DeleteCommand clicando no TableAdapter na Designer DataSet e acessando o janela Propriedades. (Verifique se você selecionou o TableAdapter e se o objeto ProductsTableAdapter é o selecionado na lista suspensa no janela Propriedades.)

O TableAdapter tem propriedades InsertCommand, UpdateCommand e DeleteCommand

Figura 23: o TableAdapter tem as propriedades InsertCommand, UpdateCommand e DeleteCommand (clique para exibir a imagem em tamanho real)

Para examinar ou modificar qualquer uma dessas propriedades de comando de banco de dados, clique na subpropriedade CommandText , que abrirá o Construtor de Consultas.

Configurar as instruções INSERT, UPDATE e DELETE no Construtor de Consultas

Figura 24: configurar as instruções INSERT, UPDATE e DELETE no Construtor de Consultas (Clique para exibir a imagem em tamanho real)

O exemplo de código a seguir mostra como usar o padrão de atualização em lote para dobrar o preço de todos os produtos que não foram descontinuados e que têm 25 unidades em estoque ou menos:

NorthwindTableAdapters.ProductsTableAdapter productsAdapter =
  new NorthwindTableAdapters.ProductsTableAdapter();
// For each product, double its price if it is not discontinued and
// there are 25 items in stock or less
Northwind.ProductsDataTable products = productsAdapter.GetProducts();
foreach (Northwind.ProductsRow product in products)
   if (!product.Discontinued && product.UnitsInStock <= 25)
      product.UnitPrice *= 2;
// Update the products
productsAdapter.Update(products);

O código a seguir ilustra como usar o padrão direto do BD para excluir programaticamente um produto específico, atualizar um e, em seguida, adicionar um novo:

NorthwindTableAdapters.ProductsTableAdapter productsAdapter =
    new NorthwindTableAdapters.ProductsTableAdapter();
// Delete the product with ProductID 3
productsAdapter.Delete(3);
// Update Chai (ProductID of 1), setting the UnitsOnOrder to 15
productsAdapter.Update("Chai", 1, 1, "10 boxes x 20 bags",
  18.0m, 39, 15, 10, false, 1);
// Add a new product
productsAdapter.Insert("New Product", 1, 1,
  "12 tins per carton", 14.95m, 15, 0, 10, false);

Criando métodos personalizados de inserção, atualização e exclusão

Os métodos Insert(), Update()e Delete() criados pelo método direto do BD podem ser um pouco complicados, especialmente para tabelas com muitas colunas. Observando o exemplo de código anterior, sem a ajuda do IntelliSense, não está particularmente claro o que a coluna da tabela Products mapeia para cada parâmetro de entrada para os métodos Update() e Insert( ). Pode haver momentos em que queremos apenas atualizar uma ou duas colunas ou desejamos um método Insert() personalizado que, talvez, retorne o valor do campo IDENTITY (incremento automático) do registro recém-inserido.

Para criar esse método personalizado, retorne à Designer DataSet. Clique com o botão direito do mouse no TableAdapter e escolha Adicionar Consulta, retornando ao assistente TableAdapter. Na segunda tela, podemos indicar o tipo de consulta a ser criada. Vamos criar um método que adiciona um novo produto e retorna o valor do ProductID do registro recém-adicionado. Portanto, opte por criar uma consulta INSERT .

Criar um método para adicionar uma nova linha à tabela Products

Figura 25: Criar um método para adicionar uma nova linha à tabela Products (clique para exibir a imagem em tamanho real)

Na tela seguinte, o CommandText de InsertCommand é exibido. Aumente essa consulta adicionando SELECT SCOPE_IDENTITY() no final da consulta, que retornará o último valor de identidade inserido em uma coluna IDENTITY no mesmo escopo. (Consulte a documentação técnica para obter mais informações sobre SCOPE_IDENTITY() e por que você provavelmente deseja usar SCOPE_IDENTITY() em vez de @@IDENTITY.) Certifique-se de encerrar a instrução INSERT com dois-pontos antes de adicionar a instrução SELECT .

Aumentar a consulta para retornar o valor SCOPE_IDENTITY()

Figura 26: Aumentar a consulta para retornar o valor de SCOPE_IDENTITY() (Clique para exibir a imagem em tamanho real)

Por fim, nomeie o novo método InsertProduct.

Definir o nome do novo método como InsertProduct

Figura 27: definir o nome do novo método como InsertProduct (clique para exibir a imagem em tamanho real)

Quando você retornar ao DataSet Designer verá que ProductsTableAdapter contém um novo método, InsertProduct. Se esse novo método não tiver um parâmetro para cada coluna na tabela Produtos , é provável que você tenha esquecido de terminar a instrução INSERT com dois-pontos. Configure o método InsertProduct e verifique se você tem um ponto e vírgula delimitando as instruções INSERT e SELECT .

Por padrão, os métodos de inserção emitem métodos que não são de consulta, o que significa que eles retornam o número de linhas afetadas. No entanto, queremos que o método InsertProduct retorne o valor retornado pela consulta, não o número de linhas afetadas. Para fazer isso, ajuste a propriedade ExecuteMode do método InsertProduct para Scalar.

Alterar a propriedade ExecuteMode para Escalar

Figura 28: alterar a propriedade ExecuteMode para Escalar (Clique para exibir a imagem em tamanho real)

O código a seguir mostra esse novo método InsertProduct em ação:

NorthwindTableAdapters.ProductsTableAdapter productsAdapter =
    new NorthwindTableAdapters.ProductsTableAdapter();
// Add a new product
int new_productID = Convert.ToInt32(productsAdapter.InsertProduct
    ("New Product", 1, 1, "12 tins per carton", 14.95m, 10, 0, 10, false));
// On second thought, delete the product
productsAdapter.Delete(new_productID);

Etapa 5: Concluindo a camada de acesso a dados

Observe que a classe ProductsTableAdapters retorna os valores CategoryID e SupplierID da tabela Products , mas não inclui a coluna CategoryName da tabela Categories ou a coluna CompanyName da tabela Suppliers, embora estas sejam provavelmente as colunas que queremos exibir ao mostrar informações do produto. Podemos aumentar o método inicial do TableAdapter, GetProducts(), para incluir os valores de coluna CategoryName e CompanyName , que atualizarão o DataTable fortemente tipado para incluir essas novas colunas também.

No entanto, isso pode apresentar um problema, pois os métodos do TableAdapter para inserir, atualizar e excluir dados são baseados nesse método inicial. Felizmente, os métodos gerados automaticamente para inserir, atualizar e excluir não são afetados por subconsultas na cláusula SELECT . Ao tomar o cuidado de adicionar nossas consultas a Categorias e Fornecedores como subconsultas, em vez de JOIN , evitaremos a necessidade de refazer esses métodos para modificar dados. Clique com o botão direito do mouse no método GetProducts() em ProductsTableAdapter e escolha Configurar. Em seguida, ajuste a cláusula SELECT para que ela se pareça com:

SELECT     ProductID, ProductName, SupplierID, CategoryID,
QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder, ReorderLevel, Discontinued,
(SELECT CategoryName FROM Categories
WHERE Categories.CategoryID = Products.CategoryID) as CategoryName,
(SELECT CompanyName FROM Suppliers
WHERE Suppliers.SupplierID = Products.SupplierID) as SupplierName
FROM         Products

Atualizar a instrução SELECT para o método GetProducts()

Figura 29: atualizar a instrução SELECT para o método GetProducts() (Clique para exibir a imagem em tamanho real)

Depois de atualizar o método GetProducts() para usar essa nova consulta, a DataTable incluirá duas novas colunas: CategoryName e SupplierName.

A DataTable de Produtos tem duas novas colunas

Figura 30: A DataTable de Produtos tem duas novas colunas

Reserve um momento para atualizar a cláusula SELECT no método GetProductsByCategoryID(categoryID) também.

Se você atualizar a sintaxe GetProducts()SELECT usando JOIN, o Designer do DataSet não poderá gerar automaticamente os métodos para inserir, atualizar e excluir dados de banco de dados usando o padrão direto do BD. Em vez disso, você precisará criá-los manualmente da mesma forma que fizemos com o método InsertProduct anteriormente neste tutorial. Além disso, você precisará fornecer manualmente os valores de propriedade InsertCommand, UpdateCommand e DeleteCommand se quiser usar o padrão de atualização em lote.

Adicionando os TableAdapters restantes

Até agora, só examinamos como trabalhar com um único TableAdapter para uma única tabela de banco de dados. No entanto, o banco de dados Northwind contém várias tabelas relacionadas com as quais precisaremos trabalhar em nosso aplicativo Web. Um Conjunto de Dados Digitado pode conter várias DataTables relacionadas. Portanto, para concluir nosso DAL, precisamos adicionar DataTables para as outras tabelas que usaremos nestes tutoriais. Para adicionar um novo TableAdapter a um Conjunto de Dados Tipado, abra o Designer DataSet, clique com o botão direito do mouse no Designer e escolha Adicionar/TableAdapter. Isso criará um novo DataTable e TableAdapter e orientará você pelo assistente que examinamos anteriormente neste tutorial.

Leve alguns minutos para criar os seguintes métodos e TableAdapters usando as consultas a seguir. Observe que as consultas no ProductsTableAdapter incluem as subconsultas para obter os nomes de categoria e fornecedor de cada produto. Além disso, se você estiver acompanhando, você já adicionou os métodos GetProducts() e GetProductsByCategoryID(categoryID) da classe ProductsTableAdapter.

  • ProductsTableAdapter

    • GetProducts:

      SELECT     ProductID, ProductName, SupplierID, 
      CategoryID, QuantityPerUnit, UnitPrice, UnitsInStock, 
      UnitsOnOrder, ReorderLevel, Discontinued, 
      (SELECT CategoryName FROM Categories WHERE
      Categories.CategoryID = Products.CategoryID) as 
      CategoryName, (SELECT CompanyName FROM Suppliers
      WHERE Suppliers.SupplierID = Products.SupplierID) 
      as SupplierName
      FROM         Products
      
    • GetProductsByCategoryID:

      SELECT     ProductID, ProductName, SupplierID, CategoryID,
      QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder,
      ReorderLevel, Discontinued, (SELECT CategoryName
      FROM Categories WHERE Categories.CategoryID = 
      Products.CategoryID) as CategoryName,
      (SELECT CompanyName FROM Suppliers WHERE
      Suppliers.SupplierID = Products.SupplierID)
      as SupplierName
      FROM         Products
      WHERE      CategoryID = @CategoryID
      
    • GetProductsBySupplierID:

      SELECT     ProductID, ProductName, SupplierID, CategoryID,
      QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder,
      ReorderLevel, Discontinued, (SELECT CategoryName
      FROM Categories WHERE Categories.CategoryID = 
      Products.CategoryID) as CategoryName, 
      (SELECT CompanyName FROM Suppliers WHERE 
      Suppliers.SupplierID = Products.SupplierID) as SupplierName
      FROM         Products
      WHERE SupplierID = @SupplierID
      
    • GetProductByProductID:

      SELECT     ProductID, ProductName, SupplierID, CategoryID,
      QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder,
      ReorderLevel, Discontinued, (SELECT CategoryName 
      FROM Categories WHERE Categories.CategoryID = 
      Products.CategoryID) as CategoryName, 
      (SELECT CompanyName FROM Suppliers WHERE Suppliers.SupplierID = Products.SupplierID) 
      as SupplierName
      FROM         Products
      WHERE ProductID = @ProductID
      
  • CategoriesTableAdapter

    • GetCategories:

      SELECT     CategoryID, CategoryName, Description
      FROM         Categories
      
    • GetCategoryByCategoryID:

      SELECT     CategoryID, CategoryName, Description
      FROM         Categories
      WHERE CategoryID = @CategoryID
      
  • FornecedoresTableAdapter

    • GetSuppliers:

      SELECT     SupplierID, CompanyName, Address,
      City, Country, Phone
      FROM         Suppliers
      
    • GetSuppliersByCountry:

      SELECT     SupplierID, CompanyName, Address,
      City, Country, Phone
      FROM         Suppliers
      WHERE Country = @Country
      
    • GetSupplierBySupplierID:

      SELECT     SupplierID, CompanyName, Address,
      City, Country, Phone
      FROM         Suppliers
      WHERE SupplierID = @SupplierID
      
  • EmployeesTableAdapter

    • GetEmployees:

      SELECT     EmployeeID, LastName, FirstName, Title,
      HireDate, ReportsTo, Country
      FROM         Employees
      
    • GetEmployeesByManager:

      SELECT     EmployeeID, LastName, FirstName, Title, 
      HireDate, ReportsTo, Country
      FROM         Employees
      WHERE ReportsTo = @ManagerID
      
    • GetEmployeeByEmployeeID:

      SELECT     EmployeeID, LastName, FirstName, Title,
      HireDate, ReportsTo, Country
      FROM         Employees
      WHERE EmployeeID = @EmployeeID
      

O conjunto de dados Designer depois que os quatro TableAdapters tiverem sido adicionados

Figura 31: o conjunto de dados Designer depois que os quatro TableAdapters tiverem sido adicionados (clique para exibir a imagem em tamanho real)

Adicionando código personalizado ao DAL

Os TableAdapters e DataTables adicionados ao Conjunto de Dados Tipado são expressos como um arquivo de Definição de Esquema XML (Northwind.xsd). Você pode exibir essas informações de esquema clicando com o botão direito do mouse no arquivo Northwind.xsd no Gerenciador de Soluções e escolhendo Exibir Código.

O arquivo XSD (Definição de Esquema XML) para o Conjunto de Dados Digitado northwinds

Figura 32: o arquivo XSD (Definição de Esquema XML) para o Conjunto de Dados Digitado northwinds (clique para exibir a imagem em tamanho real)

Essas informações de esquema são convertidas em código C# ou Visual Basic em tempo de design quando compiladas ou em runtime (se necessário), momento em que você pode percorrê-la com o depurador. Para exibir esse código gerado automaticamente, vá para a Exibição de Classe e faça drill down para as classes TableAdapter ou Typed DataSet. Se você não vir o Modo de Exibição de Classe na tela, vá para o menu Exibir e selecione-o nela ou clique em Ctrl+Shift+C. Na Exibição de Classe, você pode ver as propriedades, os métodos e os eventos das classes Typed DataSet e TableAdapter. Para exibir o código de um método específico, clique duas vezes no nome do método no Modo de Exibição de Classe ou clique com o botão direito do mouse nele e escolha Ir para Definição.

Inspecione o código gerado automaticamente selecionando Ir para Definição na Exibição de Classe

Figura 33: Inspecionar o código gerado automaticamente selecionando Ir para Definição na Exibição de Classe

Embora o código gerado automaticamente possa ser um ótimo tempo de salvamento, o código geralmente é muito genérico e precisa ser personalizado para atender às necessidades exclusivas de um aplicativo. No entanto, o risco de estender o código gerado automaticamente é que a ferramenta que gerou o código possa decidir que é hora de "regenerar" e substituir suas personalizações. Com o novo conceito de classe parcial do .NET 2.0, é fácil dividir uma classe em vários arquivos. Isso nos permite adicionar nossos próprios métodos, propriedades e eventos às classes geradas automaticamente sem precisar se preocupar com o Visual Studio substituindo nossas personalizações.

Para demonstrar como personalizar o DAL, vamos adicionar um método GetProducts() à classe SuppliersRow . A classe SuppliersRow representa um único registro na tabela Fornecedores ; cada fornecedor pode fornecer zero a muitos produtos, portanto GetProducts() retornará esses produtos do fornecedor especificado. Para fazer isso, crie um novo arquivo de classe na pasta App_Code chamada SuppliersRow.cs e adicione o seguinte código:

using System;
using System.Data;
using NorthwindTableAdapters;
public partial class Northwind
{
    public partial class SuppliersRow
    {
        public Northwind.ProductsDataTable GetProducts()
        {
            ProductsTableAdapter productsAdapter =
             new ProductsTableAdapter();
            return
              productsAdapter.GetProductsBySupplierID(this.SupplierID);
        }
    }
}

Essa classe parcial instrui o compilador de que, ao criar a classe Northwind.SuppliersRow , inclua o método GetProducts() que acabamos de definir. Se você criar seu projeto e retornar ao Modo de Exibição de Classe, verá GetProducts() agora listado como um método northwind.suppliersRow.

O método GetProducts() agora faz parte da classe Northwind.SuppliersRow

Figura 34: O método GetProducts() agora faz parte da classe Northwind.SuppliersRow

O método GetProducts() agora pode ser usado para enumerar o conjunto de produtos para um fornecedor específico, como mostra o seguinte código:

NorthwindTableAdapters.SuppliersTableAdapter suppliersAdapter =
    new NorthwindTableAdapters.SuppliersTableAdapter();
// Get all of the suppliers
Northwind.SuppliersDataTable suppliers =
  suppliersAdapter.GetSuppliers();
// Enumerate the suppliers
foreach (Northwind.SuppliersRow supplier in suppliers)
{
    Response.Write("Supplier: " + supplier.CompanyName);
    Response.Write("<ul>");
    // List the products for this supplier
    Northwind.ProductsDataTable products = supplier.GetProducts();
    foreach (Northwind.ProductsRow product in products)
        Response.Write("<li>" + product.ProductName + "</li>");
    Response.Write("</ul><p> </p>");
}

Esses dados também podem ser exibidos em qualquer um dos ASP. Controles da Web de dados do NET. A página a seguir usa um controle GridView com dois campos:

  • Um BoundField que exibe o nome de cada fornecedor e
  • Um TemplateField que contém um controle BulletedList associado aos resultados retornados pelo método GetProducts() para cada fornecedor.

Examinaremos como exibir esses relatórios master detalhes em tutoriais futuros. Por enquanto, este exemplo foi projetado para ilustrar o uso do método personalizado adicionado à classe Northwind.SuppliersRow .

SuppliersAndProducts.aspx

<%@ Page Language="C#" CodeFile="SuppliersAndProducts.aspx.cs"
    AutoEventWireup="true" Inherits="SuppliersAndProducts" %>
<!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>
    <link href="Styles.css" rel="stylesheet" type="text/css" />
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <h2>
            Suppliers and Their Products</h2>
        <p>
            <asp:GridView ID="GridView1" runat="server"
             AutoGenerateColumns="False"
             CssClass="DataWebControlStyle">
                <HeaderStyle CssClass="HeaderStyle" />
                <AlternatingRowStyle CssClass="AlternatingRowStyle" />
                <Columns>
                    <asp:BoundField DataField="CompanyName"
                      HeaderText="Supplier" />
                    <asp:TemplateField HeaderText="Products">
                        <ItemTemplate>
                            <asp:BulletedList ID="BulletedList1"
                             runat="server" DataSource="<%# ((Northwind.SuppliersRow) ((System.Data.DataRowView) Container.DataItem).Row).GetProducts() %>"
                                 DataTextField="ProductName">
                            </asp:BulletedList>
                        </ItemTemplate>
                    </asp:TemplateField>
                </Columns>
            </asp:GridView>
             </p>
    </div>
    </form>
</body>
</html>

SuppliersAndProducts.aspx.cs

using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using NorthwindTableAdapters;
public partial class SuppliersAndProducts : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        SuppliersTableAdapter suppliersAdapter = new
          SuppliersTableAdapter();
        GridView1.DataSource = suppliersAdapter.GetSuppliers();
        GridView1.DataBind();
    }
}

O nome da empresa do fornecedor está listado na coluna esquerda, seus produtos à direita

Figura 35: o nome da empresa do fornecedor está listado na coluna esquerda, seus produtos à direita (clique para exibir a imagem em tamanho real)

Resumo

Ao criar um aplicativo Web, criar o DAL deve ser uma de suas primeiras etapas, ocorrendo antes de começar a criar sua camada de apresentação. Com o Visual Studio, criar um DAL baseado em Conjuntos de Dados Tipado é uma tarefa que pode ser realizada em 10 a 15 minutos sem escrever uma linha de código. Os tutoriais que avançarão se basearão nesse DAL. No próximo tutorial , definiremos várias regras de negócios e veremos como implementá-las em uma camada lógica de negócios separada.

Programação feliz!

Leitura Adicional

Para obter mais informações sobre os tópicos discutidos neste tutorial, consulte os seguintes recursos:

Treinamento em vídeo sobre tópicos contidos neste Tutorial

Sobre o autor

Scott Mitchell, autor de sete livros do ASP/ASP.NET e fundador da 4GuysFromRolla.com, trabalha com tecnologias da Microsoft Web desde 1998. Scott trabalha como consultor independente, treinador e escritor. Seu último livro é Sams Teach Yourself ASP.NET 2.0 em 24 Horas. Ele pode ser contatado em mitchell@4GuysFromRolla.com. ou através de seu blog, que pode ser encontrado em http://ScottOnWriting.NET.

Agradecimentos Especiais

Esta série de tutoriais foi revisada por muitos revisores úteis. Os principais revisores deste tutorial foram Ron Green, Hilton Giesenow, Dennis Patterson, Liz Shulok, Abel Gomez e Carlos Santos. Interessado em revisar meus próximos artigos do MSDN? Nesse caso, solte-me uma linha em mitchell@4GuysFromRolla.com.