İş Mantığı Katmanı Oluşturma (VB)

tarafından Scott Mitchell

PDF’yi İndir

Bu öğreticide, iş kurallarınızı sunu katmanı ile DAL arasında veri alışverişine aracılık eden bir İş Mantığı Katmanına (BLL) nasıl merkezileştirebileceğimizi göreceğiz.

Giriş

İlk öğreticide oluşturulan Veri Erişim Katmanı (DAL), veri erişim mantığını sunu mantığından temiz bir şekilde ayırır. Ancak DAL, veri erişim ayrıntılarını sunu katmanından temiz bir şekilde ayırsa da, uygulanabilecek iş kurallarını zorunlu kılmaz. Örneğin, uygulamamız için alan 1 olarak ayarlandığında tablonun veya SupplierID alanlarının Products değiştirilmesine Discontinued izin CategoryID vermemeyi veya bir çalışanın kendilerinden sonra işe alınan biri tarafından yönetildiği durumları yasaklayarak kıdem kurallarını zorunlu kılmak isteyebiliriz. Bir diğer yaygın senaryo da yetkilendirmedir, belki de yalnızca belirli bir roldeki kullanıcılar ürünleri silebilir veya değeri değiştirebilir UnitPrice .

Bu öğreticide, bu iş kurallarını sunu katmanı ile DAL arasında veri alışverişine aracılık eden bir İş Mantığı Katmanına (BLL) nasıl merkezileştirebileceğimizi göreceğiz. Gerçek bir uygulamada, BLL ayrı bir Sınıf Kitaplığı projesi olarak uygulanmalıdır; ancak bu öğreticilerde, proje yapısını basitleştirmek için BLL'yi klasörümüzde App_Code bir dizi sınıf olarak uygulayacağız. Şekil 1'de sunu katmanı, BLL ve DAL arasındaki mimari ilişkiler gösterilmektedir.

BLL, Sunu Katmanını Veri Erişim Katmanından Ayırır ve İş Kuralları Uygular

Şekil 1: BLL, Sunu Katmanını Veri Erişim Katmanından Ayırır ve İş Kuralları Uygular

İş mantığımızı uygulamak için ayrı sınıflar oluşturmak yerine, alternatif olarak bu mantığı kısmi sınıflarla doğrudan Yazılan Veri Kümesine yerleştirebiliriz. Türlenmiş DataSet oluşturma ve genişletme örneği için ilk öğreticiye geri bakın.

1. Adım: BLL Sınıflarını Oluşturma

BLL'miz DAL'deki her TableAdapter için bir tane olmak üzere dört sınıftan oluşacak; bu BLL sınıflarının her biri, DAL'deki ilgili TableAdapter'ı alma, ekleme, güncelleştirme ve silme yöntemlerine sahip olur ve uygun iş kurallarını uygular.

DAL ve BLL ile ilgili sınıfları daha net bir şekilde ayırmak için klasöründe ve BLLolmak üzere iki alt App_Code klasör DAL oluşturalım. Çözüm Gezgini klasöre App_Code sağ tıklayıp Yeni Klasör'i seçmeniz yeterlidir. Bu iki klasörü oluşturduktan sonra, ilk öğreticide oluşturulan Yazılan Veri Kümesini alt klasöre DAL taşıyın.

Ardından, alt klasörde dört BLL sınıf dosyası BLL oluşturun. Bunu yapmak için alt klasöre BLL sağ tıklayın, Yeni Öğe Ekle'yi seçin ve Sınıf şablonunu seçin. Dört sınıfı ProductsBLL, , CategoriesBLLSuppliersBLLve EmployeesBLLolarak adlandırın.

App_Code Klasörüne Dört Yeni Sınıf Ekleme

Şekil 2: Klasöre App_Code Dört Yeni Sınıf Ekleme

Şimdi sınıfların her birine yöntemler ekleyerek ilk öğreticideki TableAdapters için tanımlanan yöntemleri sarmalayalım. Şimdilik bu yöntemler doğrudan DAL'ye çağrı yapacaktır; gerekli iş mantığını eklemek için daha sonra geri döneceğiz.

Not

Visual Studio Standard Edition veya üzerini kullanıyorsanız (yani, Visual Web Developer kullanmıyorsanız), isteğe bağlı olarak Sınıf Tasarım Aracı kullanarak sınıflarınızı görsel olarak tasarlayabilirsiniz. Visual Studio'daki bu yeni özellik hakkında daha fazla bilgi için Sınıf Tasarım Aracı Bloguna bakın.

sınıfı için ProductsBLL toplam yedi yöntem eklemeliyiz:

  • GetProducts() tüm ürünleri döndürür
  • GetProductByProductID(productID) belirtilen ürün kimliğine sahip ürünü döndürür
  • GetProductsByCategoryID(categoryID) belirtilen kategorideki tüm ürünleri döndürür
  • GetProductsBySupplier(supplierID) belirtilen sağlayıcının tüm ürünlerini döndürür
  • AddProduct(productName, supplierID, categoryID, quantityPerUnit, unitPrice, unitsInStock, unitsOnOrder, reorderLevel, discontinued) geçirilen değerleri kullanarak veritabanına yeni bir ürün ekler; ProductID yeni eklenen kaydın değerini verir
  • UpdateProduct(productName, supplierID, categoryID, quantityPerUnit, unitPrice, unitsInStock, unitsOnOrder, reorderLevel, discontinued, productID) geçirilen değerleri kullanarak veritabanındaki mevcut bir ürünü güncelleştirir; tam olarak bir satır güncelleştirildiyse döndürür True , False aksi takdirde
  • DeleteProduct(productID) belirtilen ürünü veritabanından siler

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

Yalnızca DAL'ye çağrı yaptıkları için , GetProductByProductID, GetProductsByCategoryIDve GetProductBySuppliersID verilerini GetProductsdöndüren yöntemler oldukça basittir. Bazı senaryolarda bu düzeyde uygulanması gereken iş kuralları (oturum açmış olan kullanıcıya veya kullanıcının ait olduğu role dayalı yetkilendirme kuralları gibi) olsa da, bu yöntemleri olduğu gibi bırakmamız yeterlidir. Bu yöntemler için BLL yalnızca sunu katmanının Veri Erişim Katmanı'ndan temel alınan verilere eriştiği bir proxy görevi görür.

AddProduct ve UpdateProduct yöntemleri, çeşitli ürün alanlarının değerlerini parametre olarak alır ve sırasıyla yeni bir ürün ekler veya mevcut bir ürünü güncelleştirir. Tablonun sütunlarının Product çoğu değerleri (CategoryID, SupplierIDve UnitPricebirkaçını adlandırmak için) kabul NULL ettiğinden ve bu tür sütunlara eşleyen giriş parametreleri AddProductUpdateProductnull atanabilir türler kullanır. Null atanabilir türler .NET 2.0'da yenidir ve bunun yerine Nothingbir değer türünün olması gerekip gerekmediğini belirten bir teknik sağlar. Daha fazla bilgi için Paul Vick'in Boş Değer Atanabilir Türler ve VB Hakkındaki Gerçekler blog girdisine ve Null atanabilir yapıya yönelik teknik belgelere bakın.

İşlem etkilenen bir satırla sonuçlanmayabileceği için üç yöntem de bir satırın eklendiğini, güncelleştirildiğini veya silindiğini belirten bir Boole değeri döndürür. Örneğin, sayfa geliştiricisi mevcut olmayan bir ürün için bir geçirmeyi çağırırsaDeleteProduct, DELETE veritabanına verilen deyiminin hiçbir etkisi olmaz ve bu nedenle DeleteProduct yöntemi döndürürFalse.ProductID

Yeni bir ürün eklerken veya mevcut bir ürünü güncelleştirirken, yeni veya değiştirilmiş ürünün alan değerlerini bir örneği kabul etmekle ProductsRow değil skalerlerin listesi olarak aldığımızı unutmayın. Sınıfı varsayılan parametresiz oluşturucuya sahip olmayan ADO.NET DataRow sınıfından türetildiği için ProductsRow bu yaklaşım seçildi. Yeni ProductsRow bir örnek oluşturmak için önce bir ProductsDataTable örnek oluşturmalı ve ardından yöntemini çağırmamız NewProductRow() gerekir (içinde bunu yaparız AddProduct). Bu eksiklik, ObjectDataSource kullanarak ürün ekleme ve güncelleştirmeye gittiğimizde başını diker. Kısacası, ObjectDataSource giriş parametrelerinin bir örneğini oluşturmayı deneyecektir. BLL yöntemi bir ProductsRow örnek bekliyorsa, ObjectDataSource bir örnek oluşturmayı dener, ancak varsayılan parametresiz oluşturucunun olmaması nedeniyle başarısız olur. Bu sorun hakkında daha fazla bilgi için şu iki ASP.NET Forum gönderisine bakın: ObjectDataSources'u Strongly-Typed DataSets ile Güncelleştirme ve ObjectDataSource ile İlgili Sorun ve DataSet Strongly-Typed.

Ardından, hem hem de AddProductUpdateProductiçinde kod bir ProductsRow örnek oluşturur ve bunu geçirilen değerlerle doldurur. DataRow'un DataColumns değerleri atanırken çeşitli alan düzeyi doğrulama denetimleri gerçekleşebilir. Bu nedenle, geçirilen değerleri el ile bir DataRow'a geri koymak, BLL yöntemine geçirilen verilerin geçerliliğini sağlamaya yardımcı olur. Ne yazık ki Visual Studio tarafından oluşturulan kesin türdeki DataRow sınıfları null atanabilir türler kullanmaz. Bunun yerine, DataRow'daki belirli bir DataColumn'un bir NULL veritabanı değerine karşılık geldiğini belirtmek için yöntemini kullanmamız SetColumnNameNull() gerekir.

'de UpdateProduct ilk olarak ürününü kullanarak GetProductByProductID(productID)güncelleştirmek üzere yükleyeceğiz. Bu, veritabanına gereksiz bir yolculuk gibi görünse de, bu ek gezi iyimser eşzamanlılığı keşfeden gelecek öğreticilerde faydalı olacaktır. İyimser eşzamanlılık, aynı anda aynı veri üzerinde çalışan iki kullanıcının yanlışlıkla bir başkasının değişikliklerinin üzerine yazmamasını sağlamaya yönelik bir tekniktir. Kaydın tamamını almak, BLL'de DataRow sütunlarının yalnızca bir alt kümesini değiştiren güncelleştirme yöntemleri oluşturmayı da kolaylaştırır. Sınıfı incelediğimizde SuppliersBLL böyle bir örnek göreceğiz.

Son olarak, sınıfına ProductsBLLDataObject özniteliğinin uygulandığını ( [System.ComponentModel.DataObject] dosyanın üst kısmındaki sınıf deyiminden hemen önceki söz dizimi) ve yöntemlerin DataObjectMethodAttribute özniteliklerine sahip olduğunu unutmayın. DataObject özniteliği sınıfını ObjectDataSource denetimine bağlamaya uygun bir nesne olarak işaretlerkenDataObjectMethodAttribute, yöntemin amacını gösterir. Sonraki öğreticilerde de göreceğimiz gibi, ASP.NET 2.0'ın ObjectDataSource'u bir sınıftaki verilere bildirimli olarak erişmeyi kolaylaştırır. ObjectDataSource sihirbazında bağlanacak olası sınıfların listesini filtrelemeye yardımcı olmak için, varsayılan olarak sihirbazın açılan listesinde yalnızca olarak DataObjects işaretlenen sınıflar gösterilir. sınıfı ProductsBLL bu öznitelikler olmadan da aynı şekilde çalışır, ancak bunları eklemek ObjectDataSource'un sihirbazında çalışmayı kolaylaştırır.

Diğer Sınıfları Ekleme

ProductsBLL Sınıf tamamlandıktan sonra da kategoriler, tedarikçiler ve çalışanlarla çalışmak için sınıfları eklememiz gerekir. Yukarıdaki örnekte yer alan kavramları kullanarak aşağıdaki sınıfları ve yöntemleri oluşturmak için biraz zaman ayırın:

  • CategoriesBLL.cs

    • GetCategories()
    • GetCategoryByCategoryID(categoryID)
  • SuppliersBLL.cs

    • GetSuppliers()
    • GetSupplierBySupplierID(supplierID)
    • GetSuppliersByCountry(country)
    • UpdateSupplierAddress(supplierID, address, city, country)
  • EmployeesBLL.cs

    • GetEmployees()
    • GetEmployeeByEmployeeID(employeeID)
    • GetEmployeesByManager(managerID)

Dikkate değer yöntemlerden biri sınıfın SuppliersBLLUpdateSupplierAddress yöntemidir. Bu yöntem yalnızca sağlayıcının adres bilgilerini güncelleştirmek için bir arabirim sağlar. Dahili olarak, bu yöntem belirtilen supplierID için nesnesinde SupplierDataRow okur (kullanarakGetSupplierBySupplierID), adresle ilgili özelliklerini ayarlar ve ardından yöntemini Update çağırırSupplierDataTable. UpdateSupplierAddress yöntemi şu şekildedir:

<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 sınıflarını tam uygulamam için bu makalenin indirmesine bakın.

2. Adım: BLL Sınıfları Aracılığıyla Yazılan Veri Kümelerine Erişme

İlk öğreticide, Doğrudan Türü Yazılan DataSet ile program aracılığıyla çalışma örnekleri gördük, ancak BLL sınıflarımızın eklenmesiyle, sunu katmanının bunun yerine BLL'de çalışması gerekir. AllProducts.aspx İlk öğreticideki örnekte, ProductsTableAdapter aşağıdaki kodda gösterildiği gibi ürün listesini bir GridView'a bağlamak için kullanılmıştır:

Dim productsAdapter As New ProductsTableAdapter()
GridView1.DataSource = productsAdapter.GetProducts()
GridView1.DataBind()

Yeni BLL sınıflarını kullanmak için değiştirilmesi gereken tek şey, ilk kod satırının nesneyi bir ProductBLL nesneyle değiştirmesidirProductsTableAdapter:

Dim productLogic As New ProductsBLL()
GridView1.DataSource = productLogic.GetProducts()
GridView1.DataBind()

BLL sınıflara ObjectDataSource kullanılarak bildirim temelli olarak da erişilebilir (Türü Belirtilen DataSet'e olduğu gibi). Aşağıdaki öğreticilerde ObjectDataSource'a daha ayrıntılı bir şekilde değineceğiz.

Ürün Listesi GridView'da Görüntülenir

Şekil 3: Ürün Listesi GridView'da Görüntülenir (Tam boyutlu görüntüyü görüntülemek için tıklayın)

3. Adım: DataRow Sınıflarına Field-Level Doğrulaması Ekleme

Alan düzeyi doğrulama, ekleme veya güncelleştirme sırasında iş nesnelerinin özellik değerleriyle ilgili denetimlerdir. Ürünler için bazı alan düzeyinde doğrulama kuralları şunlardır:

  • Alanın ProductName uzunluğu 40 karakter veya daha kısa olmalıdır
  • Alanın QuantityPerUnit uzunluğu 20 karakter veya daha kısa olmalıdır
  • ProductID, ProductNameve Discontinued alanları gereklidir, ancak diğer tüm alanlar isteğe bağlıdır
  • UnitPrice, UnitsInStock, UnitsOnOrderve ReorderLevel alanları sıfırdan büyük veya sıfıra eşit olmalıdır

Bu kurallar veritabanı düzeyinde ifade edilebilir ve ifade edilmelidir. ve alanlarındaki ProductName karakter sınırı, tablodaki (nvarchar(40) ve nvarchar(20)) bu sütunların Products veri türleri tarafından yakalanır.QuantityPerUnit Veritabanı tablosu sütunu izin veriyorsa NULL alanların gerekli ve isteğe bağlı olup olmadığı ile ifade edilir. Yalnızca sıfırdan büyük veya sıfıra eşit değerlerin bunu , UnitsInStock, UnitsOnOrderveya ReorderLevel sütunlarına dönüştürebilmesini UnitPricesağlayan dört denetim kısıtlaması vardır.

Bu kuralları veritabanında zorunlu kılmanın yanı sıra DataSet düzeyinde de zorunlu tutulmaları gerekir. Aslında, alan uzunluğu ve bir değerin gerekli mi yoksa isteğe bağlı mı olduğu her DataTable'ın DataColumns kümesi için zaten yakalanır. Otomatik olarak sağlanan mevcut alan düzeyi doğrulamayı görmek için DataSet Tasarım Aracı gidin, DataTable'lardan birinden bir alan seçin ve Özellikler penceresi gidin. Şekil 4'te ProductsDataTable gösterildiği gibi içindeki QuantityPerUnit DataColumn değeri en fazla 20 karakter uzunluğundadır ve değerlere izin verirNULL. 's QuantityPerUnit özelliğini 20 karakterden uzun bir dize değerine ayarlamaya ProductsDataRowçalışırsak bir ArgumentException oluşturulur.

DataColumn Temel Field-Level Doğrulaması Sağlar

Şekil 4: DataColumn Temel Field-Level Doğrulaması Sağlar (Tam boyutlu görüntüyü görüntülemek için tıklayın)

Ne yazık ki, değerin sıfırdan büyük veya sıfıra eşit olması gerektiği gibi UnitPrice sınır denetimlerini Özellikler penceresi belirtemiyoruz. Bu tür bir alan düzeyinde doğrulama sağlamak için DataTable'ın ColumnChanging olayı için bir olay işleyicisi oluşturmamız gerekir. Önceki öğreticide belirtildiği gibi, Türü Belirtilmiş DataSet tarafından oluşturulan DataSet, DataTables ve DataRow nesneleri kısmi sınıfların kullanımıyla genişletilebilir. Bu tekniği kullanarak sınıfı için bir ColumnChanging olay işleyicisi ProductsDataTable oluşturabiliriz. adlı ProductsDataTable.ColumnChanging.vbklasörde bir sınıf App_Code oluşturarak başlayın.

App_Code Klasörüne Yeni Sınıf Ekleme

Şekil 5: Klasöre App_Code Yeni Sınıf Ekleme (Tam boyutlu görüntüyü görüntülemek için tıklayın)

Ardından, , , UnitsOnOrderUnitsInStockve ReorderLevel sütun değerlerinin ColumnChanging (değilseNULL) sıfırdan büyük veya sıfıra eşit olmasını sağlayan UnitPriceolay için bir olay işleyicisi oluşturun. Böyle bir sütun aralığın dışındaysa, bir ArgumentExceptionat.

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. Adım: BLL Sınıflarına Özel İş Kuralları Ekleme

Alan düzeyinde doğrulamaya ek olarak, aşağıdakiler gibi tek sütun düzeyinde ifade edilemeyen farklı varlıklar veya kavramlar içeren üst düzey özel iş kuralları da olabilir:

  • Bir ürün sonlandırılırsa, UnitPrice ürün güncelleştirilemez
  • Bir çalışanın ikamet ettiği ülke, yöneticisinin ikamet ettiği ülkeyle aynı olmalıdır
  • Bir ürün, tedarikçi tarafından sağlanan tek ürünse sonlandırılamaz

BLL sınıfları, uygulamanın iş kurallarına uygun olduğundan emin olmak için denetimler içermelidir. Bu denetimler doğrudan uygulandıkları yöntemlere eklenebilir.

İş kurallarımızın, belirli bir tedarikçinin tek ürünü olması durumunda ürünün durdurulmuş olarak işaretlenmeyeceğini dikte ettiğini düşünün. Yani, X ürünü tedarikçi Y'den satın aldığımız tek ürünse, X'i sonlandırıldı olarak işaretleyemeyiz; Ancak, tedarikçi Y bize üç ürün sağladıysa, A, B ve C, o zaman bunların herhangi birini ve tümünü sonlandırıldı olarak işaretleyebiliriz. Garip bir iş kuralı, ancak iş kuralları ve sağduyu her zaman uyumlu değildir!

Yönteminde UpdateProducts bu iş kuralını zorunlu kılmak için olarak ayarlanıp ayarlanmadığını DiscontinuedTrue denetleyerek başlayacağız ve ayarlandıysa, bu ürünün sağlayıcısından kaç ürün satın aldığımızı belirlemek için çağrıda GetProductsBySupplierID bulunuruz. Bu tedarikçiden yalnızca bir ürün satın alındıysa, bir ApplicationExceptionoluştururuz.

<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

Sunu Katmanında Doğrulama Hatalarına Yanıt Verme

BLL'yi sunu katmanından çağırırken, yükseltilebilen özel durumları işlemeye mi yoksa ASP.NET kadar kabarcık oluşturmasına izin mi verebileceğimize karar verebiliriz (bu, 'nin Error olayını tetiklerHttpApplication). BLL ile program aracılığıyla çalışırken bir özel durumu işlemek için Bir Deneyin... Aşağıdaki örnekte gösterildiği gibi catch bloğu:

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

Gelecek öğreticilerde göreceğimiz gibi, veri eklemek, güncelleştirmek veya silmek için bir veri Web denetimi kullanılırken BLL'den kabaran özel durumları işleme, kodu bloklar halinde sarmalamanın aksine doğrudan bir olay işleyicisinde Try...Catch işlenebilir.

Özet

İyi tasarlanmış bir uygulama, her biri belirli bir rolü kapsülleyen ayrı katmanlar halinde oluşturulur. Bu makale serisinin ilk öğreticisinde, Yazılan Veri Kümeleri kullanarak bir Veri Erişim Katmanı oluşturduk; bu öğreticide, uygulamamızın App_Code klasöründe DAL'mize çağrıda bulunan bir dizi sınıf olarak bir İş Mantığı Katmanı oluşturacağız. BLL, uygulamamız için alan düzeyi ve iş düzeyi mantığını uygular. Bu öğreticide yaptığımız gibi ayrı bir BLL oluşturmaya ek olarak, tableadapters yöntemlerini kısmi sınıflar kullanarak genişletmek de başka bir seçenektir. Ancak, bu tekniği kullanmak mevcut yöntemleri geçersiz kılmamıza izin vermez veya DAL ve BLL'mizi bu makalede ele aldığımız yaklaşım kadar temiz bir şekilde ayırmaz.

DAL ve BLL tamamlandıktan sonra sunu katmanımıza başlamaya hazırız. Sonraki öğreticide veri erişim konularından kısa bir sapma gerçekleştireceğiz ve öğreticiler boyunca kullanmak üzere tutarlı bir sayfa düzeni tanımlayacağız.

Mutlu Programlama!

Yazar hakkında

Yedi ASP/ASP.NET kitabının yazarı ve 4GuysFromRolla.com kurucusu Scott Mitchell, 1998'den beri Microsoft Web teknolojileriyle çalışmaktadır. Scott bağımsız bir danışman, eğitmen ve yazar olarak çalışmaktadır. Son kitabı Sams Teach Yourself ASP.NET 24 Saat içinde 2.0. Adresine adresinden veya adresinden ulaşabileceğiniz http://ScottOnWriting.NETblogu aracılığıyla ulaşabilirsinizmitchell@4GuysFromRolla.com.

Özel Teşekkürler

Bu öğretici serisi birçok yararlı gözden geçiren tarafından gözden geçirildi. Bu öğreticinin baş gözden geçirenleri Liz Shulok, Dennis Patterson, Carlos Santos ve Hilton Giesenow oldu. Yaklaşan MSDN makalelerimi gözden geçirmek istiyor musunuz? Öyleyse, bana bir satır mitchell@4GuysFromRolla.combırakın.