Заметка
Доступ к этой странице требует авторизации. Вы можете попробовать войти в систему или изменить каталог.
Доступ к этой странице требует авторизации. Вы можете попробовать сменить директорию.
В этом руководстве мы посмотрим, как централизировать бизнес-правила на уровне бизнес-логики (BLL), который служит посредником для обмена данными между уровнем презентации и DAL.
Введение
Уровень доступа к данным (DAL), созданный в первом руководстве , четко отделяет логику доступа к данным от логики презентации. Однако, хотя DAL чисто отделяет сведения о доступе к данным от слоя презентации, он не применяет какие-либо бизнес-правила, которые могут применяться. Например, для нашего приложения может потребоваться запретить изменение полей CategoryID или SupplierID в таблице Products, если для поля Discontinued задано значение 1, или нам может потребоваться применить правила иерархии, запрещая ситуации, когда сотрудником управляет тот, кто был нанят позже него. Другой распространенный сценарий — авторизация, возможно, только пользователи определенной роли могут удалять продукты или изменять UnitPrice значение.
В этом руководстве мы посмотрим, как централизировать эти бизнес-правила в уровне бизнес-логики (BLL), который служит посредником для обмена данными между уровнем презентации и DAL. В реальном приложении BLL следует реализовать как отдельный проект библиотеки классов; Однако для этих учебников мы реализуем BLL в виде ряда классов в нашей App_Code папке, чтобы упростить структуру проекта. Рисунок 1 иллюстрирует архитектурные связи между уровнем презентации, BLL и DAL.
Рис. 1. BLL отделяет уровень презентации от уровня доступа к данным и накладывает бизнес-правила
Вместо создания отдельных классов для реализации бизнес-логики можно также поместить эту логику непосредственно в типизированный набор данных с частичными классами. Пример создания и расширения типизированного набора данных см. в первом руководстве.
Шаг 1. Создание классов BLL
Наш BLL будет состоять из четырех классов, по одному для каждого TableAdapter в DAL; каждый из этих классов BLL будет иметь методы для получения, вставки, обновления и удаления из соответствующего TableAdapter в DAL, применяя соответствующие бизнес-правила.
Чтобы более четко разделить классы, связанные с DAL и BLL, давайте создадим две вложенные папки в папке App_CodeDAL и BLL. Щелкните правой кнопкой мыши App_Code папку в обозревателе решений и выберите команду "Создать папку". После создания этих двух папок переместите типизированный набор данных, созданный в первом руководстве, в вложенную папку DAL .
Затем создайте четыре файла класса BLL в подпапке BLL . Чтобы это сделать, щелкните правой кнопкой мыши на BLL подпапке, выберите "Добавить новый элемент" и выберите шаблон класса. Назовите четыре класса ProductsBLL, CategoriesBLLи SuppliersBLLEmployeesBLL.
Рис. 2. Добавление четырех новых классов в папку App_Code
Далее давайте добавим методы к каждому из классов, чтобы просто упаковать методы, определенные для TableAdapters из первого руководства. Сейчас эти методы будут просто вызываться непосредственно в DAL; мы позже добавим необходимую бизнес-логику.
Замечание
Если вы используете Visual Studio Standard Edition или более поздней версии (т. е. вы не используете Visual Web Developer), вы можете при необходимости визуально разработать классы с помощью конструктора классов. Дополнительные сведения об этой новой функции в Visual Studio см. в блоге конструктора классов .
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. Хотя в некоторых сценариях могут быть бизнес-правила, которые должны быть реализованы на этом уровне (например, правила авторизации на основе текущего пользователя или роли, к которой принадлежит пользователь), мы просто оставим эти методы as-is. Для этих методов BLL служит лишь прокси-сервером, через который слой презентации обращается к базовым данным из уровня доступа к данным.
Методы AddProduct и UpdateProduct принимают в качестве параметров значения для различных полей продукта и соответственно добавляют новый продукт или обновляют существующий. Так как многие из Product столбцов таблицы могут принимать NULL значения (CategoryID, SupplierID и UnitPrice, чтобы назвать несколько), те входные параметры для AddProduct и UpdateProduct, которые соответствуют таким столбцам, используют типы, допускающие значение NULL. Типы, допускающие значение NULL, появились в .NET 2.0 и предоставляют способ указать, должен ли тип значения вместо этого быть Nothing. Дополнительные сведения см. в записи блога Пола ВикаThe Truth About Nullable Types and VB и в технической документации по структуре Nullable.
Все три метода возвращают логическое значение, указывающее, была ли строка вставлена, обновлена или удалена, так как операция не может привести к затронутой строке. Например, если разработчик страницы вызывает DeleteProduct, передавая ProductID для несуществующего продукта, DELETE SQL-запрос, отправленный в базу данных, не повлияет, и поэтому метод DeleteProduct вернет False.
Заметьте, что при добавлении нового продукта или обновлении существующего мы принимаем значения полей нового или измененного продукта в виде списка скаляров, а не экземпляра ProductsRow. Этот подход был выбран, так как ProductsRow класс является производным от класса ADO.NET DataRow , который не имеет конструктора без параметров по умолчанию. Чтобы создать новый экземпляр ProductsRow, сначала необходимо создать экземпляр ProductsDataTable, а затем вызвать его метод NewProductRow() (что мы делаем в AddProduct). Этот недостаток проявляется при вставке и обновлении товаров с помощью ObjectDataSource. Короче говоря, ObjectDataSource попытается создать экземпляр входных параметров. Если метод BLL ожидает экземпляр ProductsRow, то объект ObjectDataSource попытается создать его, но не сможет из-за отсутствия конструктора без параметров. Дополнительные сведения об этой проблеме см. в следующих двух ASP.NET форумах: обновление ObjectDataSources с помощью наборов данных Strongly-Typedи проблемы с ObjectDataSource и Strongly-Typed DataSet.
Затем в обоих AddProductUpdateProductслучаях код создает 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 2.0 ObjectDataSource упрощает декларативный доступ к данным из класса. Чтобы отфильтровать список возможных классов для привязки к мастеру 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 также могут быть доступны декларативно (как и типизированный набор данных) с помощью ObjectDataSource. Мы обсудим ObjectDataSource более подробно в рамках следующих руководств.
Рис. 3. Список продуктов отображается в GridView (щелкните, чтобы просмотреть изображение полного размера)
Шаг 3. Добавление проверки Field-Level в классы DataRow
Проверка на уровне поля — это проверки, относящиеся к значениям свойств бизнес-объектов при вставке или обновлении. Ниже перечислены некоторые правила проверки на уровне поля для продуктов:
- Поле
ProductNameдолжно содержать 40 символов или меньше длины. - Поле
QuantityPerUnitдолжно содержать 20 символов или меньше длины. - Обязательными являются поля
ProductID,ProductNameиDiscontinued, но все остальные поля необязательны. - Поля
UnitPrice,UnitsInStock,UnitsOnOrderиReorderLevelдолжны быть больше или равно нулю
Эти правила могут быть выражены на уровне базы данных. Ограничение символов для ProductNameQuantityPerUnit полей фиксируется типами данных этих столбцов в Products таблице (nvarchar(40) и nvarchar(20)соответственно). Указывает, являются ли поля обязательными и необязательными, если столбец таблицы базы данных допускает NULL s. Четыре ограничения существуют, чтобы гарантировать, что только значения, превышающие или равные нулю, могут попасть в столбцы UnitPrice, UnitsInStock, UnitsOnOrder или ReorderLevel.
Помимо применения этих правил в базе данных, они также должны быть применены на уровне Набора данных. Фактически, длина поля, а также требуемость или необязательность значения уже зафиксированы для каждого набора DataColumns таблицы данных (DataTable). Чтобы просмотреть автоматическую проверку на уровне поля, перейдите в конструктор наборов данных, выберите поле из одной из наборов данных, а затем перейдите в окно "Свойства". Как показано на рисунке 4, QuantityPerUnit DataColumn в ProductsDataTable имеет максимальную длину 20 символов и допускает NULL значения. Если мы попытаемся установить для ProductsDataRowQuantityPerUnit строковое значение длиной более 20 символов, будет выдано исключение ArgumentException.
Рис. 4: DataColumn предоставляет базовую проверку Field-Level (нажмите, чтобы увеличить изображение)
К сожалению, невозможно указать проверки границ, например UnitPrice значение должно быть больше нуля или равно нулю в окне "Свойства". Чтобы предоставить этот тип проверки на уровне поля, необходимо создать обработчик событий для события ColumnChanging dataTable. Как упоминалось в предыдущем руководстве, объекты DataSet, DataTables и DataRow, созданные типизированным набором данных, можно расширить с помощью частичных классов. С помощью этого метода можно создать 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 , мы начнем с проверки того, задано ли Discontinued значение True и, если да, мы будем вызывать 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 (что приведет к возникновению события HttpApplicationError). Для обработки исключения при работе с 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 мы готовы начать работу на нашем уровне презентации. В следующем руководстве мы рассмотрим краткий переход из разделов доступа к данным и определим согласованный макет страницы для использования во всех руководствах.
Счастливое программирование!
Сведения о авторе
Скотт Митчелл, автор семи книг ASP/ASP.NET и основатель 4GuysFromRolla.com, работает с технологиями Microsoft Web с 1998 года. Скотт работает независимым консультантом, тренером и писателем. Его последняя книга — Sams Teach Yourself ASP.NET 2.0 за 24 часа. С ним можно связаться по адресу mitchell@4GuysFromRolla.com.
Особое спасибо кому
Эта серия учебников была проверена многими полезными рецензентами. Ведущими рецензентами этого учебника были Лиз Шулок, Деннис Паттерсон, Карлос Сантос и Хилтон Гизенау. Хотите просмотреть мои предстоящие статьи MSDN? Если да, напишите мне на mitchell@4GuysFromRolla.com.