İyimser Eşzamanlılık Uygulama (VB)

tarafından Scott Mitchell

PDF’yi İndir

Birden çok kullanıcının verileri düzenlemesine izin veren bir web uygulaması için, iki kullanıcının aynı verileri aynı anda düzenleme riski vardır. Bu öğreticide bu riski işlemek için iyimser eşzamanlılık denetimi uygulayacağız.

Giriş

Kullanıcıların yalnızca verileri görüntülemesine izin veren web uygulamaları veya yalnızca verileri değiştirebilen tek bir kullanıcı içerenler için, iki eşzamanlı kullanıcının yanlışlıkla bir başkasının değişikliklerinin üzerine yazması tehdidi yoktur. Ancak, birden çok kullanıcının verileri güncelleştirmesine veya silmesine olanak sağlayan web uygulamaları için, bir kullanıcının değişikliklerinin başka bir eşzamanlı kullanıcınınkiyle çakışma olasılığı vardır. Herhangi bir eşzamanlılık ilkesi olmadığında, iki kullanıcı aynı anda tek bir kaydı düzenlerken, son değişikliklerini yapan kullanıcı ilk kayıt tarafından yapılan değişiklikleri geçersiz kılar.

Örneğin, Jisun ve Sam adlı iki kullanıcının uygulamamızda ziyaretçilerin gridview denetimi aracılığıyla ürünleri güncelleştirmesine ve silmesine izin veren bir sayfayı ziyaret ettiğini düşünün. Her ikisi de GridView'da Düzenle düğmesine aynı anda tıklar. Jisun, ürün adını "Chai Tea" olarak değiştirir ve Güncelleştir düğmesine tıklar. Net sonuç, veritabanına gönderilen ve ürünün güncelleştirilebilir alanlarının tümünü ayarlayan bir deyimdir (Jisun yalnızca bir UPDATE alanı güncelleştirmiş olsa bile). ProductName Bu noktada, veritabanı bu belirli bir ürün için "Chai Tea" değerlerine, İçecekler kategorisine, egzotik sıvılar kategorisine vb. sahiptir. Ancak Sam'in ekranındaki GridView yine de düzenlenebilir GridView satırında ürün adını "Chai" olarak gösterir. Jisun'un değişiklikleri işlendikten birkaç saniye sonra Sam kategoriyi Condiments olarak güncelleştirir ve Güncelleştir'e tıklar. Bu, veritabanına gönderilen ve ürün adını "Chai" CategoryID olarak, karşılık gelen İçecek kategorisi kimliğine ayarlayan bir UPDATE deyimle sonuçlanabilir. Jisun'un ürün adında yapılan değişikliklerin üzerine yazıldı. Şekil 1'de bu olay serisi grafik olarak gösterilmektedir.

İki Kullanıcı Aynı Anda Bir Kaydı Güncelleştirdiğinde, Bir Kullanıcının DiğerInin Üzerine Yazma Değişikliklerini Olasılığı Vardır

Şekil 1: İki Kullanıcı Bir Kaydı Aynı Anda Güncelleştirdiğinde, Bir Kullanıcının Diğer Kullanıcıların Üzerine Yazma Değişikliklerini Görme Olasılığı Vardır (Tam boyutlu görüntüyü görüntülemek için tıklayın)

Benzer şekilde, iki kullanıcı bir sayfayı ziyaret ettiğinde, bir kullanıcı başka bir kullanıcı tarafından silindiğinde kaydı güncelleştirmenin ortasında olabilir. Veya bir kullanıcı bir sayfayı yüklediğinde ve Sil düğmesine tıkladığında, başka bir kullanıcı bu kaydın içeriğini değiştirmiş olabilir.

Kullanılabilir üç eşzamanlılık denetimi stratejisi vardır:

  • Hiçbir Şey Yapma - eşzamanlı kullanıcılar aynı kaydı değiştiriyorsa, son işlemenin kazanmasına izin verin (varsayılan davranış)
  • İyimser Eşzamanlılık - her zaman eşzamanlılık çakışmaları olsa da, bu tür çakışmaların büyük çoğunluğunun ortaya çıkmayacağını varsayalım; bu nedenle, bir çakışma oluşursa, başka bir kullanıcı aynı verileri değiştirdiği için değişikliklerinin kaydedilemediğini kullanıcıya bildirmeniz yeterlidir
  • Kötümser Eşzamanlılık - eşzamanlılık çakışmalarının yaygın olduğunu ve kullanıcıların değişikliklerinin başka bir kullanıcının eşzamanlı etkinliği nedeniyle kaydedilmediğinin söylenmesine izin vermeyeceklerini varsayalım; bu nedenle, bir kullanıcı bir kaydı güncelleştirmeye başladığında, kaydı kilitleyerek kullanıcı değişikliklerini yürütene kadar diğer kullanıcıların bu kaydı düzenlemesini veya silmesini engelleyin

Şimdiye kadarki tüm öğreticilerimiz varsayılan eşzamanlılık çözümleme stratejisini kullandı. Yani son yazma işleminin kazanmasına izin verdik. Bu öğreticide iyimser eşzamanlılık denetiminin nasıl uygulandığını inceleyeceğiz.

Not

Bu öğretici serisinde kötümser eşzamanlılık örneklerine bakmayacağız. Kötümser eşzamanlılık nadiren kullanılır çünkü bu tür kilitler, düzgün şekilde iptal edilmediği takdirde diğer kullanıcıların verileri güncelleştirmesini engelleyebilir. Örneğin, bir kullanıcı bir kaydı düzenlemek üzere kilitler ve kilidi açmadan bir gün önce ayrılırsa, özgün kullanıcı geri dönüp güncelleştirmesini tamamlayana kadar başka hiçbir kullanıcı bu kaydı güncelleştiremez. Bu nedenle, kötümser eşzamanlılığın kullanıldığı durumlarda, genellikle ulaşılırsa kilidi iptal eden bir zaman aşımı olur. Kullanıcı sipariş işlemini tamamlarken belirli bir oturma konumunu kısa bir süre kilitleyen bilet satış web siteleri kötümser eşzamanlılık denetimi örneğidir.

1. Adım: İyimser Eşzamanlılığın Nasıl Uygulandığına Bakma

İyimser eşzamanlılık denetimi, güncelleştirilen veya silinen kaydın, güncelleştirme veya silme işlemi başladığındakiyle aynı değerlere sahip olduğundan emin olarak çalışır. Örneğin, düzenlenebilir bir GridView'da Düzenle düğmesine tıklandığında, kaydın değerleri veritabanından okunur ve TextBoxes ve diğer Web denetimlerinde görüntülenir. Bu özgün değerler GridView tarafından kaydedilir. Daha sonra, kullanıcı değişikliklerini yaptıktan ve Güncelleştir düğmesine tıkladıktan sonra, özgün değerler ve yeni değerler İş Mantığı Katmanı'na ve ardından Veri Erişim Katmanı'na gönderilir. Veri Erişim Katmanı, yalnızca kullanıcının düzenlemeye başladığı özgün değerler veritabanındaki değerlerle aynıysa kaydı güncelleştirecek bir SQL deyimi vermelidir. Şekil 2'de bu olay dizisi gösterilmektedir.

Güncelleştirme veya Silme işleminin Başarılı Olması için Özgün Değerlerin Geçerli Veritabanı Değerlerine Eşit Olması Gerekir

Şekil 2: Güncelleştirme veya Silme işleminin Başarılı Olması için Özgün Değerlerin Geçerli Veritabanı Değerlerine Eşit Olması Gerekir (Tam boyutlu görüntüyü görüntülemek için tıklayın)

İyimser eşzamanlılık uygulamaya yönelik çeşitli yaklaşımlar vardır (çeşitli seçeneklere kısa bir bakış için bkz . Peter A. Bromberg'inİyimser Eşzamanlılık Güncelleştirme Mantığı ). ADO.NET Yazılan Veri Kümesi, yalnızca onay kutusunun işaretiyle yapılandırılabilir bir uygulama sağlar. Typed DataSet içindeki bir TableAdapter için iyimser eşzamanlılık etkinleştirildiğinde TableAdapter'ın UPDATE ve DELETE deyimleri, yan tümcesindeki WHERE tüm özgün değerlerin karşılaştırmasını içerecek şekilde genişletildi. Örneğin aşağıdaki UPDATE deyim, yalnızca geçerli veritabanı değerleri GridView'da kaydı güncelleştirirken alınan değerlere eşitse ürünün adını ve fiyatını güncelleştirir. @ProductName ve @UnitPrice parametreleri kullanıcı tarafından girilen yeni değerleri içerirken @original_ProductName ve @original_UnitPrice Düzenle düğmesine tıklandığında GridView'a yüklenen değerleri içerir:

UPDATE Products SET
    ProductName = @ProductName,
    UnitPrice = @UnitPrice
WHERE
    ProductID = @original_ProductID AND
    ProductName = @original_ProductName AND
    UnitPrice = @original_UnitPrice

Not

Bu UPDATE deyim okunabilirlik için basitleştirilmiştir. Pratikte yan UnitPrice tümcesinde WHERE denetim daha fazla yer alabilir çünkü UnitPrice s içerebilir NULL ve her zaman False döndürüyorsa NULL = NULL denetim (bunun yerine kullanmanız IS NULLgerekir).

Farklı bir temel alınan UPDATE deyimi kullanmanın yanı sıra, bir TableAdapter'ın iyimser eşzamanlılık kullanacak şekilde yapılandırılması, veritabanı doğrudan yöntemlerinin imzasını da değiştirir. İlk öğreticimiz olan Veri Erişim Katmanı Oluşturma bölümünde db doğrudan yöntemlerinin giriş parametreleri olarak skaler değerlerin listesini kabul eden yöntemler olduğunu hatırlayın (kesin olarak türü belirlenmiş bir DataRow veya DataTable örneği yerine). İyimser eşzamanlılık kullanılırken, veritabanı doğrudan Update() ve Delete() yöntemleri özgün değerlerin giriş parametrelerini de içerir. Ayrıca, toplu güncelleştirme desenini kullanmaya yönelik BLL kodu ( Update() skaler değerler yerine DataRows ve DataTable'ları kabul eden yöntem aşırı yüklemeleri) de değiştirilmelidir.

Mevcut DAL'nin TableAdapter'larını iyimser eşzamanlılığı kullanacak şekilde genişletmek yerine (BLL'nin uyum sağlaması için değiştirilmesini zorunlu tutar), bunun yerine iyimser eşzamanlılık kullanan bir TableAdapter ekleyeceğimiz adlı NorthwindOptimisticConcurrencyyeni bir Products Typed DataSet oluşturalım. Bundan sonra, iyimser eşzamanlılık DAL'sini desteklemek için uygun değişikliklere sahip bir ProductsOptimisticConcurrencyBLL İş Mantığı Katmanı sınıfı oluşturacağız. Bu temel çalışma hazır olduktan sonra ASP.NET sayfasını oluşturmaya hazır olacağız.

2. Adım: İyimser Eşzamanlılığı Destekleyen Bir Veri Erişim Katmanı Oluşturma

Yeni bir Yazılan Veri Kümesi oluşturmak için, klasörün içindeki App_Code klasöre sağ tıklayın DAL ve adlı NorthwindOptimisticConcurrencyyeni bir DataSet ekleyin. İlk öğreticide gördüğümüz gibi, bunu yaptığınızda Typed DataSet'e yeni bir TableAdapter eklenir ve TableAdapter Yapılandırma Sihirbazı otomatik olarak başlatılır. İlk ekranda, bağlantısı oluşturulacak veritabanını belirtmemiz ve içinden ayarını Web.configkullanarak NORTHWNDConnectionString aynı Northwind veritabanına bağlanmamız istenir.

Aynı Northwind Veritabanına Bağlanma

Şekil 3: Aynı Northwind Veritabanına Bağlanma (Tam boyutlu görüntüyü görüntülemek için tıklayın)

Ardından, geçici bir SQL deyimi, yeni bir saklı yordam veya mevcut bir saklı yordam aracılığıyla verileri nasıl sorgulayacağımız sorulur. Özgün DAL'mizde geçici SQL sorguları kullandığımızdan bu seçeneği burada da kullanabilirsiniz.

Geçici SQL Deyimi Kullanarak Alınacak Verileri Belirtme

Şekil 4: Geçici SQL Deyimi Kullanarak Alınacak Verileri Belirtme (Tam boyutlu görüntüyü görüntülemek için tıklayın)

Aşağıdaki ekranda, ürün bilgilerini almak için kullanılacak SQL sorgusunu girin. Şimdi özgün DAL'den TableAdapter için Products kullanılan SQL sorgusunun Product aynısını kullanalım. Bu sorgu, ürünün sağlayıcı ve kategori adlarıyla birlikte tüm sütunları döndürür:

SELECT   ProductID, ProductName, SupplierID, CategoryID, QuantityPerUnit,
           UnitPrice, UnitsInStock, UnitsOnOrder, ReorderLevel, Discontinued,
           (SELECT CategoryName FROM Categories
              WHERE Categories.CategoryID = Products.CategoryID)
              as CategoryName,
           (SELECT CompanyName FROM Suppliers
              WHERE Suppliers.SupplierID = Products.SupplierID)
              as SupplierName
FROM     Products

Özgün DAL'deki Ürünler TablosuAdapter'dan Aynı SQL Sorgusunu Kullanma

Şekil 5: Özgün DAL'deki TableAdapter'dan Products Aynı SQL Sorgusunu Kullanma (Tam boyutlu görüntüyü görüntülemek için tıklayın)

Sonraki ekrana geçmeden önce Gelişmiş Seçenekler düğmesine tıklayın. Bu TableAdapter'ın iyimser eşzamanlılık denetimi kullanmasını sağlamak için "İyimser eşzamanlılık kullan" onay kutusunu işaretlemeniz yeterlidir.

Şekil 6: "İyimser eşzamanlılık kullan" Onay Kutusunu Denetleyerek İyimser Eşzamanlılık Denetimini Etkinleştirme (Tam boyutlu görüntüyü görüntülemek için tıklayın)

Son olarak, TableAdapter'ın hem DataTable'ı dolduran hem de DataTable döndüren veri erişim desenlerini kullanması gerektiğini belirtin; ayrıca doğrudan veritabanı yöntemlerinin oluşturulması gerektiğini de belirtir. Özgün DAL'mizde kullandığımız adlandırma kurallarını yansıtmak için GetData'dan GetProducts'a DataTable Döndür deseninin yöntem adını değiştirin.

TableAdapter'ın Tüm Veri Erişim Desenlerini Kullanmasını

Şekil 7: TableAdapter'ın Tüm Veri Erişim Desenlerini Kullanmasını Sağlayın (Tam boyutlu görüntüyü görüntülemek için tıklayın)

Sihirbazı tamamladıktan sonra DataSet Tasarım Aracı kesin olarak yazılmış Products bir DataTable ve TableAdapter içerir. DataTable'ın Products başlık çubuğuna ProductsOptimisticConcurrencysağ tıklayıp bağlam menüsünden Yeniden Adlandır'ı seçerek yapabileceğiniz DataTable'ı olarak yeniden adlandırmak için biraz zaman ayırın.

Yazılan DataSet'e DataTable ve TableAdapter Eklendi

Şekil 8: Yazılan Veri Kümesine DataTable ve TableAdapter Eklendi (Tam boyutlu görüntüyü görüntülemek için tıklayın)

TableAdapter (iyimser eşzamanlılık kullanan) ile Products TableAdapter (olmayan) arasındaki ve DELETE sorguları arasındaki UPDATEProductsOptimisticConcurrency farkları görmek için TableAdapter'a tıklayın ve Özellikler penceresi gidin. DeleteCommand DAL'nin CommandText güncelleştirme veya silmeyle ilgili yöntemleri çağrıldığında ve UpdateCommand özelliklerinin alt özelliklerinde veritabanına gönderilen gerçek SQL söz dizimini görebilirsiniz. ProductsOptimisticConcurrency TableAdapter DELETE için kullanılan deyim şu şekildedir:

DELETE FROM [Products]
    WHERE (([ProductID] = @Original_ProductID)
    AND ([ProductName] = @Original_ProductName)
    AND ((@IsNull_SupplierID = 1 AND [SupplierID] IS NULL)
       OR ([SupplierID] = @Original_SupplierID))
    AND ((@IsNull_CategoryID = 1 AND [CategoryID] IS NULL)
       OR ([CategoryID] = @Original_CategoryID))
    AND ((@IsNull_QuantityPerUnit = 1 AND [QuantityPerUnit] IS NULL)
       OR ([QuantityPerUnit] = @Original_QuantityPerUnit))
    AND ((@IsNull_UnitPrice = 1 AND [UnitPrice] IS NULL)
       OR ([UnitPrice] = @Original_UnitPrice))
    AND ((@IsNull_UnitsInStock = 1 AND [UnitsInStock] IS NULL)
       OR ([UnitsInStock] = @Original_UnitsInStock))
    AND ((@IsNull_UnitsOnOrder = 1 AND [UnitsOnOrder] IS NULL)
       OR ([UnitsOnOrder] = @Original_UnitsOnOrder))
    AND ((@IsNull_ReorderLevel = 1 AND [ReorderLevel] IS NULL)
       OR ([ReorderLevel] = @Original_ReorderLevel))
    AND ([Discontinued] = @Original_Discontinued))

DELETE Ancak özgün DAL'mizdeki Product TableAdapter deyimi çok daha basittir:

DELETE FROM [Products] WHERE (([ProductID] = @Original_ProductID))

Gördüğünüz gibi, WHERE TableAdapter deyiminde DELETE iyimser eşzamanlılık kullanan yan tümcesi, tablonun mevcut sütun değerlerinin her biri Product ile GridView'un (veya DetailsView veya FormView) son doldurulma zamanındaki özgün değerlerin karşılaştırmasını içerir. , ProductNameve Discontinued dışındaki tüm alanlar değerlere sahip NULL olabileceğinden ProductIDyan tümcesindeki WHERE değerleri doğru karşılaştırmak NULL için ek parametreler ve denetimler eklenir.

bu öğretici için iyimser eşzamanlılık özellikli DataSet'e ek DataTable eklemeyeceğiz çünkü ASP.NET sayfamız yalnızca ürün bilgilerini güncelleştirme ve silme bilgilerini sağlayacaktır. Ancak yine de yöntemini TableAdapter'a ProductsOptimisticConcurrency eklememiz GetProductByProductID(productID) gerekir.

Bunu yapmak için TableAdapter'ın başlık çubuğuna (ve GetProducts yöntemi adlarının hemen üstündeki Fill alan) sağ tıklayın ve bağlam menüsünden Sorgu Ekle'yi seçin. Bu işlem TableAdapter Sorgu Yapılandırma Sihirbazı'nı başlatır. TableAdapter'ın ilk yapılandırmasında GetProductByProductID(productID) olduğu gibi geçici bir SQL deyimi kullanarak yöntemini oluşturmayı tercih edin (bkz. Şekil 4). GetProductByProductID(productID) yöntemi belirli bir ürünle ilgili bilgileri döndürdüğünden, bu sorgunun satır döndüren bir SELECT sorgu türü olduğunu belirtin.

Sorgu Türünü

Şekil 9: Sorgu Türünü " satır döndüren"SELECT olarak işaretleyin (Tam boyutlu görüntüyü görüntülemek için tıklayın)

Sonraki ekranda TableAdapter'ın varsayılan sorgusu önceden yüklenmiş olarak KULLANıLACAK SQL sorgusu istenir. Şekil 10'da gösterildiği gibi, var olan sorguyu yan tümcesini WHERE ProductID = @ProductIDiçerecek şekilde genişletin.

Belirli bir Ürün Kaydını Döndürmek için Önceden Yüklenmiş Sorguya WHERE Yan Tümcesi Ekleme

Şekil 10: Belirli bir WHERE Ürün Kaydını Döndürmek için Önceden Yüklenmiş Sorguya Yan Tümce Ekleme (Tam boyutlu görüntüyü görüntülemek için tıklayın)

Son olarak, oluşturulan yöntem adlarını ve GetProductByProductIDolarak FillByProductID değiştirin.

Yöntemleri FillByProductID ve GetProductByProductID olarak yeniden adlandırın

Şekil 11: Yöntemleri FillByProductID ve GetProductByProductID olarak yeniden adlandırın (tam boyutlu görüntüyü görüntülemek için tıklayın)

Bu sihirbaz tamamlandığında TableAdapter artık verileri almak için iki yöntem içerir: GetProducts()tüm ürünleri döndüren ve GetProductByProductID(productID)belirtilen ürünü döndüren .

3. Adım: İyimser Concurrency-Enabled DAL için İş Mantığı Katmanı Oluşturma

Mevcut ProductsBLL sınıfımızda hem toplu güncelleştirme hem de veritabanı doğrudan desenlerini kullanma örnekleri vardır. Hem AddProduct yöntemi hem UpdateProduct de aşırı yüklemeleri toplu güncelleştirme desenini kullanır ve bir ProductRow örneği TableAdapter'ın Update yöntemine geçirir. DeleteProduct Diğer yandan yöntemi, TableAdapter'ın Delete(productID) yöntemini çağırarak veritabanı doğrudan desenini kullanır.

Yeni ProductsOptimisticConcurrency TableAdapter ile db doğrudan yöntemleri artık özgün değerlerin de geçirilmesini gerektirir. Örneğin, Delete yöntemi artık on giriş parametresi bekler: özgün ProductID, ProductName, SupplierID, CategoryID, , QuantityPerUnit, UnitPrice, , UnitsInStock, UnitsOnOrder, ReorderLevelve Discontinued. Veritabanına gönderilen deyiminin yan tümcesinde WHERE bu ek giriş parametrelerinin DELETE değerlerini kullanır, yalnızca veritabanının geçerli değerleri özgün kayıtlarla eşlerse belirtilen kaydı siler.

Toplu güncelleştirme deseninde kullanılan TableAdapter Update yönteminin yöntem imzası değişmemiş olsa da, özgün ve yeni değerleri kaydetmek için gereken kodda vardır. Bu nedenle, mevcut ProductsBLL sınıfımızla iyimser eşzamanlılık özellikli DAL'yi kullanmaya çalışmak yerine yeni DAL'mizle çalışmak için yeni bir İş Mantığı Katmanı sınıfı oluşturalım.

adlı bir sınıfı ProductsOptimisticConcurrencyBLLBLL klasörün içindeki App_Code klasöre ekleyin.

ProductsOptimisticConcurrencyBLL Sınıfını BLL Klasörüne Ekleme

Şekil 12: Sınıfı BLL Klasörüne Ekleme ProductsOptimisticConcurrencyBLL

Ardından sınıfına aşağıdaki kodu ProductsOptimisticConcurrencyBLL ekleyin:

Imports NorthwindOptimisticConcurrencyTableAdapters
<System.ComponentModel.DataObject()> _
Public Class ProductsOptimisticConcurrencyBLL
    Private _productsAdapter As ProductsOptimisticConcurrencyTableAdapter = Nothing
    Protected ReadOnly Property Adapter() As ProductsOptimisticConcurrencyTableAdapter
        Get
            If _productsAdapter Is Nothing Then
                _productsAdapter = New ProductsOptimisticConcurrencyTableAdapter()
            End If
            Return _productsAdapter
        End Get
    End Property
    <System.ComponentModel.DataObjectMethodAttribute _
    (System.ComponentModel.DataObjectMethodType.Select, True)> _
    Public Function GetProducts() As _
        NorthwindOptimisticConcurrency.ProductsOptimisticConcurrencyDataTable
        Return Adapter.GetProducts()
    End Function
End Class

Sınıf bildiriminin başlangıcının üzerindeki using NorthwindOptimisticConcurrencyTableAdapters deyimine dikkat edin. NorthwindOptimisticConcurrencyTableAdapters ad alanı, DAL'nin yöntemlerini sağlayan sınıfını içerirProductsOptimisticConcurrencyTableAdapter. Ayrıca sınıf bildiriminden önce, Visual Studio'ya bu sınıfı ObjectDataSource sihirbazının açılan listesine eklemesini emreden özniteliğini bulacaksınız System.ComponentModel.DataObject .

özelliği sınıfın ProductsOptimisticConcurrencyBLLbir örneğine ProductsOptimisticConcurrencyTableAdapter hızlı erişim sağlar ve özgün BLL sınıflarımızda (ProductsBLL, CategoriesBLLvb.) kullanılan deseni Adapter izler. Son olarak, yöntemi dal'ın GetProducts()GetProducts() yöntemine çağrı yaparak veritabanındaki her ürün kaydı için bir örnekle doldurulmuş bir ProductsOptimisticConcurrencyRow nesne döndürürProductsOptimisticConcurrencyDataTable.

İyimser Eşzamanlılık ile Db Doğrudan Desenini Kullanarak Bir Ürünü Silme

İyimser eşzamanlılık kullanan bir DAL'ye karşı veritabanı doğrudan deseni kullanılırken yöntemlere yeni ve özgün değerler geçirilmelidir. Silme için yeni değer olmadığından yalnızca özgün değerlerin geçirilmesi gerekir. BLL'mizde tüm özgün parametreleri giriş parametreleri olarak kabul etmeliyiz. sınıfındaki yönteminin DeleteProductProductsOptimisticConcurrencyBLL DB doğrudan yöntemini kullanmasını sağlayın. Bu, aşağıdaki kodda gösterildiği gibi bu yöntemin on ürün veri alanının tamamını giriş parametresi olarak alması ve dal'a geçirmesi gerektiği anlamına gelir:

<System.ComponentModel.DataObjectMethodAttribute _
(System.ComponentModel.DataObjectMethodType.Delete, True)> _
Public Function DeleteProduct( _
    ByVal original_productID As Integer, ByVal original_productName As String, _
    ByVal original_supplierID As Nullable(Of Integer), _
    ByVal original_categoryID As Nullable(Of Integer), _
    ByVal original_quantityPerUnit As String, _
    ByVal original_unitPrice As Nullable(Of Decimal), _
    ByVal original_unitsInStock As Nullable(Of Short), _
    ByVal original_unitsOnOrder As Nullable(Of Short), _
    ByVal original_reorderLevel As Nullable(Of Short), _
    ByVal original_discontinued As Boolean) _
    As Boolean
    Dim rowsAffected As Integer = Adapter.Delete(
                                    original_productID, _
                                    original_productName, _
                                    original_supplierID, _
                                    original_categoryID, _
                                    original_quantityPerUnit, _
                                    original_unitPrice, _
                                    original_unitsInStock, _
                                    original_unitsOnOrder, _
                                    original_reorderLevel, _
                                    original_discontinued)
    ' Return true if precisely one row was deleted, otherwise false
    Return rowsAffected = 1
End Function

Kullanıcı Sil düğmesine WHERE tıkladığında özgün değerler (GridView'a (veya DetailsView veya FormView) en son yüklenen değerler) veritabanındaki değerlerden farklıysa yan tümcesi hiçbir veritabanı kaydıyla eşleşmez ve hiçbir kayıt etkilenmez. Bu nedenle TableAdapter'ın Delete yöntemi döndürülecek 0 ve BLL'nin DeleteProduct yöntemi döndürülecektir false.

İyimser Eşzamanlılık ile Toplu Güncelleştirme Desenini Kullanarak Bir Ürünü Güncelleştirme

Daha önce belirtildiği gibi, TableAdapter'ın Update toplu güncelleştirme düzeni için yöntemi, iyimser eşzamanlılığın çalışıp çalışmadığına bakılmaksızın aynı yöntem imzasını kullanır. Yani yöntemi bir DataRow, Update datarows dizisi, DataTable veya Typed DataSet bekler. Özgün değerleri belirtmek için ek giriş parametresi yoktur. DataTable, DataRow'ları için özgün ve değiştirilmiş değerleri takip ettiğinden bu mümkündür. DAL deyimini UPDATE@original_ColumnName verdiği zaman, parametreler DataRow'un özgün değerleriyle doldurulurken @ColumnName , parametreler DataRow'un değiştirilmiş değerleriyle doldurulur.

ProductsBLL sınıfında (özgün, iyimser olmayan eşzamanlılık DAL'mizi kullanır) ürün bilgilerini güncelleştirmek için toplu güncelleştirme desenini kullanırken kodumuz aşağıdaki olay dizisini gerçekleştirir:

  1. TableAdapter'ın GetProductByProductID(productID) yöntemini kullanarak geçerli veritabanı ürün bilgilerini bir ProductRow örneğe okuma
  2. 1. Adım'dan örneğe ProductRow yeni değerler atama
  3. TableAdapter'ın Update yöntemini çağırın ve örneğini ProductRow geçirin

Ancak bu adım dizisi, 1. Adımda doldurulan değerlerin doğrudan veritabanından doldurulması nedeniyle iyimser eşzamanlılığı ProductRow doğru şekilde desteklemez; başka bir deyişle DataRow tarafından kullanılan özgün değerler, düzenleme işleminin başlangıcında GridView'a bağlı olanlar değil, şu anda veritabanında bulunan değerlerdir. Bunun yerine, iyimser eşzamanlılık özellikli bir DAL kullanırken aşağıdaki adımları kullanmak için yöntem aşırı yüklemelerini değiştirmemiz UpdateProduct gerekir:

  1. TableAdapter'ın GetProductByProductID(productID) yöntemini kullanarak geçerli veritabanı ürün bilgilerini bir ProductsOptimisticConcurrencyRow örneğe okuma
  2. 1. Adım'dan örneğe özgün değerleri ProductsOptimisticConcurrencyRow atama
  3. ProductsOptimisticConcurrencyRow DataRow'a AcceptChanges() geçerli değerlerinin "özgün" değerler olduğunu belirten örneğin yöntemini çağırın
  4. Yeni değerleri örneğe ProductsOptimisticConcurrencyRow atama
  5. TableAdapter'ın Update yöntemini çağırın ve örneğini ProductsOptimisticConcurrencyRow geçirin

1. adım, belirtilen ürün kaydı için tüm geçerli veritabanı değerlerini okur. Bu adım, tüm ürün sütunlarını güncelleştiren aşırı yüklemede UpdateProduct gereksizdir (2. Adımda bu değerlerin üzerine yazıldığı gibi), ancak sütun değerlerinin yalnızca bir alt kümesinin giriş parametresi olarak geçirildiği aşırı yüklemeler için önemlidir. Özgün değerler örneğe ProductsOptimisticConcurrencyRow atandıktan sonra, AcceptChanges() geçerli DataRow değerlerini deyimdeki parametrelerde @original_ColumnName kullanılacak özgün değerler olarak işaretleyen yöntemi çağrılır UPDATE . Ardından yeni parametre değerleri ve öğesine atanır ProductsOptimisticConcurrencyRow ve son olarak Update datarow'a geçirilerek yöntemi çağrılır.

Aşağıdaki kod, UpdateProduct tüm ürün veri alanlarını giriş parametreleri olarak kabul eden aşırı yüklemeyi gösterir. Burada gösterilmese de, ProductsOptimisticConcurrencyBLL bu öğreticinin indirmesine dahil edilen sınıf, giriş parametreleri olarak yalnızca ürünün adını ve fiyatını kabul eden bir UpdateProduct aşırı yükleme içerir.

Protected Sub AssignAllProductValues( _
    ByVal product As NorthwindOptimisticConcurrency.ProductsOptimisticConcurrencyRow, _
    ByVal productName As String, ByVal supplierID As Nullable(Of Integer), _
    ByVal categoryID As Nullable(Of Integer), ByVal quantityPerUnit As String, _
    ByVal unitPrice As Nullable(Of Decimal), ByVal unitsInStock As Nullable(Of Short), _
    ByVal unitsOnOrder As Nullable(Of Short), ByVal reorderLevel As Nullable(Of Short), _
    ByVal discontinued As Boolean)
    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
End Sub
<System.ComponentModel.DataObjectMethodAttribute( _
System.ComponentModel.DataObjectMethodType.Update, True)> _
Public Function UpdateProduct(
    ByVal productName As String, ByVal supplierID As Nullable(Of Integer), _
    ByVal categoryID As Nullable(Of Integer), ByVal quantityPerUnit As String, _
    ByVal unitPrice As Nullable(Of Decimal), ByVal unitsInStock As Nullable(Of Short), _
    ByVal unitsOnOrder As Nullable(Of Short), ByVal reorderLevel As Nullable(Of Short), _
    ByVal discontinued As Boolean, ByVal productID As Integer, _
    _
    ByVal original_productName As String, _
    ByVal original_supplierID As Nullable(Of Integer), _
    ByVal original_categoryID As Nullable(Of Integer), _
    ByVal original_quantityPerUnit As String, _
    ByVal original_unitPrice As Nullable(Of Decimal), _
    ByVal original_unitsInStock As Nullable(Of Short), _
    ByVal original_unitsOnOrder As Nullable(Of Short), _
    ByVal original_reorderLevel As Nullable(Of Short), _
    ByVal original_discontinued As Boolean, _
    ByVal original_productID As Integer) _
    As Boolean
    'STEP 1: Read in the current database product information
    Dim products As _
        NorthwindOptimisticConcurrency.ProductsOptimisticConcurrencyDataTable = _
        Adapter.GetProductByProductID(original_productID)
    If products.Count = 0 Then
        ' no matching record found, return false
        Return False
    End If
    Dim product As _
        NorthwindOptimisticConcurrency.ProductsOptimisticConcurrencyRow = products(0)
    'STEP 2: Assign the original values to the product instance
    AssignAllProductValues( _
        product, original_productName, original_supplierID, _
        original_categoryID, original_quantityPerUnit, original_unitPrice, _
        original_unitsInStock, original_unitsOnOrder, original_reorderLevel, _
        original_discontinued)
    'STEP 3: Accept the changes
    product.AcceptChanges()
    'STEP 4: Assign the new values to the product instance
    AssignAllProductValues( _
        product, productName, supplierID, categoryID, quantityPerUnit, unitPrice, _
        unitsInStock, unitsOnOrder, reorderLevel, discontinued)
    'STEP 5: Update the product record
    Dim rowsAffected As Integer = Adapter.Update(product)
    ' Return true if precisely one row was updated, otherwise false
    Return rowsAffected = 1
End Function

4. Adım: ASP.NET Sayfasından Özgün ve Yeni Değerleri BLL Yöntemlerine Geçirme

DAL ve BLL tamamlandıktan sonra geriye kalan tek şey, sistemde yerleşik olarak bulunan iyimser eşzamanlılık mantığını kullanabilen bir ASP.NET sayfası oluşturmaktır. Özellikle, veri Web denetiminin (GridView, DetailsView veya FormView) özgün değerlerini hatırlaması ve ObjectDataSource'un her iki değer kümesini de İş Mantığı Katmanı'na geçirmesi gerekir. Ayrıca, ASP.NET sayfası eşzamanlılık ihlallerini düzgün bir şekilde işleyecek şekilde yapılandırılmalıdır.

İlk olarak klasördeki EditInsertDelete sayfayı OptimisticConcurrency.aspx açın ve Tasarım Aracı bir GridView ekleyerek özelliğini olarak ProductsGridayarlayınID. GridView'un akıllı etiketinden adlı ProductsOptimisticConcurrencyDataSourceyeni bir ObjectDataSource oluşturmayı tercih edin. Bu ObjectDataSource'un iyimser eşzamanlılığı destekleyen DAL'yi kullanmasını istediğimizden, nesnesini kullanacak ProductsOptimisticConcurrencyBLL şekilde yapılandırın.

ObjectDataSource'un ProductsOptimisticConcurrencyBLL Nesnesini Kullanmasını Sağlar

Şekil 13: ObjectDataSource'un Nesneyi Kullanmasını ProductsOptimisticConcurrencyBLL Sağlayın (Tam boyutlu görüntüyü görüntülemek için tıklayın)

Sihirbazdaki GetProductsaçılan listelerden , UpdateProductve DeleteProduct yöntemlerini seçin. UpdateProduct yöntemi için ürünün tüm veri alanlarını kabul eden aşırı yüklemeyi kullanın.

ObjectDataSource Denetiminin Özelliklerini Yapılandırma

Sihirbazı tamamladıktan sonra ObjectDataSource'un bildirim temelli işaretlemesi aşağıdaki gibi görünmelidir:

<asp:ObjectDataSource ID="ProductsOptimisticConcurrencyDataSource" runat="server"
    DeleteMethod="DeleteProduct" OldValuesParameterFormatString="original_{0}"
    SelectMethod="GetProducts" TypeName="ProductsOptimisticConcurrencyBLL"
    UpdateMethod="UpdateProduct">
    <DeleteParameters>
        <asp:Parameter Name="original_productID" Type="Int32" />
        <asp:Parameter Name="original_productName" Type="String" />
        <asp:Parameter Name="original_supplierID" Type="Int32" />
        <asp:Parameter Name="original_categoryID" Type="Int32" />
        <asp:Parameter Name="original_quantityPerUnit" Type="String" />
        <asp:Parameter Name="original_unitPrice" Type="Decimal" />
        <asp:Parameter Name="original_unitsInStock" Type="Int16" />
        <asp:Parameter Name="original_unitsOnOrder" Type="Int16" />
        <asp:Parameter Name="original_reorderLevel" Type="Int16" />
        <asp:Parameter Name="original_discontinued" Type="Boolean" />
    </DeleteParameters>
    <UpdateParameters>
        <asp:Parameter Name="productName" Type="String" />
        <asp:Parameter Name="supplierID" Type="Int32" />
        <asp:Parameter Name="categoryID" Type="Int32" />
        <asp:Parameter Name="quantityPerUnit" Type="String" />
        <asp:Parameter Name="unitPrice" Type="Decimal" />
        <asp:Parameter Name="unitsInStock" Type="Int16" />
        <asp:Parameter Name="unitsOnOrder" Type="Int16" />
        <asp:Parameter Name="reorderLevel" Type="Int16" />
        <asp:Parameter Name="discontinued" Type="Boolean" />
        <asp:Parameter Name="productID" Type="Int32" />
        <asp:Parameter Name="original_productName" Type="String" />
        <asp:Parameter Name="original_supplierID" Type="Int32" />
        <asp:Parameter Name="original_categoryID" Type="Int32" />
        <asp:Parameter Name="original_quantityPerUnit" Type="String" />
        <asp:Parameter Name="original_unitPrice" Type="Decimal" />
        <asp:Parameter Name="original_unitsInStock" Type="Int16" />
        <asp:Parameter Name="original_unitsOnOrder" Type="Int16" />
        <asp:Parameter Name="original_reorderLevel" Type="Int16" />
        <asp:Parameter Name="original_discontinued" Type="Boolean" />
        <asp:Parameter Name="original_productID" Type="Int32" />
    </UpdateParameters>
</asp:ObjectDataSource>

Gördüğünüz gibi koleksiyon, sınıfın DeleteParametersDeleteProduct yöntemindeki on giriş parametresinin ProductsOptimisticConcurrencyBLL her biri için bir Parameter örnek içerir. Benzer şekilde, UpdateParameters koleksiyonu içindeki UpdateProductgiriş parametrelerinin her biri için bir Parameter örnek içerir.

Bu özellik, BLL yönteminin hem eski (veya özgün) değerlerin hem de yeni değerlerin geçirilmesini beklediğini gösterdiğinden, veri değişikliğini içeren önceki öğreticilerde ObjectDataSource OldValuesParameterFormatString özelliğini bu noktada kaldıracağız. Ayrıca, bu özellik değeri özgün değerler için giriş parametresi adlarını gösterir. Özgün değerleri BLL'ye aktardığımız için bu özelliği kaldırmayın .

Not

özelliğinin OldValuesParameterFormatString değeri, BLL'deki özgün değerleri bekleyen giriş parametresi adlarıyla eşlenmelidir. Bu parametreleri original_productName, vboriginal_supplierID. adlandırdığımız için özellik değerini olarak original_{0}bırakabilirsinizOldValuesParameterFormatString. Ancak, BLL yöntemlerinin giriş parametrelerinde , gibi old_productNameadlar varsa, özelliğini old_{0}olarak güncelleştirmeniz OldValuesParameterFormatStringold_supplierIDgerekir.

ObjectDataSource'un özgün değerleri BLL yöntemlerine doğru şekilde geçirmesi için yapılması gereken son bir özellik ayarı vardır. ObjectDataSource, iki değerden birine atanabilen bir ConflictDetection özelliğine sahiptir:

  • OverwriteChanges - varsayılan değer; özgün değerleri BLL yöntemlerinin özgün giriş parametrelerine göndermez
  • CompareAllValues - özgün değerleri BLL yöntemlerine gönderir; İyimser eşzamanlılık kullanırken bu seçeneği belirleyin

özelliğini CompareAllValuesolarak ayarlamak ConflictDetection için biraz zaman ayırın.

GridView Özelliklerini ve Alanlarını Yapılandırma

ObjectDataSource'un özellikleri düzgün yapılandırıldığında, GridView'u ayarlamaya dikkat edelim. İlk olarak, GridView'un düzenleme ve silmeyi desteklemesini istediğimizden, GridView'un akıllı etiketinden Düzenlemeyi Etkinleştir ve Silmeyi Etkinleştir onay kutularına tıklayın. Bu, ve ShowDeleteButton her ikisi de olarak trueayarlanmış bir CommandField ShowEditButton ekler.

ObjectDataSource'a ProductsOptimisticConcurrencyDataSource bağlıyken GridView, ürünün veri alanlarının her biri için bir alan içerir. Böyle bir GridView düzenlenebilir ancak kullanıcı deneyimi kabul edilebilir bir deneyimdir. CategoryID ve SupplierID BoundFields, kullanıcının uygun kategoriyi ve sağlayıcıyı kimlik numaraları olarak girmesini gerektiren TextBoxes olarak işlenir. Sayısal alanlar için biçimlendirme ve ürünün adının sağlandığından ve birim fiyatının, stoktaki birimlerin, siparişteki birimlerin ve yeniden sıralama düzeyi değerlerinin hem uygun sayısal değerler olduğundan hem de sıfırdan büyük veya sıfıra eşit olduğundan emin olmak için hiçbir doğrulama denetimi olmayacaktır.

Düzenleme ve Ekleme Arabirimlerine Doğrulama Denetimleri Ekleme veVeri Değiştirme Arabirimini Özelleştirme öğreticilerinde ele aldığımız gibi, kullanıcı arabirimi BoundFields yerine TemplateFields ile özelleştirilebilir. Bu GridView'ı ve düzenleme arabirimini aşağıdaki yollarla değiştirdim:

  • ProductID, SupplierName, ve CategoryName BoundFields kaldırıldı
  • ProductName BoundField bir TemplateField'e dönüştürüldü ve RequiredFieldValidation denetimi eklendi.
  • CategoryID ve SupplierID BoundField'leri TemplateFields'e dönüştürdü ve düzenleme arabirimini TextBoxes yerine DropDownLists kullanacak şekilde ayarladı. Bu TemplateField'lerde ItemTemplatesCategoryName ve SupplierName veri alanları görüntülenir.
  • UnitPrice, , UnitsInStockUnitsOnOrderve ReorderLevel BoundFields şablonalanlarına dönüştürüldü ve CompareValidator denetimleri eklendi.

Bu görevleri önceki öğreticilerde nasıl yerine getirebileceğimizi incelediğimizden, son bildirim temelli söz dizimini burada listeleyip uygulamayı uygulama olarak bırakacağım.

<asp:GridView ID="ProductsGrid" runat="server" AutoGenerateColumns="False"
    DataKeyNames="ProductID" DataSourceID="ProductsOptimisticConcurrencyDataSource"
    OnRowUpdated="ProductsGrid_RowUpdated">
    <Columns>
        <asp:CommandField ShowDeleteButton="True" ShowEditButton="True" />
        <asp:TemplateField HeaderText="Product" SortExpression="ProductName">
            <EditItemTemplate>
                <asp:TextBox ID="EditProductName" runat="server"
                    Text='<%# Bind("ProductName") %>'></asp:TextBox>
                <asp:RequiredFieldValidator ID="RequiredFieldValidator1"
                    ControlToValidate="EditProductName"
                    ErrorMessage="You must enter a product name."
                    runat="server">*</asp:RequiredFieldValidator>
            </EditItemTemplate>
            <ItemTemplate>
                <asp:Label ID="Label1" runat="server"
                    Text='<%# Bind("ProductName") %>'></asp:Label>
            </ItemTemplate>
        </asp:TemplateField>
        <asp:TemplateField HeaderText="Category" SortExpression="CategoryName">
            <EditItemTemplate>
                <asp:DropDownList ID="EditCategoryID" runat="server"
                    DataSourceID="CategoriesDataSource" AppendDataBoundItems="true"
                    DataTextField="CategoryName" DataValueField="CategoryID"
                    SelectedValue='<%# Bind("CategoryID") %>'>
                    <asp:ListItem Value=">(None)</asp:ListItem>
                </asp:DropDownList><asp:ObjectDataSource ID="CategoriesDataSource"
                    runat="server" OldValuesParameterFormatString="original_{0}"
                    SelectMethod="GetCategories" TypeName="CategoriesBLL">
                </asp:ObjectDataSource>
            </EditItemTemplate>
            <ItemTemplate>
                <asp:Label ID="Label2" runat="server"
                    Text='<%# Bind("CategoryName") %>'></asp:Label>
            </ItemTemplate>
        </asp:TemplateField>
        <asp:TemplateField HeaderText="Supplier" SortExpression="SupplierName">
            <EditItemTemplate>
                <asp:DropDownList ID="EditSuppliersID" runat="server"
                    DataSourceID="SuppliersDataSource" AppendDataBoundItems="true"
                    DataTextField="CompanyName" DataValueField="SupplierID"
                    SelectedValue='<%# Bind("SupplierID") %>'>
                    <asp:ListItem Value=">(None)</asp:ListItem>
                </asp:DropDownList><asp:ObjectDataSource ID="SuppliersDataSource"
                    runat="server" OldValuesParameterFormatString="original_{0}"
                    SelectMethod="GetSuppliers" TypeName="SuppliersBLL">
                </asp:ObjectDataSource>
            </EditItemTemplate>
            <ItemTemplate>
                <asp:Label ID="Label3" runat="server"
                    Text='<%# Bind("SupplierName") %>'></asp:Label>
            </ItemTemplate>
        </asp:TemplateField>
        <asp:BoundField DataField="QuantityPerUnit" HeaderText="Qty/Unit"
            SortExpression="QuantityPerUnit" />
        <asp:TemplateField HeaderText="Price" SortExpression="UnitPrice">
            <EditItemTemplate>
                <asp:TextBox ID="EditUnitPrice" runat="server"
                    Text='<%# Bind("UnitPrice", "{0:N2}") %>' Columns="8" />
                <asp:CompareValidator ID="CompareValidator1" runat="server"
                    ControlToValidate="EditUnitPrice"
                    ErrorMessage="Unit price must be a valid currency value without the
                    currency symbol and must have a value greater than or equal to zero."
                    Operator="GreaterThanEqual" Type="Currency"
                    ValueToCompare="0">*</asp:CompareValidator>
            </EditItemTemplate>
            <ItemTemplate>
                <asp:Label ID="Label4" runat="server"
                    Text='<%# Bind("UnitPrice", "{0:C}") %>'></asp:Label>
            </ItemTemplate>
        </asp:TemplateField>
        <asp:TemplateField HeaderText="Units In Stock" SortExpression="UnitsInStock">
            <EditItemTemplate>
                <asp:TextBox ID="EditUnitsInStock" runat="server"
                    Text='<%# Bind("UnitsInStock") %>' Columns="6"></asp:TextBox>
                <asp:CompareValidator ID="CompareValidator2" runat="server"
                    ControlToValidate="EditUnitsInStock"
                    ErrorMessage="Units in stock must be a valid number
                        greater than or equal to zero."
                    Operator="GreaterThanEqual" Type="Integer"
                    ValueToCompare="0">*</asp:CompareValidator>
            </EditItemTemplate>
            <ItemTemplate>
                <asp:Label ID="Label5" runat="server"
                    Text='<%# Bind("UnitsInStock", "{0:N0}") %>'></asp:Label>
            </ItemTemplate>
        </asp:TemplateField>
        <asp:TemplateField HeaderText="Units On Order" SortExpression="UnitsOnOrder">
            <EditItemTemplate>
                <asp:TextBox ID="EditUnitsOnOrder" runat="server"
                    Text='<%# Bind("UnitsOnOrder") %>' Columns="6"></asp:TextBox>
                <asp:CompareValidator ID="CompareValidator3" runat="server"
                    ControlToValidate="EditUnitsOnOrder"
                    ErrorMessage="Units on order must be a valid numeric value
                        greater than or equal to zero."
                    Operator="GreaterThanEqual" Type="Integer"
                    ValueToCompare="0">*</asp:CompareValidator>
            </EditItemTemplate>
            <ItemTemplate>
                <asp:Label ID="Label6" runat="server"
                    Text='<%# Bind("UnitsOnOrder", "{0:N0}") %>'></asp:Label>
            </ItemTemplate>
        </asp:TemplateField>
        <asp:TemplateField HeaderText="Reorder Level" SortExpression="ReorderLevel">
            <EditItemTemplate>
                <asp:TextBox ID="EditReorderLevel" runat="server"
                    Text='<%# Bind("ReorderLevel") %>' Columns="6"></asp:TextBox>
                <asp:CompareValidator ID="CompareValidator4" runat="server"
                    ControlToValidate="EditReorderLevel"
                    ErrorMessage="Reorder level must be a valid numeric value
                        greater than or equal to zero."
                    Operator="GreaterThanEqual" Type="Integer"
                    ValueToCompare="0">*</asp:CompareValidator>
            </EditItemTemplate>
            <ItemTemplate>
                <asp:Label ID="Label7" runat="server"
                    Text='<%# Bind("ReorderLevel", "{0:N0}") %>'></asp:Label>
            </ItemTemplate>
        </asp:TemplateField>
        <asp:CheckBoxField DataField="Discontinued" HeaderText="Discontinued"
            SortExpression="Discontinued" />
    </Columns>
</asp:GridView>

Tam olarak çalışan bir örnekle çok yakınız. Ancak, sürünecek ve bize sorunlara neden olacak birkaç incelik vardır. Buna ek olarak, eşzamanlılık ihlali oluştuğunda kullanıcıyı uyaran bir arabirime ihtiyacımız var.

Not

Veri Web denetiminin özgün değerleri ObjectDataSource'a doğru bir şekilde geçirmesi için (daha sonra BLL'ye geçirilir), GridView özelliğinin EnableViewState (varsayılan) olarak ayarlanması true çok önemlidir. Görünüm durumunu devre dışı bırakırsanız, özgün değerler geri göndermede kaybolur.

ObjectDataSource'a Doğru Özgün Değerleri Geçirme

GridView'un yapılandırılma şekliyle ilgili birkaç sorun vardır. ObjectDataSource'un ConflictDetection özelliği (bizim olduğu gibi) olarak ayarlanırsa CompareAllValues , ObjectDataSource'un Update() veya Delete() yöntemleri GridView (veya DetailsView veya FormView) tarafından çağrıldığında, ObjectDataSource GridView'un özgün değerlerini uygun Parameter örneklerine kopyalamayı dener. Bu işlemin grafik gösterimi için Şekil 2'ye geri bakın.

Özellikle, GridView'un özgün değerlerine, veriler GridView'a her bağlandığında iki yönlü veri bağlama deyimlerindeki değerler atanır. Bu nedenle, gerekli özgün değerlerin tümünün iki yönlü veri bağlama yoluyla yakalanması ve dönüştürülebilir bir biçimde sağlanması önemlidir.

Bunun neden önemli olduğunu görmek için bir dakika ayırarak sayfamızı bir tarayıcıda ziyaret edin. Beklendiği gibi GridView, her ürünü en soldaki sütunda düzenle ve sil düğmesiyle listeler.

Ürünler GridView'da Listelenir

Şekil 14: Ürünler GridView'da Listelenir (Tam boyutlu görüntüyü görüntülemek için tıklayın)

Herhangi bir ürün için Sil düğmesine tıklarsanız, bir FormatException oluşturulur.

FormatException'da Herhangi Bir Ürün Sonucunu Silmeye Çalışma

Şekil 15: Bir içindeki Herhangi Bir FormatException Ürün Sonucunu Silmeye Çalışma (Tam boyutlu görüntüyü görüntülemek için tıklayın)

FormatException, ObjectDataSource özgün UnitPrice değerde okumayı denediğinde oluşturulur. ItemTemplate para birimi ()<%# Bind("UnitPrice", "{0:C}") %> olarak biçimlendirildiğindenUnitPrice, 19,95 ABD doları gibi bir para birimi simgesi içerir. , FormatException ObjectDataSource bu dizeyi öğesine decimaldönüştürmeye çalıştığında gerçekleşir. Bu sorunu aşmak için birkaç seçeneğimiz vardır:

  • para birimi biçimlendirmesini ItemTemplateiçinden kaldırın. Diğer bir ifadeyle kullanmak yerine <%# Bind("UnitPrice", "{0:C}") %>yalnızca kullanın <%# Bind("UnitPrice") %>. Bunun dezavantajı, fiyatın artık biçimlendirilmemiş olmasıdır.
  • UnitPrice Biçimlendirilmiş para birimini içinde ItemTemplatebir para birimi olarak görüntüleyin, ancak bunu gerçekleştirmek için anahtar sözcüğünü Eval kullanın. Bunun tek yönlü veri bağlama işlemi gerçekleştirdiğini Eval hatırlayın. Özgün değerlerin değerini sağlamamız gerektiğinden UnitPrice , içinde yine de iki yönlü bir veri bağlama deyimine ItemTemplateihtiyacımız olacaktır, ancak bu özellik olarak ayarlanmış bir Etiket Web denetimine Visiblefalseyerleştirilebilir. ItemTemplate içinde aşağıdaki işaretlemeyi kullanabiliriz:
<ItemTemplate>
    <asp:Label ID="DummyUnitPrice" runat="server"
        Text='<%# Bind("UnitPrice") %>' Visible="false"></asp:Label>
    <asp:Label ID="Label4" runat="server"
        Text='<%# Eval("UnitPrice", "{0:C}") %>'></asp:Label>
</ItemTemplate>
  • kullanarak <%# Bind("UnitPrice") %>para birimi biçimlendirmesini ItemTemplateiçinden kaldırın. GridView'un RowDataBound olay işleyicisinde, değerin görüntülendiği Label Web denetimine UnitPrice program aracılığıyla erişin ve özelliğini biçimlendirilmiş sürüme ayarlayın Text .
  • UnitPrice Para birimi olarak biçimlendirilmiş olarak bırakın. GridView'un RowDeleting olay işleyicisinde, kullanarak Decimal.Parsemevcut özgün UnitPrice değeri ($19,95) gerçek ondalık değerle değiştirin. bir ASP.NET Sayfasındaki BLL- ve DAL-Level Özel Durumlarını İşleme öğreticisindeki olay işleyicisinde benzer RowUpdating bir şeyin nasıl gerçekleştirildiğini gördük.

Örneğim için, özelliği biçimlendirilmemiş UnitPrice değere bağlı iki yönlü veriler olan Text gizli bir Label Web denetimi ekleyerek ikinci yaklaşımı tercih ettim.

Bu sorunu çözdükten sonra herhangi bir ürün için Sil düğmesine tıklamayı yeniden deneyin. Bu kez, ObjectDataSource BLL'nin UpdateProduct yöntemini çağırmaya çalıştığında bir InvalidOperationException alırsınız.

ObjectDataSource Göndermek istediği Giriş Parametrelerine Sahip Bir Yöntemi Bulamıyor

Şekil 16: ObjectDataSource Göndermek istediği Giriş Parametrelerine Sahip Bir Yöntemi Bulamıyor (Tam boyutlu görüntüyü görüntülemek için tıklayın)

Özel durumun iletisine baktığımızda, ObjectDataSource'un ve original_SupplierName giriş parametrelerini içeren original_CategoryName bir BLL DeleteProduct yöntemini çağırmak istediği açıktır. Bunun nedeni, ve SupplierID TemplateFields için CategoryID s şu anda ve SupplierName veri alanlarıyla iki yönlü Bind deyimleri içermesidirCategoryName.ItemTemplate Bunun yerine ve SupplierID veri alanlarına deyimleri CategoryID eklememiz Bind gerekir. Bunu yapmak için, var olan Bind deyimlerini deyimleriyle Eval değiştirin ve ardından aşağıda gösterildiği gibi iki yönlü veri bağlama kullanarak ve SupplierID veri alanlarına bağlı CategoryID olan gizli Etiket denetimleri Text ekleyin:

<asp:TemplateField HeaderText="Category" SortExpression="CategoryName">
    <EditItemTemplate>
        ...
    </EditItemTemplate>
    <ItemTemplate>
        <asp:Label ID="DummyCategoryID" runat="server"
            Text='<%# Bind("CategoryID") %>' Visible="False"></asp:Label>
        <asp:Label ID="Label2" runat="server"
            Text='<%# Eval("CategoryName") %>'></asp:Label>
    </ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Supplier" SortExpression="SupplierName">
    <EditItemTemplate>
        ...
    </EditItemTemplate>
    <ItemTemplate>
        <asp:Label ID="DummySupplierID" runat="server"
            Text='<%# Bind("SupplierID") %>' Visible="False"></asp:Label>
        <asp:Label ID="Label3" runat="server"
            Text='<%# Eval("SupplierName") %>'></asp:Label>
    </ItemTemplate>
</asp:TemplateField>

Bu değişikliklerle artık ürün bilgilerini başarıyla silip düzenleyebiliyoruz! 5. Adım'da eşzamanlılık ihlallerinin algılandığını doğrulamayı inceleyeceğiz. Ancak şimdilik, tek bir kullanıcı için güncelleştirme ve silmenin beklendiği gibi çalıştığından emin olmak için birkaç kaydı güncelleştirmeyi ve silmeyi denemeniz birkaç dakika sürer.

5. Adım: İyimser Eşzamanlılık Desteğini Test Etme

Eşzamanlılık ihlallerinin algılandığını doğrulamak için (verilerin üzerine körü körüne yazılmasına neden olmak yerine) bu sayfaya iki tarayıcı penceresi açmamız gerekir. Her iki tarayıcı örneğinde de Chai için Düzenle düğmesine tıklayın. Ardından, tarayıcılardan yalnızca birinde adı "Chai Tea" olarak değiştirin ve Güncelleştir'e tıklayın. Güncelleştirme başarılı olmalı ve GridView'u yeni ürün adı olarak "Chai Tea" ile ön düzenleme durumuna döndürmelidir.

Öte yandan diğer tarayıcı penceresi örneğinde, TextBox ürün adı hala "Chai" olarak gösterilir. Bu ikinci tarayıcı penceresinde öğesini olarak 25.00güncelleştirinUnitPrice. İyimser eşzamanlılık desteği olmadan, ikinci tarayıcı örneğinde güncelleştirme seçeneğine tıklanması ürün adını "Chai" olarak değiştirir ve böylece ilk tarayıcı örneği tarafından yapılan değişikliklerin üzerine yazılır. İyimser eşzamanlılık kullanılırken, ikinci tarayıcı örneğinde Güncelleştir düğmesine tıklanması DBConcurrencyException ile sonuçlanmıştır.

Eşzamanlılık İhlali Algılandığında DBConcurrencyException Oluşturulur

Şekil 17: Eşzamanlılık İhlali Algılandığında, bir DBConcurrencyException Oluşturulur (Tam boyutlu görüntüyü görüntülemek için tıklayın)

DBConcurrencyException yalnızca DAL'nin toplu güncelleştirme deseni kullanıldığında oluşturulur. Veritabanı doğrudan deseni bir özel durum oluşturmaz, yalnızca hiçbir satırın etkilenmediğini gösterir. Bunu göstermek için her iki tarayıcı örneğinin GridView değerini de düzenleme öncesi durumlarına döndürin. Ardından, ilk tarayıcı örneğinde Düzenle düğmesine tıklayın ve ürün adını "Chai Tea" yerine "Chai" olarak değiştirin ve Güncelleştir'e tıklayın. İkinci tarayıcı penceresinde Chai için Sil düğmesine tıklayın.

Sil'e tıklanması üzerine sayfa geri gönderir, GridView ObjectDataSource'un Delete() yöntemini çağırır ve ObjectDataSource sınıfın ProductsOptimisticConcurrencyBLLDeleteProduct yöntemine çağrı yaparak özgün değerleri geçirir. İkinci tarayıcı örneğinin özgün ProductName değeri ,veritabanındaki geçerli ProductName değerle eşleşmeyen "Chai Tea" değeridir. Bu nedenle DELETE , veritabanında yan tümcenin karşılediği kayıt olmadığından veritabanına WHERE verilen deyim sıfır satırı etkiler. DeleteProduct yöntemi döndürür false ve ObjectDataSource'un verileri GridView'a yeniden eklenir.

Son kullanıcının perspektifinden, ikinci tarayıcı penceresinde Chai Tea için Sil düğmesine tıklanması ekranın yanıp sönmesine neden oldu ve geri döndükten sonra ürün hala orada, ancak artık "Chai" olarak listeleniyor (ilk tarayıcı örneği tarafından yapılan ürün adı değişikliği). Kullanıcı Sil düğmesine yeniden tıklarsa, GridView'un özgün ProductName değeri ("Chai") artık veritabanındaki değerle eşleştiğinden Sil başarılı olur.

Bu iki durumda da kullanıcı deneyimi idealden çok uzaktır. Toplu güncelleştirme desenini kullanırken kullanıcıya özel durumun nitty-gritty ayrıntılarını DBConcurrencyException göstermek istemediğimiz açıktır. Kullanıcılar komutu başarısız olduğundan veritabanı doğrudan desenini kullanma davranışı biraz kafa karıştırıcı olsa da bunun nedeninin kesin bir göstergesi yoktu.

Bu iki sorunu gidermek için, sayfada bir güncelleştirmenin veya silmenin neden başarısız olduğuna ilişkin bir açıklama sağlayan Etiket Web denetimleri oluşturabiliriz. Toplu güncelleştirme düzeni için GridView'un son düzey olay işleyicisinde uyarı etiketini gerektiği gibi görüntüleyen bir DBConcurrencyException özel durumun oluşup oluşmadığını belirleyebiliriz. Db doğrudan yöntemi için BLL yönteminin dönüş değerini inceleyebilir ( true bir satır etkilendiyse, false aksi takdirde) ve gerektiğinde bilgilendirsel bir ileti görüntüleyebiliriz.

6. Adım: Bilgilendirici İletiler Ekleme ve Eşzamanlılık İhlali Karşısında Görüntüleme

Eşzamanlılık ihlali oluştuğunda, sergilenen davranış DAL'ın toplu güncelleştirmesinin mi yoksa VERITABANı doğrudan deseninin mi kullanıldığına bağlıdır. Öğreticimizde, güncelleştirme için toplu güncelleştirme deseni ve silme için kullanılan veritabanı doğrudan deseni ile birlikte her iki desen de kullanılmaktadır. Başlamak için sayfamıza verileri silmeye veya güncelleştirmeye çalışırken eşzamanlılık ihlalinin oluştuğuna ilişkin iki Label Web denetimi ekleyelim. Etiket denetiminin Visible ve EnableViewState özelliklerini olarak falseayarlayın; bu, özelliklerinin program aracılığıyla olarak ayarlandığı belirli sayfa ziyaretleri dışında her sayfa ziyaretinde gizlenmelerine Visibletrueneden olur.

<asp:Label ID="DeleteConflictMessage" runat="server" Visible="False"
    EnableViewState="False" CssClass="Warning"
    Text="The record you attempted to delete has been modified by another user
           since you last visited this page. Your delete was cancelled to allow
           you to review the other user's changes and determine if you want to
           continue deleting this record." />
<asp:Label ID="UpdateConflictMessage" runat="server" Visible="False"
    EnableViewState="False" CssClass="Warning"
    Text="The record you attempted to update has been modified by another user
           since you started the update process. Your changes have been replaced
           with the current values. Please review the existing values and make
           any needed changes." />

, ve TextEnabledViewStateözelliklerini ayarlamaya Visibleek olarak, özelliğini Warningolarak da ayarladımCssClass. Bu özellik, Etiketin büyük, kırmızı, italik ve kalın yazı tipinde görüntülenmesine neden oluyor. Bu CSS Warning sınıfı tanımlandı ve ekleme, güncelleştirme ve silme ile ilişkili olayları inceleme öğreticisinde Styles.css geri eklendi.

Bu Etiketleri ekledikten sonra Visual Studio'daki Tasarım Aracı Şekil 18'e benzer görünmelidir.

Sayfaya İki Etiket Denetimi Eklendi

Şekil 18: Sayfaya İki Etiket Denetimi Eklendi (Tam boyutlu görüntüyü görüntülemek için tıklayın)

Bu Etiket Web denetimleri uygulandığında, bir eşzamanlılık ihlalinin ne zaman oluştuğunun nasıl belirleneceğini incelemeye hazırız. Bu noktada, bilgilendirici iletiyi görüntüleyen uygun Label'ın Visible özelliği olarak trueayarlanabilir.

Güncelleştirme Sırasında Eşzamanlılık İhlallerini İşleme

Şimdi ilk olarak toplu güncelleştirme desenini kullanırken eşzamanlılık ihlallerini işlemeye bakalım. Toplu güncelleştirme düzeniyle ilgili bu tür ihlaller özel durum DBConcurrencyException oluşturmasına neden olduğundan, güncelleştirme işlemi sırasında bir DBConcurrencyException özel durumun oluşup oluşmadığını belirlemek için ASP.NET sayfamıza kod eklememiz gerekir. Bu durumda, kullanıcıya, başka bir kullanıcı kaydı düzenlemeye başladığı ve Güncelleştir düğmesine tıklaması arasında aynı verileri değiştirdiği için değişikliklerinin kaydedilmediğini açıklayan bir ileti görüntülememiz gerekir.

bir ASP.NET Sayfasındaki BLL- ve DAL-Level Özel Durumlarını İşleme öğreticisinde gördüğümüz gibi, bu tür özel durumlar veri Web denetiminin son düzey olay işleyicilerinde algılanabilir ve gizlenebilir. Bu nedenle, GridView'un RowUpdated olayı için özel durumun oluşturulup oluşturulmadığını denetleen bir DBConcurrencyException olay işleyicisi oluşturmamız gerekir. Bu olay işleyicisine, aşağıdaki olay işleyici kodunda gösterildiği gibi güncelleştirme işlemi sırasında oluşturulan herhangi bir özel duruma başvuru geçirilir:

Protected Sub ProductsGrid_RowUpdated _
        (ByVal sender As Object, ByVal e As GridViewUpdatedEventArgs) _
        Handles ProductsGrid.RowUpdated
    If e.Exception IsNot Nothing AndAlso e.Exception.InnerException IsNot Nothing Then
        If TypeOf e.Exception.InnerException Is System.Data.DBConcurrencyException Then
            ' Display the warning message and note that the exception has
            ' been handled...
            UpdateConflictMessage.Visible = True
            e.ExceptionHandled = True
        End If
    End If
End Sub

Bir DBConcurrencyException özel durum karşısında, bu olay işleyicisi Etiket denetimini görüntüler UpdateConflictMessage ve özel durumun işlendiğini gösterir. Bu kod uygulandığında, bir kayıt güncelleştirilirken eşzamanlılık ihlali oluştuğunda kullanıcının değişiklikleri kaybolur çünkü aynı anda başka bir kullanıcının değişikliklerinin üzerine yazılırdı. Özellikle GridView, düzenleme öncesi durumuna döndürülür ve geçerli veritabanı verilerine bağlanır. Bu, GridView satırını daha önce görünür olmayan diğer kullanıcının değişiklikleriyle güncelleştirir. Ayrıca, UpdateConflictMessage Etiket denetimi kullanıcıya az önce ne olduğunu açıklar. Bu olay dizisi Şekil 19'da ayrıntılı olarak anlatılır.

Bir Kullanıcının Güncelleştirmeler Eşzamanlılık İhlali Karşısında Kaybolur

Şekil 19: Eşzamanlılık İhlaliNin Karşısında Kullanıcının Güncelleştirmeler Kayboldu (Tam boyutlu görüntüyü görüntülemek için tıklayın)

Not

Alternatif olarak, GridView'u düzenleme öncesi durumuna döndürmek yerine, geçirilen nesnenin özelliğini true olarak ayarlayarak KeepInEditMode GridView'u GridViewUpdatedEventArgs düzenleme durumunda bırakabiliriz. Ancak bu yaklaşımı benimsediğinizde, diğer kullanıcının değerlerinin düzenleme arabirimine yüklenmesi için verileri GridView'a yeniden bağlamayı (yöntemini çağırarak DataBind() ) emin olun. Bu öğreticiyle indirilebilen kod, olay işleyicisinde RowUpdated şu iki kod satırına açıklama satırı eklenmiştir; GridView'un eşzamanlılık ihlalinden sonra düzenleme modunda kalması için bu kod satırlarını açıklamadan çıkarmanız yeterlidir.

Silerken Eşzamanlılık İhlallerine Yanıt Verme

Veritabanı doğrudan deseni ile eşzamanlılık ihlaline karşı oluşturulan bir özel durum yoktur. Bunun yerine, WHERE yan tümcesi herhangi bir kayıtla eşleşmediğinden veritabanı deyimi hiçbir kaydı etkilemez. BLL'de oluşturulan tüm veri değiştirme yöntemleri, tam olarak bir kaydı etkileyip etkilemediklerini belirten bir Boole değeri döndürecekler şekilde tasarlanmıştır. Bu nedenle, bir kayıt silinirken eşzamanlılık ihlalinin oluşup oluşmadığını belirlemek için BLL'nin DeleteProduct yönteminin dönüş değerini inceleyebiliriz.

Bir BLL yönteminin dönüş değeri, olay işleyicisine geçirilen nesnenin ObjectDataSourceStatusEventArgs özelliği aracılığıyla ReturnValue ObjectDataSource'un son düzey olay işleyicilerinde incelenebilir. yönteminden DeleteProduct dönüş değerini belirlemekle ilgilendiğimiz için ObjectDataSource'un Deleted olayı için bir olay işleyicisi oluşturmamız gerekir. ReturnValue özelliği türündedir object ve bir özel durum oluşturulduysa ve yöntem bir değer döndürmeden önce kesildiyse olabilirnull. Bu nedenle, önce özelliğin ReturnValue bir Boole değeri olmadığından null ve olmadığından emin olmalıyız. Bu denetimin başarılı olduğunu varsayarsak, etiketi ReturnValuefalseise Etiket denetimini gösteririzDeleteConflictMessage. Bu, aşağıdaki kod kullanılarak gerçekleştirilebilir:

Protected Sub ProductsOptimisticConcurrencyDataSource_Deleted _
        (ByVal sender As Object, ByVal e As ObjectDataSourceStatusEventArgs) _
        Handles ProductsOptimisticConcurrencyDataSource.Deleted
    If e.ReturnValue IsNot Nothing AndAlso TypeOf e.ReturnValue Is Boolean Then
        Dim deleteReturnValue As Boolean = CType(e.ReturnValue, Boolean)
        If deleteReturnValue = False Then
            ' No row was deleted, display the warning message
            DeleteConflictMessage.Visible = True
        End If
    End If
End Sub

Eşzamanlılık ihlali durumunda kullanıcının silme isteği iptal edilir. GridView yenilenir ve bu kayıt için kullanıcının sayfayı yüklediği zaman ile Sil düğmesine tıklaması arasında gerçekleşen değişiklikler gösterilir. Böyle bir ihlal gerçekleştiğinde DeleteConflictMessage , az önce ne olduğunu açıklayan Etiket gösterilir (bkz. Şekil 20).

Eşzamanlılık İhlali Karşısında Kullanıcı Silme İptal Edildi

Şekil 20: Eşzamanlılık İhlaliNin Karşısında Kullanıcı Silme İptal Edildi (Tam boyutlu görüntüyü görüntülemek için tıklayın)

Özet

Eşzamanlılık ihlalleri için fırsatlar, birden çok eşzamanlı kullanıcının verileri güncelleştirmesine veya silmesine olanak tanıyan her uygulamada mevcuttur. Bu tür ihlaller dikkate alınmazsa, iki kullanıcı aynı anda aynı verileri güncelleştirdiğinde, son yazmada "kazanır" yazan diğer kullanıcının değişikliklerinin üzerine yazılır. Alternatif olarak geliştiriciler iyimser veya kötümser eşzamanlılık denetimi uygulayabilir. İyimser eşzamanlılık denetimi, eşzamanlılık ihlallerinin seyrek olduğunu varsayar ve yalnızca eşzamanlılık ihlali oluşturacak bir güncelleştirme veya silme komutuna izin vermemektedir. Kötümser eşzamanlılık denetimi, eşzamanlılık ihlallerinin sık sık olduğunu varsayar ve yalnızca bir kullanıcının güncelleştirme veya silme komutunu reddetmenin kabul edilemez olduğunu varsayar. Kötümser eşzamanlılık denetimiyle bir kaydın güncelleştirilmesi, kaydın kilitlenmesini ve böylece diğer kullanıcıların kilitliyken kaydı değiştirmesini veya silmesini önler.

.NET'te Yazılan Veri Kümesi, iyimser eşzamanlılık denetimini desteklemek için işlevsellik sağlar. Özellikle, UPDATE veritabanına verilen ve DELETE deyimleri tablonun tüm sütunlarını içerir, böylece güncelleştirme veya silme işleminin yalnızca kaydın geçerli verileri kullanıcının güncelleştirme veya silme işlemini gerçekleştirirken sahip olduğu özgün verilerle eşleşmesi durumunda gerçekleşmesini sağlar. DAL iyimser eşzamanlılığı destekleyecek şekilde yapılandırıldıktan sonra BLL yöntemlerinin güncelleştirilmiş olması gerekir. Buna ek olarak, BLL'ye çağrıda bulunan ASP.NET sayfası, ObjectDataSource'un özgün değerleri veri Web denetiminden alıp BLL'ye iletecek şekilde yapılandırılması gerekir.

Bu öğreticide gördüğümüz gibi, ASP.NET bir web uygulamasında iyimser eşzamanlılık denetimi uygulamak için DAL ve BLL'nin güncelleştirilmesi ve ASP.NET sayfasına destek eklenmesi gerekir. Bu eklenen çalışmanın zamanınızın ve çabanızın akıllıca bir yatırımı olup olmadığı uygulamanıza bağlıdır. Verileri güncelleştiren eş zamanlı kullanıcılarınız nadiren varsa veya güncelleştirdikleri veriler birbirinden farklıysa, eşzamanlılık denetimi önemli bir sorun değildir. Ancak, sitenizde aynı verilerle düzenli olarak birden çok kullanıcı çalışıyorsa eşzamanlılık denetimi, bir kullanıcının güncelleştirmelerinin veya silmelerinin farkında olmadan başka birinin üzerine yazılmasını önlemeye yardımcı olabilir.

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 Hours 2.0'dır. Adresine adresinden veya adresinden ulaşabileceğiniz http://ScottOnWriting.NETblogu aracılığıyla ulaşabilirsinizmitchell@4GuysFromRolla.com.