• Nenhum resultado encontrado

Criação de uma DAL com Typed DataSets

N/A
N/A
Protected

Academic year: 2021

Share "Criação de uma DAL com Typed DataSets"

Copied!
13
0
0

Texto

(1)

Criação de uma DAL com Typed DataSets

Do tutorial: “Creating a Data Access Layer” de Scott Mitchell

http://www.asp.net/data-access/tutorials/creating-a-data-access-layer-cs

1. Abrir o Projecto Base

Duplo clique no ficheiro .sln

Já está adicionada a base de dados NORTHWIND.MDF ao App_Data Alternativa: criação desta versão inicial do programa (Projecto Base) (Step 1 do Tutorial)

A.Criar uma Solução

File > New Project… > Other Project Types > Visual Studio Solutions > Blank Solution > TutorialDALeBLL

B.Adicionar à solução uma Aplicação Web

Na Solução : Add > New Web Site… > ASP.NET Empty Web Site WebSite

C.Adicionar à Aplicação Web a base de dados NORTHWND.MDF: No Projecto WebSite Add ASP.NET Folder > App_Data

No App-Data Add Existing Item… > NORTHWND.MDF

D.Adicionar à Aplicação Web 4 páginas: AllProducts.aspx

Beverages.aspx NewProduct.aspx

(2)

Colocar em cada página um cabeçalho, escrever o texto, seleccioná-lo, e clicar em Heading 1 <h1>.

A seguir ao cabeçalho, colocar um controlo GridView, e em GridView Tasks, AutoFormat… seleccionar um esquema de formatação.

E.Adicionar à solução uma Class Library para a camada de acesso a dados: DAL Na Solução : Add > New Project… > (Visual C#) Class Library DAL Apagar a classe Class1.cs automaticamente adicionada à Class Library DAL.

F. Adicionar à Aplicação Web uma referência para a Class Library DAL

2. Adicione um Typed DataSet (Step 2 do Tutorial)

Na Class library DAL Add New Item… > DataSet Northwind.xsd (Adiciona o dataSet à class library DAL)

O ficheiro Northwind.xsd abre em modo Design, visualizando-se a janela DataSet Designer.

O dataSet fortemente tipado adicionado ao Projecto DAL não inclui informação sobre como aceder aos dados de qualquer tabela da base de dados. Essa informação irá estar contida nos tableAdapters.

Um dataSet tipado é composto de instâncias dataTable tipadas, cada uma das quais é composta de instâncias dataRow tipadas. Para colocar cada instância dataTable no dataSet é necessário um objecto de uma classe TableAdapter. Cada tableAdapter possui vários métodos para selecção de dados de uma dada tabela da base de dados e também métodos para actualização desses dados. Os dados retribuídos por cada método povoam um dataTable dentro do dataSet.

3. Adicione TableAdapters

Verifique o conteúdo do ficheiro web.config, o qual não contém qualquer elemento connectionStrings.

No Server Explorer, expandir a base de dados e arrastar 3 tabelas da base de dados, Categories, Products e Suppliers:

Categories(CategoryID, CategoryName, Description, Picture) Products(ProductID, ProductName, SupplierID, CategoryID,

QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder, ReorderLevel, Discontinued)

Suppliers(SupplierID, CompanyName, ContactName, ContactTitle, Address, City, Region, PostalCode, Country, Phone, Fax, HomePage)

(3)

Verifique agora o conteúdo do ficheiro app.config criado automaticamente na class library, o qual já contém o elemento connectionStrings, com uma connectionString para a base de dados.

O DataSet Designer cria 3 tableAdapters, um para cada tabela, com os nomes CategoriesTableAdapter

PoductsTableAdapter SuppliersTableAdapter.

Estes tableAdapters são criados dentro do namespace NorthwindTableAdapters. Estas classes TableAdapter permitem criar objectos que representam a ligação e comandos usados para retribuir e gravar dados.

Cada um dos tableAdapters criados automaticamente pelo DataSet Designer já possui 2 métodos para retribuir os dados das respectivas tabelas, com os seguintes nomes: Fill – este método recebe um dataTable como parâmetro e preenche-o com os dados da tabela da base de dados.

GetData - este método não recebe qualquer parâmetro e retorna um dataTable povoado com os dados da tabela da base de dados.

Cada tableAdapter também cria os métodos Insert, Update e Delete para inserir, actualizar e apagar registos individuais na respectiva tabela.

Na Class Library DAL faça

Build > Build Solution

4. Visualize o Código gerado automaticamente

Este passo destina-se apenas a visualizar o código gerado automaticamente pelo Visual Studio para as classes DataSet tipada e TableAdapters:

Visualizando directamente com Class View no Visual Studio

Os TableAdapters e DataTables adicionados ao Typed DataSet são expressos em XML Schema Definition.

Pode visualizar este documento seleccionando Northwind.xsd no Solution Explorer e escolhendo Open With… XML (Text) Editor.

Para ver o código C# gerado automaticamente faça View > Class View. Pode ver propriedades, métodos e eventos das classes Typed DataSet e TableAdapter. Para ver o código de um método particular faça duplo clique no nome do método ou seleccione Go To Definition a partir do nome do método.

Neste caso de um dataSet adicionado a uma classe library, o código C# gerado está no ficheiro Northwind.Designer.cs mostrado na janela do Solution Explorer.

(4)

5. Liste todos os registos da tabela Products

Para preencher as tabelas do dataSet Northwind, o DataSet Designer criou tableAdapters, com os nomes CategoriesTableAdapter,

ProductsTableAdapter, e SupliersTableAdapter.

Estes tableAdapters são criados dentro de um namespace com o nome

NorthwindTableAdapters.

No WebSite adicionar uma referência para a Class library: Add Reference… > DAL (Projects)

Build > Build Solution

Dá erro na página SuppliersAndProducts.aspx. Excluí-la do Projecto Build > Build Solution

Adicione à página AllProducts.aspx o seguinte código no Page_Load: protected void Page_Load(object sender, EventArgs e) { DAL.NorthwindTableAdapters.ProductsTableAdapter taProd = new DAL.NorthwindTableAdapters.ProductsTableAdapter(); GridView1.DataSource = taProd.GetData(); GridView1.DataBind(); //DAL.Northwind.ProductsDataTable dtProd = // new DAL.Northwind.ProductsDataTable(); //taProd.Fill(dtProd); //GridView1.DataSource = dtProd; //GridView1.DataBind(); }

Adicione mais uma página (ListarProdutos.aspx) ao Web Site e coloque o seguinte código no Page_Load:

protected void Page_Load(object sender, EventArgs e) { DAL.NorthwindTableAdapters.ProductsTableAdapter taProd =

new DAL.NorthwindTableAdapters.ProductsTableAdapter(); DAL.Northwind.ProductsDataTable tabelaProd = taProd.GetData();

foreach (DAL.Northwind.ProductsRow row in tabelaProd) Response.Write("Id = " + row.ProductID +

" Nome do Produto = " + row.ProductName + "<br />"); }

6. Liste todos os registos da tabela Products da Categoria Beverages CategoryID = 1

Adicione os métodos parametrizados (Step 3 do Tutorial) GetProductsByCategoryID(IdCategoria), e

(5)

GetProductsByProductID(IdProduto)

Estes métodos devem ser adicionados ao tableAdapter ProductsTableAdapter. No DataSet Designer, com o botão direito do rato na secção ProductsTableAdapter seleccione: Add > Query…

Use SQL Statements Next SELECT which returns rows Next

Complete a instrucção SQL a usar para aceder aos dados, adicionando a cláusula WHERE

SELECT ProductID, ProductName, SupplierID, CategoryID, QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder, ReorderLevel, Discontinued FROM dbo.Products

WHERE CategoryID = @CategoryID

O parâmetro @CategoryID indica que o método necessita de um parâmetro de entrada

do tipo CategoryID.

No último passo escolhe-se o padrão de acesso a usar (Fill e/ou GetData) assim como o nome dos métodos. Altere os nomes para:

FillProductsByCategoryID, e GetProductsByCategoryID.

Depois de premir Finish o DataSet Designer inclui os novos métodos no tableAdapter. Teste estes métodos listando numa página (Beverages.aspx) todos os produtos da categoria Beverages.

protected void Page_Load(object sender, EventArgs e) { DAL.NorthwindTableAdapters.ProductsTableAdapter taProd = new DAL.NorthwindTableAdapters.ProductsTableAdapter(); GridView1.DataSource = taProd.GetProductsByCategoryID(); GridView1.DataBind();

}

Adicione o método GetProductsByProductID(int ProductID) usando a mesma técnica.

7. Inserir, Actualizar e Apagar Dados (Step 4 do Tutorial) Existem 2 padrões para inserir, actualizar e apagar dados:

• Um padrão cria métodos INSERT, UPDATE e DELETE em que a execução de cada método altera apenas um único registo da base de dados.

• O outro padrão cria métodos UPDATE com um parâmetro - um DataSet, um DataTable ou uma colecção de DataRows - em que a execução de um qualquer destes método actualiza os dados da tabela na base de dados, podendo alterar múltiplos registos da base de dados.

(6)

Para a tabela Products a classe ProductsTableAdapter possui os seguintes métodos:

public int Update(DataSet1.ProductsDataTable dataTable) public int Update(DataSet1 dataSet)

public int Update(DataRow[] dataRows) public int Delete(int Original_ProductID)

public int Insert(string ProductName, int SupplierID,

int CategoryID, string QuantityPerUnit, decimal UnitPrice, short UnitsInStock, short UnitsOnOrder, short ReorderLevel, bool Discontinued)

public int Update(string ProductName, int SupplierID,

int CategoryID, string QuantityPerUnit, decimal UnitPrice, short UnitsInStock, short UnitsOnOrder, short ReorderLevel, bool Discontinued, int Original_ProductID)

Estes métodos podem ser inspeccionados e modificados clicando no TableAdapter apresentado no DataSet Designer e seleccionando Properties.

Na janela Properties seleccionar o tableAdapter no drop-down list.

Expandir os métodos DeleteCommand, InsertCommand, SelectCommand, e UpdateCommand para visualizar a sub-propriedade CommandText.

Para modificar clicar na Propriedade CommandText, surgindo a janela Query Builder.

Teste estes métodos adicionando uma página (AlterarPrecosProdutos.aspx) que permita alterar o preço de todos os produtos da Categoria 2:

Double factor = . . . ;

DAL.NorthwindTableAdapters.ProductsTableAdapter taProd =

new DAL.NorthwindTableAdapters.ProductsTableAdapter(); DAL.Northwind.ProductsDataTable tabelaProd = taProd.GetData();

foreach (DAL.Northwind.ProductsRow row in tabelaProd)

if (row.CategoryID == 2) Response.Write(

row.ProductName + " Preco:" + row.UnitPrice + "<br />");

foreach (DAL.Northwind.ProdutosRow row in tabelaProd)

if (row.CategoryID == 2) row.UnitPrice *= factor; // Actualiza a tabela Produtos

taProd.Update(tabelaProd);

foreach (DAL.Northwind.ProductsRow row in tabelaProd)

if (row.CategoryID == 2) Response.Write(

row.ProductName + " Preco:" + row.UnitPrice + "<br />");

Teste o método Insert, construindo uma interface gráfica adequada na página NewProduct.aspx:

protected void Button1_Click(object sender, EventArgs e) {

string nomePoduto = TextBox1.Text;

int idFornecedor = int.Parse(TextBox2.Text); int idCategoria = int.Parse(TextBox3.Text); string quantidade = TextBox4.Text;

decimal precoUnitario = decimal.Parse(TextBox5.Text); short stock = short.Parse(TextBox6.Text);

(7)

short quantEncomendada = short.Parse(TextBox7.Text); short nivel = short.Parse(TextBox8.Text);

bool descontinuado = false;

DAL.NorthwindTableAdapters.ProductsTableAdapter tableAdapterProd =

new DAL.NorthwindTableAdapters.ProductsTableAdapter();

int n = tableAdapterProd.Insert(nomePoduto, idFornecedor, idCategoria, quantidade, precoUnitario, stock, quantEncomendada, nivel, descontinuado);

TextBox10.Text = n.ToString(); }

8. Criar Métodos Insert, Update e Delete específicos

Vamos criar um método para inserir um registo e retornar o valor do campo IDENTITY auto-gerado pela base de dados.

No DataSet Designer, com o botão direito do rato na secção ProductsTableAdapter seleccione: Add > Query…

Use SQL Statements Next

INSERT Next

Termine a instrução SQL com ponto e vírgula e acrescente no fim: SELECT SCOPE_IDENTITY(), para retornar o último valor identity.

INSERT INTO [dbo].[Products] ([ProductName], [SupplierID], [CategoryID], [QuantityPerUnit], [UnitPrice], [UnitsInStock],

[UnitsOnOrder], [ReorderLevel], [Discontinued]) VALUES (@ProductName, @SupplierID, @CategoryID, @QuantityPerUnit, @UnitPrice, @UnitsInStock, @UnitsOnOrder, @ReorderLevel, @Discontinued);

SELECT SCOPE IDENTITY();

Function Name: InserirProduto Finish.

Verificar que o tableAdapter ProductsTableAdapter contém um novo método, InserirProduto.

Por omissão, os métodos Insert são executados pelo método ExecuteNonQuery, o qual retorna o número de linhas afectadas. Contudo nós pretendemos que o método

InserirProduto retorne o valor retornado pela query, e não o número de linhas afectadas. Para isso temos de alterar a propriedade ExecuteMode de NonQuery para Scalar.

Teste este método, utilizando a interface gráfica da página NewProduct.aspx

protected void Button1_Click(object sender, EventArgs e) {

string nomePoduto = TextBox1.Text;

int idFornecedor = int.Parse(TextBox2.Text); int idCategoria = int.Parse(TextBox3.Text); string quantidade = TextBox4.Text;

(8)

short stock = short.Parse(TextBox6.Text);

short quantEncomendada = short.Parse(TextBox7.Text); short nivel = short.Parse(TextBox8.Text);

bool descontinuado = false;

DAL.NorthwindTableAdapters.ProductsTableAdapter tableAdapterProd =

new DAL.NorthwindTableAdapters.ProductsTableAdapter();

int n = tableAdapterProd.InserirProduto(nomePoduto, idFornecedor, idCategoria, quantidade, precoUnitario, stock, quantEncomendada, nivel, descontinuado);

TextBox10.Text = n.ToString(); }

9. Uso de Subqueries na cláusula Select

O tableAdapter ProductsTableAdapter retorna os valores CategoryID da tabela Products, mas não inclui o CategoryName (Nome da Categoria) da tabela Categories, embora esta coluna seja mais significativa para mostrar informações de cada produto. Podemos aumentar o método GetData() gerado automaticamente para incluir os valores de CategoryName.

Se usarmos um JOIN para modificar o SELECT do método GetData() o DataSet Designer não será capaz de gerar automaticamente os métodos Insert, Update, e Delete usados para alterar registos individuais na Base de Dados. Teremos que os criar

manualmente tal como fizemos com o método InserirProduto().

Também teremos de escrever os valores das propriedades InsertCommand,

UpdateCommand, e DeleteCommand para usar o método Update do tableAdpter para alterar múltiplos resgistos a partir de um DataSet.

Se usarmos Subqueries na cláusula Select os métodos gerados automaticamente não serão afectados.

Seleccione os métodos Fill e GetData do tableAdapter ProductsTableAdapter e prima Configure…

A seguir ajuste a cláusula Select

SELECT ProductID, ProductName, SupplierID, CategoryID, QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder, ReorderLevel, Discontinued FROM dbo.Products

Para:

SELECT ProductID, ProductName, SupplierID, CategoryID,

(SELECT CategoryName FROM Categories WHERE Categories.CategoryID = Products.CategoryID) as CategoryName,

QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder, ReorderLevel, Discontinued FROM dbo.Products

(9)

10. Adicionar Código Específico ao Código Gerado Automaticamente

Por vezes o código gerado automaticamente necessita de ser alterado para fornecer as necessidades de uma aplicação.

Se alterássemos directamente o código, essas alterações poderiam ser pagadas por uma nova geração automática de código efectuada pelo Visual Studio.

Com o conceito de classes parciais é fácil separar uma classe por múltiplos ficheiros. Isto permite-nos adicionar código às classes geradas automaticamente.

Vamos adicionar o método GetProducts() à classe SuppliersRow. A classe

SuppliersRow representa um único registo na tabela Suppliers. O método GetProducts() deverá retornar os produtos de um fornecedor (registo da tabela Suppliers) particular. Para isso crie uma nova classe (ficheiro SuppliersRow.cs) no directório DAL e adicione o seguinte código:

namespace DAL {

public partial class Northwind {

public partial class SuppliersRow {

public Northwind.ProductsDataTable GetProducts() {

NorthwindTableAdapters.ProductsTableAdapter tableAdapterProd =

new NorthwindTableAdapters.ProductsTableAdapter();

return tableAdapterProd.GetProductsBySupplierID(this.SupplierID); }

} } }

Adicione o método GetProductsBySupplierID ao tableAdapter ProductsTableAdapter.

Recompile a class library DAL.

Teste o método GetProducts() da classe CategoriesRow.

Utilize a página SuppliersAndProducts.aspx para listar os nomes dos Suppliers e os nomes dos Produtos de cada Supplier. Inclua novamente a página no Projecto. Esta página usa um GridView com 2 campos:

• Um BoundField que mostra o nome da Categoria.

• Um TemplateField que contém o controlo BulletedList que lista os resultados retornados pelo método GetProducts() para cada Suplier.

Alterar:

DataSource='<%#

((DAL.Northwind.SuppliersRow)((System.Data.DataRowView) Container.DataItem).Row).GetProducts() %>'

(10)

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='<%# ((DAL.Northwind.SuppliersRow) ((System.Data.DataRowView)Container.DataItem).Row).GetProducts() %>' DataTextField="ProductName"> </asp:BulletedList> </ItemTemplate> </asp:TemplateField> </Columns> </asp:GridView>

Na página SuppliersAndProducts.aspx para listar os nomes dos Suppliers coloque:

public partial class SuppliersAndProducts : System.Web.UI.Page {

protected void Page_Load(object sender, EventArgs e) {

DAL.NorthwindTableAdapters.SuppliersTableAdapter taSuppliers = new DAL.NorthwindTableAdapters.SuppliersTableAdapter();

GridView1.DataSource = taSuppliers.GetData(); GridView1.DataBind();

} }

Criação de uma BLL com Typed DataSets

Do tutorial: “Creating a Business Logic Layer” de Scott Mitchell

http://www.asp.net/data-access/tutorials/creating-a-business-logic-layer-cs

11. Adicionar à solução uma Class Library para a camada de lógica de negócio: BLL

Na Solução : Add > New Project… > (Visual C#) Class Library BLL Apagar a classe Class1.cs automaticamente adicionada à Class Library BLL. Adicionar à Class Library BLL uma referência para a Class Library DAL

12. Adicionar classes à BLL

BLL Add New Item… > Class CategoriesBLL.cs

ProductsBLL.cs SuppliersBLL.cs

(11)

CategoriesBLL.cs

public class CategoriesBLL {

private NorthwindTableAdapters.CategoriesTableAdapter taCat = null;

protected NorthwindTableAdapters.CategoriesTableAdapter Adapter {

get {

if (taCat == null)

taCat = new NorthwindTableAdapters.CategoriesTableAdapter(); return taCat;

} }

public Northwind.CategoriesDataTable GetCategories() {

return Adapter.GetCategories(); }

}

ProductsBLL.cs

public class ProductsBLL {

private NorthwindTableAdapters.ProductsTableAdapter taProd = null;

protected NorthwindTableAdapters.ProductsTableAdapter Adapter {

get {

if (taProd == null) taProd =

new NorthwindTableAdapters.ProductsTableAdapter();

return taProd; }

}

public Northwind.ProductsDataTable GetProducts() {

return Adapter.GetProducts(); }

public Northwind.ProductsDataTable GetProductByProductID(

int productID) { return Adapter.GetProductByProductID(productID);

}

public Northwind.ProductsDataTable GetProductsByCategoryID(

int categoryID) { return Adapter.GetProductsByCategoryID(categoryID);

}

public Northwind.ProductsDataTable GetProductsBySupplierID(

int supplierID) { return Adapter.GetProductsBySupplierID(supplierID);

}

public bool InsertProduct(string productName, int supplierID, int categoryID, string quantityPerUnit, decimal unitPrice, short unitsInStock, short unitsOnOrder, short reorderLevel, bool discontinued) {

int rowsAffected = Adapter.Insert(productName, supplierID, categoryID, quantityPerUnit, unitPrice, unitsInStock, unitsOnOrder, reorderLevel, discontinued);

// Retorna true se exactamente umalinha é inserida, senao false return rowsAffected == 1;

(12)

}

SuppliersBLL.cs

public class SuppliersBLL {

private NorthwindTableAdapters.SuppliersTableAdapter taSup = null;

protected NorthwindTableAdapters.SuppliersTableAdapter Adapter {

get {

if (taSup == null) taSup =

new NorthwindTableAdapters.SuppliersTableAdapter();

return taSup; }

}

public Northwind.SuppliersDataTable GetSuppliers() {

return Adapter.GetSuppliers(); }

}

13. Alterar o Código das Páginas aspx

Apagar a Referência da Aplicação Web à Class Library DAL: remova o directório Bin existente na Aplicação Web WebSite.

Adicionar à Aplicação Web uma referência para a Class Library BLL. O código da páginas aspx deve invocar funcionalidades da Camada BLL.

AllProducts.aspx

public partial class AllProducts : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { ProductsBLL produtos = new ProductsBLL();

GridView1.DataSource = produtos.GetProducts(); GridView1.DataBind();

} }

Beverages.aspx

public partial class Beverages : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { ProductsBLL produtos = new ProductsBLL();

GridView1.DataSource = produtos.GetProductsByCategoryID(1); GridView1.DataBind();

} }

(13)

NewProduct.aspx

public partial class NewProduct : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { }

protected void Button1_Click(object sender, EventArgs e) { string nomePoduto = TextBox1.Text;

int iDFornecedor = int.Parse(TextBox2.Text); int idCategoria = int.Parse(TextBox3.Text); string quantidade = TextBox4.Text;

decimal precoUnitario = decimal.Parse(TextBox5.Text); short stock = short.Parse(TextBox6.Text);

short quantEncomendada = short.Parse(TextBox7.Text); short nivel = short.Parse(TextBox8.Text);

bool descontinuado = false;

ProductsBLL produtos = new ProductsBLL(); bool b =

produtos.InsertProduct(nomePoduto, iDFornecedor, idCategoria, quantidade, precoUnitario, stock, quantEncomendada, nivel, descontinuado);

TextBox10.Text = b.ToString(); }

}

Referências

Documentos relacionados

Ele pretende ficar com uma dúzia de laranjas e distribuir o restante, igualmente, em 10 lotes.?. a) Quantas laranjas esse comerciante possui

Acreditando na força da leitura literária para pensar a vida e sonhar um país e um mundo melhor, como diria Bartolomeu Campos de Queirós, trazemos neste último Notícias do ano e já

- contáveis: elementos que se podem contar e que, por isso, assumem a forma singular ou plural. - não contáveis: elementos que não se podem contar distintamente e que assumem,

a) O polícia disse um palavrão, após ter saído da casa de Adrian. Corrige as falsas.. A mãe também está com gripe. “Quase que não consegui ficar calado quando vi que não

Eles variam em género (masculino e feminino), número (singular e plural) e grau (normal, diminutivo e aumentativo).. As subclasses

O Ebitda não é uma medida utilizada nas práticas contábeis adotadas no Brasil, não representando o fluxo de caixa para os períodos apresentados e não deve ser

Nas duas páginas seguintes, por fileira: tres fotos do ensaio da Citizen K do inverno 2009; foto do motoqueiro da revista Flair de abril 2008 - uma das primeiras borradas que eu vi

O trecho de solo exposto é classificado em Estado Geoambiental Instável, pois além da alteração das propriedades originais da área, pode contribuir com a