Создание уровня бизнес-логики (VB)
В этом руководстве мы покажем, как централизировать бизнес-правила в уровне бизнес-логики (BLL), который служит посредником для обмена данными между уровнем представления и DAL.
Введение
Уровень доступа к данным (DAL), созданный в первом руководстве , четко отделяет логику доступа к данным от логики представления. Однако, хотя DAL четко отделяет сведения о доступе к данным от уровня представления, он не применяет бизнес-правила, которые могут применяться. Например, для нашего приложения может потребоваться запретить CategoryID
изменение полей Products
или SupplierID
таблицы, если Discontinued
для поля задано значение 1, или применить правила старшинства, запрещающие ситуации, когда сотрудник управляется кем-то, кто был нанят после них. Другой распространенный сценарий заключается в том, что только пользователи с определенной ролью могут удалять продукты или изменять UnitPrice
значение.
В этом руководстве мы посмотрим, как централизовать эти бизнес-правила в уровне бизнес-логики (BLL), который служит посредником для обмена данными между уровнем представления и DAL. В реальном приложении BLL следует реализовать как отдельный проект библиотеки классов; Однако в этих руководствах мы реализуем BLL как серию классов в нашей App_Code
папке, чтобы упростить структуру проекта. На рисунке 1 показаны архитектурные связи между уровнем представления, BLL и DAL.
Рис. 1. BLL отделяет уровень представления от уровня доступа к данным и накладывает бизнес-правила
Вместо создания отдельных классов для реализации бизнес-логики можно также поместить эту логику непосредственно в typed DataSet с разделяемыми классами. Пример создания и расширения typed DataSet см. в первом руководстве.
Шаг 1. Создание классов BLL
Наш BLL будет состоять из четырех классов, по одному для каждого TableAdapter в DAL; каждый из этих классов BLL будет иметь методы для извлечения, вставки, обновления и удаления из соответствующего TableAdapter в DAL, применяя соответствующие бизнес-правила.
Чтобы более четко разделить классы, связанные с DAL и BLL, создадим две вложенные папки в папке App_Code
и DAL
BLL
. Просто щелкните правой кнопкой мыши папку App_Code
в Обозреватель решений и выберите Создать папку. После создания этих двух папок переместите типизированный набор данных, созданный в первом руководстве, во вложенную папку DAL
.
Затем создайте четыре файла класса BLL во вложенной BLL
папке. Для этого щелкните правой BLL
кнопкой мыши вложенную папку, выберите Добавить новый элемент и выберите шаблон Класс. Назовите четыре класса ProductsBLL
, CategoriesBLL
, SuppliersBLL
и EmployeesBLL
.
Рис. 2. Добавление четырех новых классов в папку App_Code
Далее давайте добавим методы к каждому классу, чтобы просто упаковать методы, определенные для TableAdapters из первого учебника. Пока эти методы будут вызываться непосредственно в DAL; Мы вернемся позже, чтобы добавить любую необходимую бизнес-логику.
Примечание
Если вы используете Visual Studio Standard Edition или более поздней версии (то есть вы не используете Visual Web Developer), вы можете при необходимости визуально создать классы с помощью Designer класса. Дополнительные сведения об этой новой функции в Visual Studio см. в блоге о классах Designer.
ProductsBLL
Для класса необходимо добавить в общей сложности семь методов:
GetProducts()
возвращает все продуктыGetProductByProductID(productID)
возвращает продукт с указанным идентификатором продукта.GetProductsByCategoryID(categoryID)
возвращает все продукты из указанной категории.GetProductsBySupplier(supplierID)
возвращает все продукты от указанного поставщикаAddProduct(productName, supplierID, categoryID, quantityPerUnit, unitPrice, unitsInStock, unitsOnOrder, reorderLevel, discontinued)
вставляет новый продукт в базу данных с использованием переданных значений;ProductID
возвращает значение только что вставленной записи.UpdateProduct(productName, supplierID, categoryID, quantityPerUnit, unitPrice, unitsInStock, unitsOnOrder, reorderLevel, discontinued, productID)
обновляет существующий продукт в базе данных с использованием переданных значений; возвращает значениеTrue
, если была обновлена только одна строка;False
в противном случаеDeleteProduct(productID)
удаляет указанный продукт из базы данных.
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
Методы, которые просто возвращают данные GetProducts
, GetProductByProductID
, GetProductsByCategoryID
и GetProductBySuppliersID
, довольно просты, так как они просто вызывают вниз в DAL. Хотя в некоторых сценариях могут существовать бизнес-правила, которые необходимо реализовать на этом уровне (например, правила авторизации на основе вошедшего в систему пользователя или роли, к которой принадлежит пользователь), мы просто оставим эти методы как есть. Для этих методов BLL служит просто прокси-сервером, через который уровень представления обращается к базовым данным из уровня доступа к данным.
Оба AddProduct
метода и UpdateProduct
принимают в качестве параметров значения для различных полей продукта и добавляют новый продукт или обновляют существующий соответственно. Так как многие столбцы Product
таблицы могут принимать NULL
значения (CategoryID
, SupplierID
и UnitPrice
, чтобы назвать несколько), эти входные параметры для AddProduct
и UpdateProduct
, сопоставленные с такими столбцами, используют типы, допускающие значение NULL. Типы, допускающие значение NULL, являются новыми для .NET 2.0 и предоставляют метод определения того, должен ли тип значения иметь Nothing
значение . Дополнительные сведения см. в записи блога Пола ВикаThe Truth About Null Types and VB и технической документации по структуре, допускаемой значения NULL .
Все три метода возвращают логическое значение, указывающее, была ли строка вставлена, обновлена или удалена, так как операция может не привести к созданию затронутой строки. Например, если разработчик страницы вызывает передачу ProductID
для несуществующего продукта, инструкция, выданная для базы данных, DELETE
не будет влиять, и, следовательно, DeleteProduct
метод вернет False
.DeleteProduct
Обратите внимание, что при добавлении нового продукта или обновлении существующего мы принимаем значения полей нового или измененного продукта в виде списка скаляров, а не как для принятия экземпляра ProductsRow
. Этот подход был выбран, так как ProductsRow
класс является производным от класса ADO.NET DataRow
, который не имеет конструктора без параметров по умолчанию. Чтобы создать новый ProductsRow
экземпляр, необходимо сначала создать ProductsDataTable
экземпляр, а затем вызвать его NewProductRow()
метод (что мы делаем в AddProduct
). Этот недостаток переползает, когда мы переходим к вставке и обновлению продуктов с помощью ObjectDataSource. Короче говоря, ObjectDataSource попытается создать экземпляр входных параметров. Если метод BLL ожидает ProductsRow
экземпляр, ObjectDataSource попытается создать его, но завершится сбоем из-за отсутствия конструктора без параметров по умолчанию. Дополнительные сведения об этой проблеме см. в следующих двух публикациях на форумах ASP.NET: Обновление ObjectDataSources с помощью Strongly-Typed DataSets и Проблема с ObjectDataSource и Strongly-Typed DataSet.
Затем в AddProduct
и UpdateProduct
код создает ProductsRow
экземпляр и заполняет его только что переданными значениями. При назначении значений DataColumns dataRow могут выполняться различные проверки на уровне поля. Таким образом, помещение переданных значений вручную обратно в DataRow помогает обеспечить допустимость данных, передаваемых в метод BLL. К сожалению, строго типизированные классы DataRow, созданные Visual Studio, не используют типы, допускаемые значением NULL. Вместо этого, чтобы указать, что определенный объект DataColumn в DataRow должен соответствовать значению NULL
базы данных, необходимо использовать SetColumnNameNull()
метод .
В UpdateProduct
первую очередь мы загружаем в продукт для обновления с помощью GetProductByProductID(productID)
. Хотя это может показаться ненужным путешествием в базу данных, эта дополнительная поездка окажется полезной в будущих руководствах, в которые рассматривается оптимистичный параллелизм. Оптимистичный параллелизм — это метод, гарантирующий, что два пользователя, одновременно работающие с одними и теми же данными, случайно не перезаписывают изменения друг друга. Захват всей записи также упрощает создание методов обновления в BLL, которые изменяют только подмножество столбцов DataRow. При изучении SuppliersBLL
класса мы увидим такой пример.
Наконец, обратите внимание, что к классу ProductsBLL
применен атрибут DataObject ( [System.ComponentModel.DataObject]
синтаксис прямо перед оператором класса в верхней части файла), а методы имеют атрибуты DataObjectMethodAttribute. Атрибут помечает DataObject
класс как объект, подходящий для привязки к элементу управления ObjectDataSource, тогда как DataObjectMethodAttribute
указывает назначение метода . Как мы увидим в будущих руководствах, ASP.NET ObjectDataSource 2.0 упрощает декларативный доступ к данным из класса. Чтобы упростить фильтрацию списка возможных классов для привязки в мастере ObjectDataSource, по умолчанию в раскрывающемся списке мастера отображаются только те классы, которые помечены как DataObjects
. Класс ProductsBLL
будет работать так же хорошо и без этих атрибутов, но их добавление упрощает работу с мастером ObjectDataSource.
Добавление других классов
ProductsBLL
После завершения класса нам по-прежнему нужно добавить классы для работы с категориями, поставщиками и сотрудниками. Уделите немного времени, чтобы создать следующие классы и методы, используя основные понятия из приведенного выше примера:
CategoriesBLL.cs
GetCategories()
GetCategoryByCategoryID(categoryID)
SuppliersBLL.cs
GetSuppliers()
GetSupplierBySupplierID(supplierID)
GetSuppliersByCountry(country)
UpdateSupplierAddress(supplierID, address, city, country)
EmployeesBLL.cs
GetEmployees()
GetEmployeeByEmployeeID(employeeID)
GetEmployeesByManager(managerID)
Один метод, который стоит отметить, SuppliersBLL
— это метод класса UpdateSupplierAddress
. Этот метод предоставляет интерфейс для обновления только сведений об адресе поставщика. Внутренне этот метод считывает объект SupplierDataRow
для указанного supplierID
(с помощью GetSupplierBySupplierID
), задает его свойства, связанные с адресом, а затем вызывает метод .SupplierDataTable
Update
Метод UpdateSupplierAddress
выглядит следующим образом:
<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
См. сведения о полной реализации классов BLL в этой статье.
Шаг 2. Доступ к типизированным наборам данных с помощью классов BLL
В первом руководстве мы видели примеры работы с типизированным набором данных программным способом, но с добавлением классов BLL уровень представления должен работать с BLL. AllProducts.aspx
В примере из первого руководства ProductsTableAdapter
для привязки списка продуктов к GridView использовался , как показано в следующем коде:
Dim productsAdapter As New ProductsTableAdapter()
GridView1.DataSource = productsAdapter.GetProducts()
GridView1.DataBind()
Чтобы использовать новые классы BLL, необходимо только изменить первую строку кода, просто замените ProductsTableAdapter
объект ProductBLL
объектом :
Dim productLogic As New ProductsBLL()
GridView1.DataSource = productLogic.GetProducts()
GridView1.DataBind()
Классы BLL также можно получить декларативно (как и typed DataSet) с помощью ObjectDataSource. Мы рассмотрим ObjectDataSource более подробно в следующих руководствах.
Рис. 3. Список продуктов отображается в GridView (щелкните для просмотра полноразмерного изображения)
Шаг 3. Добавление проверки Field-Level в классы DataRow
Проверка на уровне полей — это проверки, относящиеся к значениям свойств бизнес-объектов при вставке или обновлении. Ниже перечислены некоторые правила проверки на уровне полей для продуктов.
- Длина
ProductName
поля не должна превышать 40 символов. - Длина
QuantityPerUnit
поля не должна превышать 20 символов. - Поля
ProductID
,ProductName
иDiscontinued
являются обязательными, но все остальные поля являются необязательными - Поля
UnitPrice
,UnitsInStock
,UnitsOnOrder
иReorderLevel
должны быть больше или равны нулю.
Эти правила могут и должны быть выражены на уровне базы данных. Ограничение символов ProductName
в полях и QuantityPerUnit
фиксируется типами данных этих столбцов в Products
таблице (nvarchar(40)
и nvarchar(20)
соответственно). Указывает, являются ли поля обязательными и необязательными, можно ли использовать столбцы таблицы NULL
базы данных. Существует четыре ограничения проверка, которые гарантируют, что только значения, превышающие или равные нулю, могут попасть в UnitPrice
столбцы , UnitsInStock
, UnitsOnOrder
или ReorderLevel
.
Помимо применения этих правил в базе данных они также должны применяться на уровне DataSet. На самом деле длина поля и то, является ли значение обязательным или необязательным, уже записаны для набора DataColumns каждой таблицы DataTable. Чтобы просмотреть существующую проверку на уровне полей автоматически, перейдите на Designer DataSet, выберите поле из одной из данных DataTables и перейдите к окно свойств. Как показано на рисунке QuantityPerUnit
4, dataColumn в объекте ProductsDataTable
имеет максимальную длину 20 символов и допускает NULL
значения. При попытке ProductsDataRow
QuantityPerUnit
задать для свойства строковое значение, превышающее 20 символовArgumentException
, будет выдано значение .
Рис. 4. DataColumn предоставляет базовую проверку Field-Level (щелкните для просмотра полноразмерного изображения)
К сожалению, мы не можем указать проверки границ, например UnitPrice
значение должно быть больше или равно нулю через окно свойств. Чтобы обеспечить этот тип проверки на уровне поля, необходимо создать обработчик события ColumnChanging в DataTable. Как упоминалось в предыдущем руководстве, объекты DataSet, DataTables и DataRow, созданные typed DataSet, можно расширить с помощью разделяемых классов. С помощью этого метода можно создать ColumnChanging
обработчик событий для ProductsDataTable
класса . Начните с создания класса в папке App_Code
с именем ProductsDataTable.ColumnChanging.vb
.
Рис. 5. Добавление нового класса в папку App_Code
(щелкните для просмотра полноразмерного изображения)
Затем создайте обработчик событий для ColumnChanging
события, который гарантирует, что UnitPrice
значения столбцов , UnitsInStock
, UnitsOnOrder
и ReorderLevel
(если нет NULL
) больше или равны нулю. Если какой-либо из таких столбцов выходит за пределы диапазона, создайте исключение ArgumentException
.
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
Шаг 4. Добавление пользовательских бизнес-правил в классы BLL
В дополнение к проверке на уровне полей могут существовать высокоуровневые настраиваемые бизнес-правила, включающие различные сущности или понятия, которые не могут быть выражены на уровне одного столбца, например:
- Если продукт недоступен, его
UnitPrice
нельзя обновить - Страна проживания сотрудника должна совпадать со страной проживания руководителя
- Продукт не может быть прекращен, если он является единственным продуктом, предоставляемым поставщиком
Классы BLL должны содержать проверки для соблюдения бизнес-правил приложения. Эти проверки можно добавлять непосредственно в методы, к которым они применяются.
Представьте, что наши бизнес-правила диктуют, что продукт не может быть помечен как снятый, если он был единственным продуктом от данного поставщика. То есть, если продукт X был единственным продуктом, приобретенным у поставщика Y, мы не могли бы пометить X как снятый с производства; Если, однако, поставщик Y поставил нам три продукта: A, B и C, то мы могли бы пометить все и все из них как снятые с производства. Нечетное бизнес-правило, но бизнес-правила и здравый смысл не всегда согласованы!
Чтобы применить это бизнес-правило в UpdateProducts
методе, мы сначала проверим, задано True
ли Discontinued
значение , и если да, мы вызовемGetProductsBySupplierID
, чтобы определить, сколько продуктов мы приобрели у поставщика этого продукта. Если у этого поставщика приобретен только один продукт, мы выдаем .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
Реагирование на ошибки проверки на уровне представления
При вызове BLL с уровня представления мы можем решить, следует ли обрабатывать исключения, которые могут быть вызваны, или разрешить их пузырьков до ASP.NET (что вызовет HttpApplication
Error
событие ). Чтобы обработать исключение при работе с BLL программным способом, можно использовать try... Блок Catch , как показано в следующем примере:
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
Как мы увидим в будущих руководствах, обработка исключений, которые возникают из BLL при использовании веб-элемента управления данными для вставки, обновления или удаления данных, может обрабатываться непосредственно в обработчике событий, а не в Try...Catch
блоки.
Сводка
Хорошо спроектированное приложение состоит из отдельных слоев, каждый из которых инкапсулирует определенную роль. В первом руководстве этой серии статей мы создали уровень доступа к данным с помощью типизированных наборов данных; В этом руководстве мы создали уровень бизнес-логики в виде ряда классов в папке приложения App_Code
, которые вызываются в DAL. BLL реализует логику уровня поля и бизнес-уровня для нашего приложения. Помимо создания отдельного BLL, как мы делали в этом руководстве, еще одним вариантом является расширение методов TableAdapters за счет использования разделяемых классов. Однако использование этого метода не позволяет нам переопределить существующие методы и не разделяет DAL и BLL так же четко, как мы использовали в этой статье.
После завершения DAL и BLL мы готовы начать работу с уровнем презентации. В следующем руководстве мы кратко рассмотрим разделы, посвященные доступу к данным, и определим согласованный макет страницы для использования во всех руководствах.
Счастливого программирования!
Об авторе
Скотт Митчелл( Scott Mitchell), автор семи книг ASP/ASP.NET и основатель 4GuysFromRolla.com, работает с веб-технологиями Майкрософт с 1998 года. Скотт работает независимым консультантом, тренером и писателем. Его последняя книга Sams Teach Yourself ASP.NET 2.0 в 24 часах. Он может быть доступен в mitchell@4GuysFromRolla.com. или через его блог, который можно найти по адресу http://ScottOnWriting.NET.
Особая благодарность
Эта серия учебников была рассмотрена многими полезными рецензентами. Ведущим рецензентом этого руководства были Лиз Шулок, Деннис Паттерсон, Карлос Сантос и Хилтон Гисенов. Хотите просмотреть предстоящие статьи MSDN? Если да, опустите мне строку на mitchell@4GuysFromRolla.com.