Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
oleh Scott Mitchell
Dalam tutorial ini kita akan melihat cara memusatkan aturan bisnis Anda ke dalam Lapisan Logika Bisnis (BLL) yang berfungsi sebagai perantara untuk pertukaran data antara lapisan presentasi dan DAL.
Pendahuluan
Lapisan Akses Data (DAL) yang dibuat dalam tutorial pertama memisahkan logika akses data dengan bersih dari logika presentasi. Namun, sementara DAL secara tepat memisahkan detail akses data dari lapisan presentasi, DAL tidak memberlakukan aturan bisnis apa pun yang mungkin berlaku. Misalnya, untuk aplikasi kami, kami mungkin ingin melarang kolom CategoryID
atau SupplierID
dari tabel Products
untuk dimodifikasi ketika kolom Discontinued
diatur ke 1, atau kami mungkin ingin menginjeksikan aturan senioritas dengan melarang situasi di mana seorang karyawan dikelola oleh seseorang yang dipekerjakan setelah mereka. Skenario umum lainnya adalah otorisasi mungkin hanya pengguna dalam peran tertentu yang dapat menghapus produk atau dapat mengubah nilainya UnitPrice
.
Dalam tutorial ini kita akan melihat cara memusatkan aturan bisnis ini ke dalam Lapisan Logika Bisnis (BLL) yang berfungsi sebagai perantara untuk pertukaran data antara lapisan presentasi dan DAL. Dalam aplikasi dunia nyata, BLL harus diimplementasikan sebagai proyek Pustaka Kelas terpisah; namun, untuk tutorial ini kami akan menerapkan BLL sebagai serangkaian kelas di folder kami App_Code
untuk menyederhanakan struktur proyek. Gambar 1 menggambarkan hubungan arsitektur di antara lapisan presentasi, BLL, dan DAL.
Gambar 1: BLL Memisahkan Lapisan Presentasi dari Lapisan Akses Data dan Memberlakukan Aturan Bisnis
Daripada membuat kelas terpisah untuk mengimplementasikan logika bisnis kami, kami dapat menempatkan logika ini secara langsung di Typed DataSet dengan kelas parsial. Untuk contoh membuat dan memperluas DataSet Bertipe, rujuk kembali ke tutorial pertama.
Langkah 1: Membuat Kelas BLL
BLL kami akan terdiri dari empat kelas, satu untuk setiap TableAdapter dalam DAL; masing-masing kelas BLL ini akan memiliki metode untuk ambil, menyisipkan, memperbarui, dan menghapus dari TableAdapter terkait dalam DAL, dan menerapkan aturan bisnis yang sesuai.
Untuk memisahkan kelas terkait DAL dan BLL dengan lebih bersih, mari kita buat dua subfolder di App_Code
folder, DAL
dan BLL
. Cukup klik kanan pada App_Code
folder di Penjelajah Solusi dan pilih Folder Baru. Setelah membuat kedua folder ini, pindahkan Typed DataSet yang dibuat dalam tutorial pertama ke subfolder DAL
.
Selanjutnya, buat empat file kelas BLL di BLL
subfolder. Untuk menyelesaikan ini, klik kanan pada BLL
subfolder, pilih Tambahkan Item Baru, dan pilih templat Kelas. Beri nama empat kelas ProductsBLL
, , CategoriesBLL
SuppliersBLL
, dan EmployeesBLL
.
Gambar 2: Tambahkan Empat Kelas Baru ke App_Code
Folder
Selanjutnya, mari kita tambahkan metode ke setiap kelas untuk dengan mudah membungkus metode yang telah ditentukan untuk TableAdapters dari tutorial pertama. Untuk saat ini, metode ini hanya akan memanggil langsung ke DAL; kita akan kembali nanti untuk menambahkan logika bisnis yang diperlukan.
Nota
Jika Anda menggunakan Visual Studio Standard Edition atau lebih tinggi (yaitu, Anda tidak menggunakan Visual Web Developer), Anda dapat secara opsional mendesain kelas Anda secara visual menggunakan Perancang Kelas. Lihat Blog Perancang Kelas untuk informasi selengkapnya tentang fitur baru ini di Visual Studio.
Untuk kelas, ProductsBLL
kita perlu menambahkan total tujuh metode:
-
GetProducts()
mengembalikan semua produk -
GetProductByProductID(productID)
mengembalikan produk dengan ID produk yang ditentukan -
GetProductsByCategoryID(categoryID)
mengembalikan semua produk dari kategori yang ditentukan -
GetProductsBySupplier(supplierID)
mengembalikan semua produk dari pemasok yang ditentukan -
AddProduct(productName, supplierID, categoryID, quantityPerUnit, unitPrice, unitsInStock, unitsOnOrder, reorderLevel, discontinued)
menyisipkan produk baru ke dalam database menggunakan nilai yang diteruskan;ProductID
mengembalikan nilai rekaman yang baru disisipkan -
UpdateProduct(productName, supplierID, categoryID, quantityPerUnit, unitPrice, unitsInStock, unitsOnOrder, reorderLevel, discontinued, productID)
memperbarui produk yang ada dalam database menggunakan nilai yang diteruskan; mengembalikanTrue
jika justru satu baris diperbarui,False
jika tidak -
DeleteProduct(productID)
menghapus produk yang ditentukan dari database
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
Metode yang hanya mengembalikan data GetProducts
, , GetProductByProductID
GetProductsByCategoryID
, dan GetProductBySuppliersID
cukup mudah karena mereka hanya memanggil ke DAL. Meskipun dalam beberapa skenario mungkin ada aturan bisnis yang perlu diterapkan pada tingkat ini (seperti aturan otorisasi berdasarkan pengguna yang saat ini masuk atau peran tempat pengguna berada), kami hanya akan meninggalkan metode ini as-is. Untuk metode ini, maka, BLL hanya berfungsi sebagai proksi di mana lapisan presentasi mengakses data yang mendasar dari Lapisan Akses Data.
Metode AddProduct
dan UpdateProduct
keduanya mengambil sebagai parameter nilai untuk berbagai bidang produk dan menambahkan produk baru atau memperbarui yang sudah ada, masing-masing. Karena banyak kolom Product
tabel dapat menerima nilai NULL
(CategoryID
, SupplierID
, dan UnitPrice
, contohnya), parameter input tersebut untuk AddProduct
dan UpdateProduct
yang sesuai dengan kolom tersebut menggunakan jenis nullable. Jenis nullable baru untuk .NET 2.0 dan menyediakan teknik untuk menunjukkan apakah jenis nilai harus, sebagai gantinya, menjadi Nothing
. Lihat entri blog Paul VickThe Truth About Nullable Types dan VB dan dokumentasi teknis tentang struktur Nullable untuk informasi lebih lanjut.
Ketiga metode mengembalikan nilai Boolean yang menunjukkan apakah baris dimasukkan, diperbarui, atau dihapus karena operasi mungkin tidak menghasilkan baris yang terpengaruh. Misalnya, jika pengembang halaman memanggil DeleteProduct
meneruskan ProductID
untuk produk yang tidak ada, pernyataan DELETE
yang dikeluarkan untuk database tidak akan berpengaruh dan metode DeleteProduct
akan mengembalikan False
.
Perhatikan bahwa saat menambahkan produk baru atau memperbarui produk yang sudah ada, kami mengambil nilai bidang produk baru atau yang dimodifikasi sebagai daftar skalar alih-alih menerima suatu instans ProductsRow
. Pendekatan ini dipilih karena ProductsRow
kelas berasal dari kelas ADO.NET DataRow
, yang tidak memiliki konstruktor tanpa parameter default. Untuk membuat instans baru ProductsRow
, kita harus terlebih dahulu membuat ProductsDataTable
instans dan kemudian memanggil metodenya NewProductRow()
(yang kita lakukan di AddProduct
). Kekurangan ini terasa jelas saat kita menyisipkan dan memperbarui produk menggunakan ObjectDataSource. Singkatnya, ObjectDataSource akan mencoba membuat objek dari parameter input. Jika metode BLL mengharapkan instans ProductsRow
, ObjectDataSource akan mencoba membuatnya, tetapi gagal karena kurangnya konstruktor tanpa parameter default. Untuk informasi selengkapnya tentang masalah ini, lihat dua posting forum ASP.NET berikut: Memperbarui ObjectDataSources dengan Strongly-Typed Himpunan Data, dan Masalah Dengan ObjectDataSource dan Strongly-Typed Himpunan Data.
Selanjutnya, dalam AddProduct
dan UpdateProduct
, kode membuat instans ProductsRow
dan mengisinya dengan nilai yang baru saja diteruskan. Saat menetapkan nilai ke DataColumns dari dataRow berbagai pemeriksaan validasi tingkat bidang dapat terjadi. Oleh karena itu, memasukkan nilai yang diteruskan secara manual kembali ke DataRow membantu memastikan validitas data yang diteruskan ke metode BLL. Sayangnya, kelas DataRow bertipe kuat yang dihasilkan oleh Visual Studio tidak menggunakan Tipe Nullable. Sebaliknya, untuk menunjukkan bahwa DataColumn tertentu dalam DataRow harus sesuai dengan nilai database NULL
, kita harus menggunakan metode SetColumnNameNull()
.
Di UpdateProduct
, pertama-tama kami memuat produk yang akan diperbarui dengan menggunakan GetProductByProductID(productID)
. Meskipun ini mungkin tampak seperti perjalanan yang tidak perlu ke database, perjalanan tambahan ini akan terbukti berguna dalam tutorial di masa depan yang mengeksplorasi konkurensi optimis. Konkurensi optimis adalah teknik untuk memastikan bahwa dua pengguna yang secara bersamaan mengerjakan data yang sama tidak secara tidak sengaja menimpa perubahan satu sama lain. Mengambil seluruh catatan juga memudahkan untuk membuat metode pembaruan di BLL yang hanya memodifikasi subset kolom DataRow. Ketika kita menjelajahi SuppliersBLL
kelas, kita akan melihat contoh seperti itu.
Terakhir, perhatikan bahwa ProductsBLL
kelas memiliki atribut DataObject yang diterapkan padanya (sintaksnya tepat di atas pernyataan kelas di bagian atas file) dan metode memiliki [System.ComponentModel.DataObject]
. Atribut DataObject
menandai kelas sebagai objek yang cocok untuk mengikat kontrol ObjectDataSource, sedangkan DataObjectMethodAttribute
menunjukkan tujuan metode . Seperti yang akan kita lihat di tutorial mendatang, ObjectDataSource ASP.NET 2.0 memudahkan untuk mengakses data secara deklaratif dari kelas. Untuk membantu memfilter daftar kelas yang mungkin diikat dalam wizard ObjectDataSource, secara default hanya kelas yang ditandai seperti DataObjects
yang diperlihatkan dalam daftar drop-down wizard. Kelas ProductsBLL
juga akan berfungsi tanpa atribut ini, tetapi menambahkannya membuatnya lebih mudah untuk dikerjakan dalam wizard ObjectDataSource.
Menambahkan Kelas Lain
Dengan kelas ProductsBLL
selesai, kita masih perlu menambahkan kelas untuk bekerja dengan kategori, pemasok, dan karyawan. Luangkan waktu sejenak untuk membuat kelas dan metode berikut menggunakan konsep dari contoh di atas:
CategoriesBLL.cs
GetCategories()
GetCategoryByCategoryID(categoryID)
SuppliersBLL.cs
GetSuppliers()
GetSupplierBySupplierID(supplierID)
GetSuppliersByCountry(country)
UpdateSupplierAddress(supplierID, address, city, country)
EmployeesBLL.cs
GetEmployees()
GetEmployeeByEmployeeID(employeeID)
GetEmployeesByManager(managerID)
Salah satu metode yang perlu diperhatikan adalah metode SuppliersBLL
dari kelas UpdateSupplierAddress
. Metode ini menyediakan antarmuka untuk memperbarui hanya informasi alamat pemasok. Secara internal, metode ini membaca objek SupplierDataRow
untuk supplierID
yang ditentukan (menggunakan GetSupplierBySupplierID
), mengatur properti terkait alamatnya, lalu memanggil metode SupplierDataTable
pada Update
. Metode UpdateSupplierAddress
adalah sebagai berikut:
<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
Lihat unduhan artikel ini untuk implementasi lengkap kelas BLL saya.
Langkah 2: Mengakses Himpunan Data yang Ditik melalui Kelas BLL
Dalam tutorial pertama kami melihat contoh bekerja langsung dengan Typed DataSet secara terprogram, tetapi dengan penambahan kelas BLL kami, tingkat presentasi harus bekerja melawan BLL sebagai gantinya.
AllProducts.aspx
Dalam contoh dari tutorial pertama, ProductsTableAdapter
digunakan untuk mengikat daftar produk ke GridView, seperti yang ditunjukkan dalam kode berikut:
Dim productsAdapter As New ProductsTableAdapter()
GridView1.DataSource = productsAdapter.GetProducts()
GridView1.DataBind()
Untuk menggunakan kelas BLL baru, yang perlu diubah adalah baris kode pertama cukup ganti ProductsTableAdapter
objek dengan ProductBLL
objek:
Dim productLogic As New ProductsBLL()
GridView1.DataSource = productLogic.GetProducts()
GridView1.DataBind()
Kelas BLL juga dapat diakses secara deklaratif (seperti halnya Typed DataSet) dengan menggunakan ObjectDataSource. Kita akan membahas ObjectDataSource secara lebih rinci dalam tutorial berikut.
Gambar 3: Daftar Produk Ditampilkan dalam GridView (Klik untuk melihat gambar ukuran penuh)
Langkah 3: Menambahkan Validasi Field-Level ke Kelas DataRow
Validasi tingkat lapangan adalah pemeriksaan yang berkaitan dengan nilai properti objek bisnis ketika menyisipkan atau memperbarui. Beberapa aturan validasi tingkat bidang untuk produk meliputi:
- Panjang
ProductName
bidang harus 40 karakter atau kurang - Panjang
QuantityPerUnit
bidang harus 20 karakter atau kurang - Bidang
ProductID
,ProductName
, danDiscontinued
diperlukan, tetapi semua bidang lainnya bersifat opsional - Bidang
UnitPrice
,UnitsInStock
,UnitsOnOrder
, danReorderLevel
harus lebih besar dari atau sama dengan nol
Aturan ini dapat dan harus diekspresikan di tingkat database. Batas karakter pada kolom ProductName
dan QuantityPerUnit
ditentukan oleh jenis data dari kolom tersebut dalam tabel Products
(nvarchar(40)
dan nvarchar(20)
, masing-masing). Apakah bidang diperlukan atau opsional ditentukan oleh apakah kolom tabel database mengizinkan NULL
. Ada empat batasan pemeriksaan yang memastikan bahwa hanya nilai yang lebih besar dari atau sama dengan nol dapat masuk ke kolom UnitPrice
, UnitsInStock
, UnitsOnOrder
, atau ReorderLevel
.
Selain memberlakukan aturan ini di database, aturan tersebut juga harus diberlakukan di tingkat Himpunan Data. Bahkan, panjang kolom dan apakah nilai diperlukan atau opsional sudah dicatat untuk setiap kumpulan DataColumn dalam DataTable. Untuk melihat validasi tingkat bidang yang ada secara otomatis disediakan, buka Perancang Himpunan Data, pilih bidang dari salah satu DataTables lalu buka jendela Properti. Seperti yang ditunjukkan Gambar 4, QuantityPerUnit
DataColumn dalam ProductsDataTable
memiliki panjang maksimum 20 karakter dan mengizinkan nilai NULL
. Jika kita mencoba mengatur properti ProductsDataRow
dari QuantityPerUnit
ke nilai string yang lebih panjang dari 20 karakter, maka ArgumentException
akan dihasilkan.
Gambar 4: DataColumn Menyediakan Validasi Field-Level Dasar (Klik untuk melihat gambar ukuran penuh)
Sayangnya, kami tidak dapat menentukan pemeriksaan batas, seperti UnitPrice
nilainya harus sama dengan atau lebih besar dari nol, melalui jendela Properti. Untuk menyediakan jenis validasi tingkat bidang ini, kita perlu membuat penanganan aktivitas untuk peristiwa ColumnChanging DataTable. Seperti disebutkan dalam tutorial sebelumnya, objek DataSet, DataTables, dan DataRow yang dibuat oleh Typed DataSet dapat diperluas melalui penggunaan kelas parsial. Menggunakan teknik ini kita dapat membuat ColumnChanging
penanganan aktivitas untuk ProductsDataTable
kelas . Mulailah dengan membuat kelas di App_Code
folder bernama ProductsDataTable.ColumnChanging.vb
.
Gambar 5: Tambahkan Kelas Baru ke App_Code
Folder (Klik untuk melihat gambar ukuran penuh)
Selanjutnya, buat penangan acara untuk peristiwa ColumnChanging
yang memastikan bahwa nilai kolom UnitPrice
, UnitsInStock
, UnitsOnOrder
, dan ReorderLevel
(jika tidak NULL
) lebih besar dari atau sama dengan nol. Jika kolom tersebut berada di luar rentang, lemparkan 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
Langkah 4: Menambahkan Aturan Bisnis Kustom ke Kelas BLL
Selain validasi tingkat bidang, mungkin ada aturan bisnis kustom tingkat tinggi yang melibatkan entitas atau konsep yang berbeda yang tidak dapat diekspresikan pada tingkat kolom tunggal, seperti:
- Jika produk dihentikan, produk
UnitPrice
tidak dapat diperbarui - Negara tempat tinggal karyawan harus sama dengan negara tempat tinggal manajer mereka
- Produk tidak dapat dihentikan jika merupakan satu-satunya produk yang disediakan oleh pemasok
Kelas BLL harus berisi pemeriksaan untuk memastikan kepatuhan terhadap aturan bisnis aplikasi. Pemeriksaan ini dapat ditambahkan langsung ke metode yang diterapkan.
Bayangkan bahwa aturan bisnis kami menentukan bahwa produk tidak dapat ditandai dihentikan jika itu adalah satu-satunya produk dari pemasok tertentu. Artinya, jika produk X adalah satu-satunya produk yang kami beli dari pemasok Y, kami tidak dapat menandai X sebagai dihentikan; namun, jika, pemasok Y memasok kami dengan tiga produk, A, B, dan C, maka kami dapat menandai salah satu dan semua ini sebagai dihentikan. Aturan bisnis yang aneh, tetapi aturan bisnis dan akal sehat tidak selalu selaras!
Untuk menerapkan aturan bisnis ini dalam metode UpdateProducts
, kita akan memulai dengan memeriksa apakah Discontinued
disetel ke True
dan, jika demikian, kita akan memanggil GetProductsBySupplierID
untuk menentukan berapa banyak produk yang kita beli dari pemasok produk ini. Jika hanya satu produk dibeli dari pemasok ini, kami akan menghasilkan 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
Menanggapi Kesalahan Validasi di Tingkat Presentasi
Saat memanggil BLL dari tingkat presentasi, kita dapat memutuskan apakah akan mencoba menangani pengecualian apa pun yang mungkin terjadi atau membiarkannya diteruskan ke ASP.NET (yang akan menyebabkan terjadinya acara HttpApplication
Error
). Untuk menangani pengecualian saat bekerja dengan BLL secara terprogram, kita dapat menggunakan Coba... Tangkap blok, seperti yang ditunjukkan contoh berikut:
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
Seperti yang akan kita lihat di tutorial mendatang, menangani pengecualian yang muncul ke permukaan dari BLL saat menggunakan kontrol Web data untuk menyisipkan, memperbarui, atau menghapus data dapat ditangani langsung dalam penangan kejadian dibandingkan harus membungkus kode dalam blok Try...Catch
.
Ringkasan
Aplikasi yang dirancang dengan baik dibuat menjadi lapisan yang berbeda, yang masing-masing merangkum peran tertentu. Dalam tutorial pertama dari seri artikel ini, kami membuat Lapisan Akses Data menggunakan Typed DataSets; dalam tutorial ini kami membangun Lapisan Logika Bisnis sebagai serangkaian kelas di folder aplikasi App_Code
kami yang memanggil ke DAL kami. BLL mengimplementasikan logika tingkat bidang dan tingkat bisnis untuk aplikasi kami. Selain membuat BLL terpisah, seperti yang kami lakukan dalam tutorial ini, opsi lain adalah memperluas metode TableAdapters melalui penggunaan kelas parsial. Namun, menggunakan teknik ini tidak memungkinkan kami untuk mengambil alih metode yang ada atau tidak memisahkan DAL dan BLL kami dengan bersih seperti pendekatan yang telah kami ambil dalam artikel ini.
Dengan DAL dan BLL selesai, kami siap untuk memulai pada lapisan presentasi kami. Dalam tutorial berikutnya kita akan menyimpang sejenak dari topik akses data dan menentukan tata letak halaman yang konsisten untuk digunakan di seluruh tutorial.
Selamat Pemrograman!
Tentang Penulis
Scott Mitchell, penulis tujuh buku ASP/ASP.NET dan pendiri 4GuysFromRolla.com, telah bekerja sama dengan teknologi Microsoft Web sejak 1998. Scott bekerja sebagai konsultan, pelatih, dan penulis independen. Buku terbarunya adalah Sams Teach Yourself ASP.NET 2.0 dalam 24 Jam. Dia dapat dijangkau di mitchell@4GuysFromRolla.com.
Ucapan terima kasih khusus kepada
Seri tutorial ini ditinjau oleh banyak peninjau yang bermanfaat. Peninjau utama untuk tutorial ini adalah Liz Shulok, Dennis Patterson, Carlos Santos, dan Hilton Giesenow. Tertarik untuk meninjau artikel MSDN saya yang akan datang? Jika demikian, hubungi saya di mitchell@4GuysFromRolla.com.