Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
por Scott Mitchell
Neste tutorial, veremos como centralizar suas regras de negócios em uma camada de lógica de negócios (BLL) que serve como intermediário para a troca de dados entre a camada de apresentação e o DAL.
Introdução
A camada de acesso a dados (DAL) criada no primeiro tutorial separa claramente a lógica de acesso a dados da lógica de apresentação. No entanto, embora a DAL separa claramente os detalhes de acesso a dados da camada de apresentação, ela não impõe nenhuma regra de negócios que possa ser aplicada. Por exemplo, para a nossa aplicação, podemos querer não permitir que os campos CategoryID ou SupplierID da tabela Products sejam modificados quando o campo Discontinued estiver definido como 1, ou podemos querer impor regras de antiguidade, evitando situações em que um funcionário seja gerido por alguém que foi contratado depois dele. Outro cenário comum é a autorização, talvez apenas usuários em uma função específica possam excluir produtos ou alterar o UnitPrice valor.
Neste tutorial, veremos como centralizar essas regras de negócios em uma camada de lógica de negócios (BLL) que serve como intermediária para a troca de dados entre a camada de apresentação e o DAL. Em um aplicativo do mundo real, a BLL deve ser implementada como um projeto separado de Biblioteca de Classes; no entanto, para estes tutoriais, implementaremos o BLL como uma série de classes em nossa App_Code pasta, a fim de simplificar a estrutura do projeto. A Figura 1 ilustra as relações arquitetônicas entre a camada de apresentação, BLL e DAL.
Figura 1: A BLL separa a camada de apresentação da camada de acesso a dados e impõe regras de negócios
Em vez de criar classes separadas para implementar nossa lógica de negócios, poderíamos alternativamente colocar essa lógica diretamente no DataSet Tipado com classes parciais. Para ver um exemplo de como criar e estender um DataSet Tipado, consulte o primeiro tutorial.
Etapa 1: Criação das classes BLL
Nossa BLL será composta por quatro classes, uma para cada TableAdapter no DAL; cada uma dessas classes BLL terá métodos para recuperar, inserir, atualizar e excluir do respetivo TableAdapter no DAL, aplicando as regras de negócios apropriadas.
Para separar mais claramente as classes relacionadas a DAL e BLL, vamos criar duas subpastas na App_Code pasta DAL e BLL. Basta clicar com o botão direito do App_Code mouse na pasta no Gerenciador de Soluções e escolher Nova Pasta. Depois de criar essas duas pastas, mova o DataSet Tipado criado no primeiro tutorial para a DAL subpasta.
Em seguida, crie os quatro arquivos de classe BLL na BLL subpasta. Para fazer isso, clique com o botão direito do BLL mouse na subpasta, escolha Adicionar um Novo Item e escolha o modelo de Classe. Nomeie as quatro classes ProductsBLL, CategoriesBLL, SuppliersBLL, e EmployeesBLL.
Figura 2: Adicionar quatro novas classes à App_Code pasta
Em seguida, vamos adicionar métodos a cada uma das classes para simplesmente encapsular os métodos definidos para os TableAdapters do primeiro tutorial. Por enquanto, esses métodos apenas chamarão diretamente o DAL; Voltaremos mais tarde para adicionar qualquer lógica de negócios necessária.
Observação
Se você estiver usando o Visual Studio Standard Edition ou superior (ou seja, você não estiver usando o Visual Web Developer), você pode, opcionalmente, projetar suas classes visualmente usando o Class Designer. Consulte o Blog do Class Designer para obter mais informações sobre esse novo recurso no Visual Studio.
Para a classe, ProductsBLL precisamos adicionar um total de sete métodos:
-
GetProducts()retorna todos os produtos -
GetProductByProductID(productID)devolve o produto com o ID do produto especificado -
GetProductsByCategoryID(categoryID)Devolve todos os produtos da categoria especificada -
GetProductsBySupplier(supplierID)Devolve todos os produtos do fornecedor especificado -
AddProduct(productName, supplierID, categoryID, quantityPerUnit, unitPrice, unitsInStock, unitsOnOrder, reorderLevel, discontinued)insere um novo produto na base de dados utilizando os valores passados; Devolve oProductIDvalor do registo recém-inserido -
UpdateProduct(productName, supplierID, categoryID, quantityPerUnit, unitPrice, unitsInStock, unitsOnOrder, reorderLevel, discontinued, productID)atualiza um produto existente no banco de dados usando os valores passados; retornaTruese precisamente uma linha foi atualizada,Falsecaso contrário -
DeleteProduct(productID)Exclui o produto especificado do banco de dados
ProductsBLL.vb
Imports NorthwindTableAdapters
<System.ComponentModel.DataObject()> _
Public Class ProductsBLL
Private _productsAdapter As ProductsTableAdapter = Nothing
Protected ReadOnly Property Adapter() As ProductsTableAdapter
Get
If _productsAdapter Is Nothing Then
_productsAdapter = New ProductsTableAdapter()
End If
Return _productsAdapter
End Get
End Property
<System.ComponentModel.DataObjectMethodAttribute _
(System.ComponentModel.DataObjectMethodType.Select, True)> _
Public Function GetProducts() As Northwind.ProductsDataTable
Return Adapter.GetProducts()
End Function
<System.ComponentModel.DataObjectMethodAttribute _
(System.ComponentModel.DataObjectMethodType.Select, False)> _
Public Function GetProductByProductID(ByVal productID As Integer) _
As Northwind.ProductsDataTable
Return Adapter.GetProductByProductID(productID)
End Function
<System.ComponentModel.DataObjectMethodAttribute _
(System.ComponentModel.DataObjectMethodType.Select, False)> _
Public Function GetProductsByCategoryID(ByVal categoryID As Integer) _
As Northwind.ProductsDataTable
Return Adapter.GetProductsByCategoryID(categoryID)
End Function
<System.ComponentModel.DataObjectMethodAttribute _
(System.ComponentModel.DataObjectMethodType.Select, False)> _
Public Function GetProductsBySupplierID(ByVal supplierID As Integer) _
As Northwind.ProductsDataTable
Return Adapter.GetProductsBySupplierID(supplierID)
End Function
<System.ComponentModel.DataObjectMethodAttribute _
(System.ComponentModel.DataObjectMethodType.Insert, True)> _
Public Function AddProduct( _
productName As String, supplierID As Nullable(Of Integer), _
categoryID As Nullable(Of Integer), quantityPerUnit As String, _
unitPrice As Nullable(Of Decimal), unitsInStock As Nullable(Of Short), _
unitsOnOrder As Nullable(Of Short), reorderLevel As Nullable(Of Short), _
discontinued As Boolean) _
As Boolean
Dim products As New Northwind.ProductsDataTable()
Dim product As Northwind.ProductsRow = products.NewProductsRow()
product.ProductName = productName
If Not supplierID.HasValue Then
product.SetSupplierIDNull()
Else
product.SupplierID = supplierID.Value
End If
If Not categoryID.HasValue Then
product.SetCategoryIDNull()
Else
product.CategoryID = categoryID.Value
End If
If quantityPerUnit Is Nothing Then
product.SetQuantityPerUnitNull()
Else
product.QuantityPerUnit = quantityPerUnit
End If
If Not unitPrice.HasValue Then
product.SetUnitPriceNull()
Else
product.UnitPrice = unitPrice.Value
End If
If Not unitsInStock.HasValue Then
product.SetUnitsInStockNull()
Else
product.UnitsInStock = unitsInStock.Value
End If
If Not unitsOnOrder.HasValue Then
product.SetUnitsOnOrderNull()
Else
product.UnitsOnOrder = unitsOnOrder.Value
End If
If Not reorderLevel.HasValue Then
product.SetReorderLevelNull()
Else
product.ReorderLevel = reorderLevel.Value
End If
product.Discontinued = discontinued
products.AddProductsRow(product)
Dim rowsAffected As Integer = Adapter.Update(products)
Return rowsAffected = 1
End Function
<System.ComponentModel.DataObjectMethodAttribute _
(System.ComponentModel.DataObjectMethodType.Update, True)> _
Public Function UpdateProduct(_
productName As String, supplierID As Nullable(Of Integer), _
categoryID As Nullable(Of Integer), quantityPerUnit As String, _
unitPrice As Nullable(Of Decimal), unitsInStock As Nullable(Of Short), _
unitsOnOrder As Nullable(Of Short), reorderLevel As Nullable(Of Short), _
discontinued As Boolean, productID As Integer) _
As Boolean
Dim products As Northwind.ProductsDataTable = _
Adapter.GetProductByProductID(productID)
If products.Count = 0 Then
Return False
End If
Dim product as Northwind.ProductsRow = products(0)
product.ProductName = productName
If Not supplierID.HasValue Then
product.SetSupplierIDNull()
Else
product.SupplierID = supplierID.Value
End If
If Not categoryID.HasValue Then
product.SetCategoryIDNull()
Else
product.CategoryID = categoryID.Value
End If
If quantityPerUnit Is Nothing Then
product.SetQuantityPerUnitNull()
Else
product.QuantityPerUnit = quantityPerUnit
End If
If Not unitPrice.HasValue Then
product.SetUnitPriceNull()
Else
product.UnitPrice = unitPrice.Value
End If
If Not unitsInStock.HasValue Then
product.SetUnitsInStockNull()
Else
product.UnitsInStock = unitsInStock.Value
End If
If Not unitsOnOrder.HasValue Then
product.SetUnitsOnOrderNull()
Else
product.UnitsOnOrder = unitsOnOrder.Value
End If
If Not reorderLevel.HasValue Then
product.SetReorderLevelNull()
Else
product.ReorderLevel = reorderLevel.Value
End If
product.Discontinued = discontinued
Dim rowsAffected As Integer = Adapter.Update(product)
Return rowsAffected = 1
End Function
<System.ComponentModel.DataObjectMethodAttribute _
(System.ComponentModel.DataObjectMethodType.Delete, True)> _
Public Function DeleteProduct(ByVal productID As Integer) As Boolean
Dim rowsAffected As Integer = Adapter.Delete(productID)
Return rowsAffected = 1
End Function
End Class
Os métodos que simplesmente retornam dados GetProducts, GetProductByProductID, GetProductsByCategoryID e GetProductBySuppliersID são bastante diretos, pois fazem chamadas para o DAL. Embora em alguns cenários possa haver regras de negócios que precisam ser implementadas nesse nível (como regras de autorização com base no usuário conectado no momento ou na função à qual o usuário pertence), simplesmente deixaremos esses métodos as-is. Para esses métodos, então, a BLL serve meramente como um proxy através do qual a camada de apresentação acessa os dados subjacentes da camada de acesso a dados.
Os AddProduct métodos e UpdateProduct tomam como parâmetros os valores para os vários campos de produto e adicionam um novo produto ou atualizam um existente, respectivamente. Dado que muitas colunas da tabela podem aceitar valores como Product, NULL, e CategoryID (para mencionar alguns), os parâmetros de entrada de SupplierID e UnitPrice que se associam a essas colunas utilizam AddProduct. Os tipos anuláveis são novos no .NET 2.0 e fornecem uma técnica para indicar se um tipo de valor deve, em vez disso, ser Nothing. Consulte a entrada do blog de Paul VickThe Truth About Nullable Types and VB e a documentação técnica da estrutura Nullable para obter mais informações.
Todos os três métodos retornam um valor booleano indicando se uma linha foi inserida, atualizada ou excluída, pois a operação pode não resultar em uma linha afetada. Por exemplo, se o desenvolvedor da página chamar DeleteProduct ao passar um ProductID para um produto inexistente, a instrução DELETE emitida para o banco de dados não terá qualquer efeito e, portanto, o método DeleteProduct retornará False.
Observe que, ao adicionar um novo produto ou atualizar um existente, tomamos os valores de campo do produto novo ou modificado como uma lista de escalares, em vez de aceitar uma ProductsRow instância. Essa abordagem foi escolhida porque a ProductsRow classe deriva da classe ADO.NET DataRow , que não tem um construtor sem parâmetros padrão. Para criar uma nova ProductsRow instância, devemos primeiro criar uma ProductsDataTable instância e, em seguida, invocar seu NewProductRow() método (o que fazemos em AddProduct). Essa limitação se manifesta quando recorremos para inserir e atualizar produtos usando o ObjectDataSource. Em resumo, o ObjectDataSource tentará criar uma instância dos parâmetros de entrada. Se o método BLL espera uma ProductsRow instância, o ObjectDataSource tentará criar uma, mas falhará devido à falta de um construtor sem parâmetro padrão. Para obter mais informações sobre esse problema, consulte as seguintes duas postagens de fóruns ASP.NET: Atualizando ObjectDataSources com Strongly-Typed DataSets e Problema com ObjectDataSource e Strongly-Typed DataSet.
Em seguida, em ambos AddProduct e UpdateProduct, o código cria uma instância de ProductsRow e preenche-a com os valores acabados de passar. Ao atribuir valores a DataColumns de um DataRow, várias verificações de validação em nível de campo podem ocorrer. Portanto, colocar manualmente os valores passados de volta em um DataRow ajuda a garantir a validade dos dados que estão sendo passados para o método BLL. Infelizmente, as classes DataRow fortemente tipadas que são geradas pelo Visual Studio não utilizam tipos anuláveis. Em vez disso, para indicar que um determinado DataColumn em um DataRow deve corresponder a um NULL valor de banco de dados, devemos usar o SetColumnNameNull() método.
Primeiro, carregamos o produto em UpdateProduct para atualizar usando GetProductByProductID(productID). Embora isso possa parecer uma viagem desnecessária ao banco de dados, essa viagem extra valerá a pena em futuros tutoriais que exploram a simultaneidade otimista. A simultaneidade otimista é uma técnica para garantir que dois usuários que estão trabalhando simultaneamente nos mesmos dados não substituam acidentalmente as alterações um do outro. Pegar o registro inteiro também facilita a criação de métodos de atualização na BLL que modificam apenas um subconjunto das colunas do DataRow. Quando explorarmos a SuppliersBLL classe, veremos tal exemplo.
Finalmente, observe que a ProductsBLL classe tem o atributo DataObject aplicado a ela (a sintaxe [System.ComponentModel.DataObject] logo antes da instrução de classe, perto do topo do arquivo) e os métodos têm atributos DataObjectMethodAttribute. O DataObject atributo marca a classe como sendo um objeto adequado para ligação a um controle ObjectDataSource, enquanto o DataObjectMethodAttribute indica a finalidade do método. Como veremos em tutoriais futuros, o ObjectDataSource do ASP.NET 2.0 facilita o acesso declarativo a dados de uma classe. Para ajudar a filtrar a lista de possíveis classes para vincular no assistente do ObjectDataSource, apenas as classes marcadas como DataObjects são mostradas, por padrão, na lista suspensa do assistente. A ProductsBLL classe funcionará tão bem sem esses atributos, mas adicioná-los facilita o trabalho no assistente do ObjectDataSource.
Adicionando as outras classes
Com a ProductsBLL classe completa, ainda precisamos adicionar as classes para trabalhar com categorias, fornecedores e funcionários. Reserve um momento para criar as seguintes classes e métodos usando os conceitos do exemplo acima:
CategoriesBLL.cs
GetCategories()GetCategoryByCategoryID(categoryID)
SuppliersBLL.cs
GetSuppliers()GetSupplierBySupplierID(supplierID)GetSuppliersByCountry(country)UpdateSupplierAddress(supplierID, address, city, country)
EmployeesBLL.cs
GetEmployees()GetEmployeeByEmployeeID(employeeID)GetEmployeesByManager(managerID)
O único método que vale a pena notar é o método da classe SuppliersBLLUpdateSupplierAddress. Este método fornece uma interface para atualizar apenas as informações de endereço do fornecedor. Internamente, esse método lê o objeto SupplierDataRow para o especificado supplierID (usando GetSupplierBySupplierID), define as suas propriedades relacionadas ao endereço e, em seguida, chama o método SupplierDataTable de Update. O UpdateSupplierAddress método é o seguinte:
<System.ComponentModel.DataObjectMethodAttribute _
(System.ComponentModel.DataObjectMethodType.Update, True)> _
Public Function UpdateSupplierAddress(ByVal supplierID As Integer, _
ByVal address As String, ByVal city As String, ByVal country As String) _
As Boolean
Dim suppliers As Northwind.SuppliersDataTable = _
Adapter.GetSupplierBySupplierID(supplierID)
If suppliers.Count = 0 Then
Return False
Else
Dim supplier As Northwind.SuppliersRow = suppliers(0)
If address Is Nothing Then
supplier.SetAddressNull()
Else
supplier.Address = address
End If
If city Is Nothing Then
supplier.SetCityNull()
Else
supplier.City = city
End If
If country Is Nothing Then
supplier.SetCountryNull()
Else
supplier.Country = country
End If
Dim rowsAffected As Integer = Adapter.Update(supplier)
Return rowsAffected = 1
End If
End Function
Consulte o download deste artigo para minha implementação completa das classes BLL.
Etapa 2: Acessando os conjuntos de dados digitados por meio das classes BLL
No primeiro tutorial, vimos exemplos de trabalho direto com o DataSet tipado programaticamente, mas com a adição de nossas classes BLL, a camada de apresentação deve funcionar contra a BLL em vez disso.
AllProducts.aspx No exemplo do primeiro tutorial, o ProductsTableAdapter foi usado para vincular a lista de produtos a um GridView, conforme mostrado no código a seguir:
Dim productsAdapter As New ProductsTableAdapter()
GridView1.DataSource = productsAdapter.GetProducts()
GridView1.DataBind()
Para usar as novas classes BLL, tudo o que precisa ser alterado é a primeira linha de código simplesmente substituir o ProductsTableAdapter objeto por um ProductBLL objeto:
Dim productLogic As New ProductsBLL()
GridView1.DataSource = productLogic.GetProducts()
GridView1.DataBind()
As classes BLL também podem ser acessadas declarativamente (assim como o Typed DataSet) usando o ObjectDataSource. Discutiremos o ObjectDataSource com mais detalhes nos tutoriais a seguir.
Figura 3: A lista de produtos é exibida em um GridView (Clique para visualizar a imagem em tamanho real)
Etapa 3: Adicionando validação de Field-Level às classes DataRow
A validação ao nível de campo é uma verificação que pertence aos valores de propriedade dos objetos de negócios durante a inserção ou atualização. Algumas regras de validação em nível de campo para produtos incluem:
- O
ProductNamecampo deve ter 40 caracteres ou menos - O
QuantityPerUnitcampo deve ter 20 caracteres ou menos - Os campos
ProductID,ProductName, eDiscontinuedsão obrigatórios, mas todos os outros campos são opcionais. - Os campos
UnitPrice,UnitsInStock,UnitsOnOrdereReorderLeveldevem ser maiores ou iguais a zero
Estas regras podem e devem ser expressas ao nível da base de dados. O limite de caracteres nos ProductName campos e QuantityPerUnit é capturado pelos tipos de dados dessas colunas na Products tabela (nvarchar(40) e nvarchar(20), respectivamente). Se os campos são obrigatórios ou opcionais é determinado por a coluna da tabela do banco de dados permitir NULL s. Existem quatro restrições de verificação que garantem que apenas valores maiores ou iguais a zero possam entrar nas UnitPricecolunas , UnitsInStock, UnitsOnOrder, ou ReorderLevel .
Além de aplicar essas regras no banco de dados, elas também devem ser aplicadas no nível do DataSet. Na verdade, o comprimento do campo e se um valor é necessário ou opcional já são capturados para cada conjunto DataTable de DataColumns. Para ver a validação de nível de campo existente fornecida automaticamente, vá para o DataSet Designer, selecione um campo de uma das DataTables e vá para a janela Propriedades. Como mostra a Figura 4, o QuantityPerUnit DataColumn no ProductsDataTable tem um comprimento máximo de 20 caracteres e permite valores NULL. Se tentarmos definir a propriedade ProductsDataRow de QuantityPerUnit para um valor de texto maior do que 20 caracteres, será lançado um ArgumentException.
Figura 4: O DataColumn fornece validação básica de Field-Level (Clique para visualizar a imagem em tamanho real)
Infelizmente, não podemos especificar verificações de limites, como o valor UnitPrice deve ser maior ou igual a zero, pela janela de propriedades. Para fornecer esse tipo de validação em nível de campo, precisamos criar um manipulador de eventos para o evento ColumnChanging de DataTable . Conforme mencionado no tutorial anterior, os objetos DataSet, DataTables e DataRow criados pelo Typed DataSet podem ser estendidos por meio do uso de classes parciais. Usando essa técnica, podemos criar um manipulador de ColumnChanging eventos para a ProductsDataTable classe. Comece criando uma classe na App_Code pasta chamada ProductsDataTable.ColumnChanging.vb.
Figura 5: Adicionar uma nova classe à pasta (App_Code imagem em tamanho real)
Em seguida, crie um manipulador de eventos para o evento ColumnChanging que garanta que os valores das colunas UnitPrice, UnitsInStock, UnitsOnOrder e ReorderLevel (se não NULL) sejam maiores ou iguais a zero. Se alguma dessas colunas estiver fora do intervalo, lance um ArgumentExceptionarquivo .
ProductsDataTable.ColumnChanging.vb
Imports System.data
Partial Public Class Northwind
Partial Public Class ProductsDataTable
Public Overrides Sub BeginInit()
AddHandler Me.ColumnChanging, AddressOf ValidateColumn
End Sub
Sub ValidateColumn(sender As Object, e As DataColumnChangeEventArgs)
If e.Column.Equals(Me.UnitPriceColumn) Then
If Not Convert.IsDBNull(e.ProposedValue) AndAlso _
CType(e.ProposedValue, Decimal) < 0 Then
Throw New ArgumentException( _
"UnitPrice cannot be less than zero", "UnitPrice")
End If
ElseIf e.Column.Equals(Me.UnitsInStockColumn) OrElse _
e.Column.Equals(Me.UnitsOnOrderColumn) OrElse _
e.Column.Equals(Me.ReorderLevelColumn) Then
If Not Convert.IsDBNull(e.ProposedValue) AndAlso _
CType(e.ProposedValue, Short) < 0 Then
Throw New ArgumentException(String.Format( _
"{0} cannot be less than zero", e.Column.ColumnName), _
e.Column.ColumnName)
End If
End If
End Sub
End Class
End Class
Etapa 4: Adicionando regras de negócios personalizadas às classes da BLL
Além da validação em nível de campo, pode haver regras de negócios personalizadas de alto nível que envolvem diferentes entidades ou conceitos não expressáveis no nível de uma única coluna, como:
- Se um produto for descontinuado, não poderá
UnitPriceser atualizado - O país de residência de um trabalhador deve ser o mesmo que o país de residência do seu gestor
- Um produto não pode ser descontinuado se for o único produto fornecido pelo fornecedor
As classes BLL devem conter verificações para garantir a aderência às regras de negócios do aplicativo. Estas verificações podem ser adicionadas diretamente aos métodos a que se aplicam.
Imagine que as nossas regras comerciais determinam que um produto não pode ser marcado como descontinuado se for o único produto de um determinado fornecedor. Ou seja, se o produto X fosse o único produto que compramos do fornecedor Y, não poderíamos marcar X como descontinuado; se, no entanto, o fornecedor Y nos fornecesse três produtos, A, B e C, então poderíamos marcar todo e qualquer um deles como descontinuado. Uma regra de negócio estranha, mas as regras de negócio e o bom senso nem sempre estão alinhados!
Para aplicar essa regra de negócios no UpdateProducts método, começaríamos verificando se Discontinued estava definido para True e, em caso afirmativo, ligaríamos GetProductsBySupplierID para determinar quantos produtos compramos do fornecedor desse produto. Se apenas um produto for comprado a este fornecedor, lançamos um ApplicationException.
<System.ComponentModel.DataObjectMethodAttribute_
(System.ComponentModel.DataObjectMethodType.Update, True)> _
Public Function UpdateProduct( _
productName As String, supplierID As Nullable(Of Integer), _
categoryID As Nullable(Of Integer), quantityPerUnit As String, _
unitPrice As Nullable(Of Decimal), unitsInStock As Nullable(Of Short), _
unitsOnOrder As Nullable(Of Short), reorderLevel As Nullable(Of Short), _
discontinued As Boolean, productID As Integer) _
As Boolean
Dim products As Northwind.ProductsDataTable = _
Adapter.GetProductByProductID(productID)
If products.Count = 0 Then
Return False
End If
Dim product As Northwind.ProductsRow = products(0)
If discontinued Then
Dim productsBySupplier As Northwind.ProductsDataTable = _
Adapter.GetProductsBySupplierID(product.SupplierID)
If productsBySupplier.Count = 1 Then
Throw New ApplicationException( _
"You cannot mark a product as discontinued if it is " & _
"the only product purchased from a supplier")
End If
End If
product.ProductName = productName
If Not supplierID.HasValue Then
product.SetSupplierIDNull()
Else
product.SupplierID = supplierID.Value
End If
If Not categoryID.HasValue Then
product.SetCategoryIDNull()
Else
product.CategoryID = categoryID.Value
End If
If quantityPerUnit Is Nothing Then
product.SetQuantityPerUnitNull()
Else
product.QuantityPerUnit = quantityPerUnit
End If
If Not unitPrice.HasValue Then
product.SetUnitPriceNull()
Else
product.UnitPrice = unitPrice.Value
End If
If Not unitsInStock.HasValue Then
product.SetUnitsInStockNull()
Else
product.UnitsInStock = unitsInStock.Value
End If
If Not unitsOnOrder.HasValue Then
product.SetUnitsOnOrderNull()
Else
product.UnitsOnOrder = unitsOnOrder.Value
End If
If Not reorderLevel.HasValue Then
product.SetReorderLevelNull()
Else
product.ReorderLevel = reorderLevel.Value
End If
product.Discontinued = discontinued
Dim rowsAffected As Integer = Adapter.Update(product)
Return rowsAffected = 1
End Function
Respondendo a erros de validação na camada de apresentação
Ao chamar a Camada de Lógica de Negócios (BLL) a partir da camada de apresentação, podemos decidir se tentamos lidar com quaisquer exceções que possam ser levantadas ou deixá-las propagar-se até ao ASP.NET (que irá gerar o evento HttpApplicationError). Para lidar com uma exceção ao trabalhar programaticamente com a BLL, podemos usar um bloco Try...Catch, como mostra o exemplo a seguir:
Dim productLogic As New ProductsBLL()
Try
productLogic.UpdateProduct("Scotts Tea", 1, 1, Nothing, _
-14, 10, Nothing, Nothing, False, 1)
Catch ae As ArgumentException
Response.Write("There was a problem: " & ae.Message)
End Try
Como veremos em tutoriais futuros, o tratamento de exceções que surgem da BLL ao usar um controlo de dados da Web para inserir, atualizar ou excluir dados pode ser feito diretamente num manipulador de eventos, em vez de encapsular o código em blocos Try...Catch.
Resumo
Um aplicativo bem arquitetado é criado em camadas distintas, cada uma das quais encapsula uma função específica. No primeiro tutorial desta série de artigos, criámos uma camada de acesso a dados usando Typed DataSets; neste tutorial, construímos uma camada de lógica de negócios como uma série de classes na pasta da nossa aplicação App_Code, que fazem chamadas ao nosso DAL. A BLL implementa a lógica de campo e de negócios para a nossa aplicação. Além de criar uma BLL separada, como fizemos neste tutorial, outra opção é estender os métodos TableAdapters através do uso de classes parciais. No entanto, o uso dessa técnica não nos permite substituir os métodos existentes nem separa nossa DAL e nossa BLL de forma tão limpa quanto a abordagem que adotamos neste artigo.
Com o DAL e o BLL concluídos, estamos prontos para começar a nossa camada de apresentação. No próximo tutorial , faremos um breve desvio dos tópicos de acesso a dados e definiremos um layout de página consistente para uso ao longo dos tutoriais.
Feliz Programação!
Sobre o Autor
Scott Mitchell, autor de sete livros sobre ASP/ASP.NET e fundador da 4GuysFromRolla.com, trabalha com tecnologias Web da Microsoft desde 1998. Scott trabalha como consultor, formador e escritor independente. Seu último livro é Sams Teach Yourself ASP.NET 2.0 in 24 Hours. Ele pode ser contatado em mitchell@4GuysFromRolla.com.
Um agradecimento especial a
Esta série de tutoriais foi revisada por muitos revisores úteis. Os principais revisores deste tutorial foram Liz Shulok, Dennis Patterson, Carlos Santos e Hilton Giesenow. Interessado em rever meus próximos artigos do MSDN? Se for o caso, envie-me uma mensagem para mitchell@4GuysFromRolla.com.