Veritabanı Değişikliklerini Bir İşlemin İçinde Sarmalama (C#)

tarafından Scott Mitchell

PDF'i indirin

Bu öğretici, toplu veri güncelleştirme, silme ve ekleme işlemlerinin dördünden ilkidir. Bu öğreticide, veritabanı işlemlerinin toplu değişikliklerin atomik bir işlem olarak gerçekleştirilmesini nasıl sağladığını ve bu sayede tüm adımların başarılı olmasını veya tüm adımların başarısız olmasını nasıl sağladığını öğreneceğiz.

Giriş

Veri Ekleme, Güncelleştirme ve Silmeye Genel Bakış öğreticisiyle başladığımız gibi, GridView satır düzeyinde düzenleme ve silme için yerleşik destek sağlar. Farenin birkaç tıklamasıyla, satır başına düzenleme ve silme işlemine uygun olduğunuz sürece, bir kod satırı yazmadan zengin bir veri değiştirme arabirimi oluşturmak mümkündür. Ancak, bazı senaryolarda bu yetersizdir ve kullanıcılara bir grup kaydı düzenleme veya silme olanağı sağlamamız gerekir.

Örneğin, çoğu web tabanlı e-posta istemcisi, her satırın e-posta bilgileri (konu, gönderen vb.) ile birlikte bir onay kutusu içerdiği her iletiyi listelemek için bir kılavuz kullanır. Bu arabirim, kullanıcının birden çok iletiyi denetleyerek ve ardından Seçili İletileri Sil düğmesine tıklayarak silmesine izin verir. Toplu düzenleme arabirimi, kullanıcıların yaygın olarak birçok farklı kaydı düzenlediği durumlarda idealdir. Kullanıcıyı Düzenle'ye tıklamaya, değişiklik yapmaya ve ardından değiştirilmesi gereken her kayıt için Güncelleştir'e tıklamaya zorlamak yerine, toplu düzenleme arabirimi her satırı düzenleme arabirimiyle işler. Kullanıcı değiştirilmesi gereken satır kümesini hızla değiştirebilir ve ardından Tümünü Güncelleştir düğmesine tıklayarak bu değişiklikleri kaydedebilir. Bu öğretici kümesinde, toplu veri ekleme, düzenleme ve silme arabirimlerinin nasıl oluşturulacağını inceleyeceğiz.

Toplu işlem gerçekleştirirken, bazıları başarısız olurken toplu işteki bazı işlemlerin başarılı olup olmayacağını belirlemek önemlidir. Toplu silme arabirimini göz önünde bulundurun- seçilen ilk kayıt başarıyla silinirse ancak ikinci kayıt başarısız olursa ( örneğin, yabancı anahtar kısıtlama ihlali nedeniyle) ne olur? İlk kaydın silinmesi geri alınsın mı yoksa ilk kaydın silinmeye devam etmesi kabul edilebilir mi?

Toplu işlemin, tüm adımların başarılı veya tüm adımların başarısız olduğu bir atomik işlem olarak değerlendirilmesini istiyorsanız, veri erişim katmanının veritabanı işlemleri için destek içerecek şekilde genişletilmesi gerekir. Veritabanı işlemleri, işlem çatısı INSERTaltında yürütülen , UPDATEve DELETE deyimleri kümesi için bölünmezliği garanti eder ve tüm modern veritabanı sistemlerinin çoğu tarafından desteklenen bir özelliktir.

Bu öğreticide DAL'yi veritabanı işlemlerini kullanacak şekilde genişletmeyi inceleyeceğiz. Sonraki öğreticilerde, arabirimleri toplu ekleme, güncelleştirme ve silme için web sayfalarının uygulanması incelenir. Haydi başlayalım!

Not

Toplu işlemdeki verileri değiştirirken, bölünmezlik her zaman gerekli değildir. Bazı senaryolarda, web tabanlı bir e-posta istemcisinden bir dizi e-postayı silerken olduğu gibi bazı veri değişikliklerinin başarılı olması ve diğerlerinin aynı toplu işlemde başarısız olması kabul edilebilir. Silme işleminin ortasında bir veritabanı hatası varsa, hata olmadan işlenen bu kayıtların silinmiş olarak kalması büyük olasılıkla kabul edilebilir. Bu gibi durumlarda DAL'nin veritabanı işlemlerini desteklemek için değiştirilmesi gerekmez. Ancak, bölünmezliğin önemli olduğu başka toplu işlem senaryoları da vardır. Bir müşteri fonlarını bir banka hesabından diğerine taşırken iki işlem yapılmalıdır: fonlar ilk hesaptan düşülmeli ve sonra ikinci hesaba eklenmelidir. Banka ilk adımın başarılı olmasına aldırmıyor olsa da, ikinci adım başarısız olsa da müşterileri anlaşılır bir şekilde üzülecek. Bu öğreticide çalışmanızı ve aşağıdaki üç öğreticide oluşturacağımız arabirimleri toplu ekleme, güncelleştirme ve silme işlemlerinde kullanmayı planlamıyor olsanız bile veritabanı işlemlerini desteklemek için DAL'de yapılan geliştirmeleri uygulamanızı öneririz.

İşlemlere Genel Bakış

Veritabanlarının çoğu, birden çok veritabanı komutlarının tek bir mantıksal iş birimi halinde gruplandırılabilmesini sağlayan işlemlere yönelik destek içerir. bir işlemi oluşturan veritabanı komutlarının atomik olması garanti edilir, yani tüm komutlar başarısız olur veya tümü başarılı olur.

Genel olarak, işlemler aşağıdaki desen kullanılarak SQL deyimleri aracılığıyla uygulanır:

  1. İşlemin başlangıcını belirtin.
  2. İşlemi oluşturan SQL deyimlerini yürütür.
  3. 2. Adım'daki deyimlerden birinde hata varsa işlemi geri alın.
  4. 2. Adımdaki tüm deyimler hatasız tamamlanırsa işlemi işleyin.

İşlemi oluşturmak, işlemek ve geri almak için kullanılan SQL deyimleri, SQL betikleri yazılırken veya saklı yordamlar oluşturulurken el ile veya ad alanında ADO.NET veya sınıflar System.Transactions kullanılarak program aracılığıyla girilebilir. Bu öğreticide yalnızca ADO.NET kullanarak işlemleri yönetmeyi inceleyeceğiz. Sonraki bir öğreticide Veri Erişim Katmanı'nda saklı yordamların nasıl kullanılacağına bakacağız. Bu aşamada işlemleri oluşturmak, geri almak ve işlemek için SQL deyimlerini inceleyeceğiz.

Not

TransactionScope Ad alanında sınıfı, geliştiricilerin System.Transactions bir işlem kapsamında bir dizi deyimi program aracılığıyla sarmalamalarına olanak tanır ve iki farklı veritabanı ve hatta Microsoft SQL Server veritabanı, Oracle veritabanı ve Web hizmeti gibi heterojen veri depoları gibi birden fazla kaynak içeren karmaşık işlemler için destek içerir. ADO.NET veritabanı işlemleri için daha belirgin olduğundan ve çoğu durumda çok daha az kaynak kullanımına sahip olduğundan bu öğretici için sınıf yerine TransactionScope ADO.NET işlemleri kullanmaya karar verdim. Ayrıca, belirli senaryolarda TransactionScope sınıfı Microsoft Dağıtılmış İşlem Düzenleyicisi'ni (MSDTC) kullanır. MSDTC'yi çevreleyen yapılandırma, uygulama ve performans sorunları, onu oldukça özel ve gelişmiş bir konu haline getirir ve bu öğreticilerin kapsamının dışındadır.

ADO.NET'da SqlClient sağlayıcısıyla çalışırken, işlemler bir nesne döndüren SqlTransaction sınıf sBeginTransaction yöntemine SqlConnectionyapılan bir çağrı aracılığıyla başlatılır. İşlemin yapısını oluşturan veri değişikliği deyimleri bir try...catch blok içine yerleştirilir. Bloktaki bir deyimde try hata oluşursa yürütme, nesnenin Rollback yöntemi aracılığıyla SqlTransaction işlemin geri alınabileceği bloğa aktarırcatch. Tüm deyimler başarıyla tamamlanırsa, bloğunun SqlTransaction sonundaki nesne s Commit yöntemine try yapılan bir çağrı işlemi işler. Aşağıdaki kod parçacığında bu desen gösterilmektedir. Bkz . İşlemlerle Veritabanı Tutarlılığını Koruma.

// Create the SqlTransaction object
SqlTransaction myTransaction = SqlConnectionObject.BeginTransaction();
try
{
    /*
     * ... Perform the database transaction�s data modification statements...
     */
    // If we reach here, no errors, so commit the transaction
    myTransaction.Commit();
}
catch
{
    // If we reach here, there was an error, so rollback the transaction
    myTransaction.Rollback();
    throw;
}

Varsayılan olarak, Türlenmiş DataSet içindeki TableAdapters işlemleri kullanmaz. İşlemler için destek sağlamak için TableAdapter sınıflarını, bir işlem kapsamında bir dizi veri değişikliği deyimi gerçekleştirmek üzere yukarıdaki deseni kullanan ek yöntemleri içerecek şekilde artırmamız gerekir. 2. Adım'da bu yöntemleri eklemek için kısmi sınıfların nasıl kullanılacağını göreceğiz.

1. Adım: Toplu VeriLerle Çalışma Web Sayfaları Oluşturma

DAL'yi veritabanı işlemlerini destekleyecek şekilde nasıl artıracağımızı keşfetmeye başlamadan önce, bu öğretici ve sonraki üç öğretici için ihtiyacımız olacak ASP.NET web sayfalarını oluşturmak için biraz zaman ayıralım. adlı BatchData yeni bir klasör ekleyerek başlayın ve ardından aşağıdaki ASP.NET sayfaları ekleyin ve her sayfayı ana sayfayla ilişkilendirin Site.master .

  • Default.aspx
  • Transactions.aspx
  • BatchUpdate.aspx
  • BatchDelete.aspx
  • BatchInsert.aspx

SqlDataSource ile İlgili Öğreticiler için ASP.NET Sayfaları Ekleme

Şekil 1: SqlDataSource ile İlgili Öğreticiler için ASP.NET Sayfaları Ekleme

Diğer klasörlerde olduğu gibi, Default.aspx bölümünde yer alan SectionLevelTutorialListing.ascx öğreticileri listelemek için Kullanıcı Denetimi'ni kullanacaktır. Bu nedenle, bu Kullanıcı Denetimini Default.aspx Çözüm Gezgini sayfanın Tasarım görünümüne sürükleyerek öğesine ekleyin.

SectionLevelTutorialListing.ascx Kullanıcı Denetimini Default.aspx ekleme

Şekil 2: Kullanıcı Denetimini ekleme SectionLevelTutorialListing.ascx Default.aspx (Tam boyutlu görüntüyü görüntülemek için tıklayın)

Son olarak, bu dört sayfayı dosyaya Web.sitemap girdi olarak ekleyin. Özellikle, Site Haritasını <siteMapNode>Özelleştirme'nin ardından aşağıdaki işaretlemeyi ekleyin:

<siteMapNode title="Working with Batched Data" 
    url="~/BatchData/Default.aspx" 
    description="Learn how to perform batch operations as opposed to 
                 per-row operations.">
    
    <siteMapNode title="Adding Support for Transactions" 
        url="~/BatchData/Transactions.aspx" 
        description="See how to extend the Data Access Layer to support 
                     database transactions." />
    <siteMapNode title="Batch Updating" 
        url="~/BatchData/BatchUpdate.aspx" 
        description="Build a batch updating interface, where each row in a 
                      GridView is editable." />
    <siteMapNode title="Batch Deleting" 
        url="~/BatchData/BatchDelete.aspx" 
        description="Explore how to create an interface for batch deleting 
                     by adding a CheckBox to each GridView row." />
    <siteMapNode title="Batch Inserting" 
        url="~/BatchData/BatchInsert.aspx" 
        description="Examine the steps needed to create a batch inserting 
                     interface, where multiple records can be created at the 
                     click of a button." />
</siteMapNode>

güncelleştirdikten Web.sitemapsonra, öğreticiler web sitesini bir tarayıcı üzerinden görüntülemek için biraz bekleyin. Soldaki menü artık toplu verilerle çalışma öğreticilerine yönelik öğeleri içerir.

Site Haritası Artık Toplu Verilerle Çalışma Öğreticileri için Girdiler Içeriyor

Şekil 3: Site Haritası Artık Toplu Verilerle Çalışma Öğreticileri için Girdiler Içeriyor

2. Adım: Veri Erişim Katmanını Veritabanı İşlemlerini Destekleyecek Şekilde Güncelleştirme

İlk öğreticide ele aldığımız gibi, Veri Erişim Katmanı Oluşturma, DAL'mizdeki Yazılan DataSet DataTable'lar ve TableAdapters'lardan oluşur. DataTable'lar verileri tutarken TableAdapters veritabanından DataTable'lara veri okuma, veritabanını DataTable'larda yapılan değişikliklerle güncelleştirme gibi işlevler sağlar. TableAdapters'ın verileri güncelleştirmek için Batch Update ve DB-Direct olarak adlandırılan iki desen sağladığını hatırlayın. Batch Update düzeniyle TableAdapter'a DataSet, DataTable veya DataRows koleksiyonu geçirilir. Bu veriler numaralandırılır ve eklenen, değiştirilen veya silinen her satır InsertCommandiçin , UpdateCommandveya DeleteCommand yürütülür. Db-Direct düzeniyle TableAdapter'a bunun yerine tek bir kayıt eklemek, güncelleştirmek veya silmek için gereken sütunların değerleri geçirilir. Db Direct desen yöntemi daha sonra uygun InsertCommand, UpdateCommandveya DeleteCommand deyimini yürütmek için bu geçirilen değerleri kullanır.

Kullanılan güncelleştirme deseni ne olursa olsun TableAdapters otomatik olarak oluşturulan yöntemler işlemleri kullanmaz. Varsayılan olarak TableAdapter tarafından gerçekleştirilen her ekleme, güncelleştirme veya silme işlemi tek bir ayrık işlem olarak değerlendirilir. Örneğin, DB-Direct deseninin BLL'deki bir kod tarafından veritabanına on kayıt eklemek için kullanıldığını düşünün. Bu kod TableAdapter Insert yöntemini on kez çağırır. İlk beş ekleme başarılı olursa ancak altıncısı özel durumla sonuçlanırsa, eklenen ilk beş kayıt veritabanında kalır. Benzer şekilde, Batch Update düzeni DataTable'da eklenen, değiştirilen ve silinen satırlara ekleme, güncelleştirme ve silme işlemleri gerçekleştirmek için kullanılırsa, ilk birkaç değişiklik başarılı olduysa ancak daha sonra bir hatayla karşılaşırsa, tamamlanan önceki değişiklikler veritabanında kalır.

Bazı senaryolarda, bir dizi değişiklikte bölünmezlik sağlamak istiyoruz. Bunu başarmak için, UpdateCommand, ve DeleteCommand s işlemlerini bir işlem şemsiyesi altında yürüten InsertCommandyeni yöntemler ekleyerek TableAdapter'ı el ile genişletmemiz gerekir. Veri Erişim Katmanı Oluşturma bölümünde, Yazılan DataSet içindeki DataTable'ların işlevselliğini genişletmek için kısmi sınıflar kullanmayı inceledik. Bu teknik TableAdapters ile de kullanılabilir.

Typed DataSetNorthwind.xsd, klasörün DAL alt klasöründe bulunurApp_Code. adlı klasörde bir alt klasör DAL oluşturun ve adlı TransactionSupport ProductsTableAdapter.TransactionSupport.cs yeni bir sınıf dosyası ekleyin (bkz. Şekil 4). Bu dosya, bir işlem kullanarak veri değişiklikleri gerçekleştirme yöntemlerini içeren kısmi uygulamasını ProductsTableAdapter barındıracaktır.

TransactionSupport Adlı Bir Klasör ve ProductsTableAdapter.TransactionSupport.cs Adlı Bir Sınıf Dosyası Ekleme

Şekil 4: Adlı Bir Klasör ve Adlı TransactionSupport Bir Sınıf Dosyası Ekleme ProductsTableAdapter.TransactionSupport.cs

Dosyaya ProductsTableAdapter.TransactionSupport.cs aşağıdaki kodu girin:

using System;
using System.Data;
using System.Data.SqlClient;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
namespace NorthwindTableAdapters
{
    public partial class ProductsTableAdapter
    {
        private SqlTransaction _transaction;
        private SqlTransaction Transaction
        {
            get
            {                
                return this._transaction;
            }
            set
            {
                this._transaction = value;
            }
        }
        public void BeginTransaction()
        {
            // Open the connection, if needed
            if (this.Connection.State != ConnectionState.Open)
                this.Connection.Open();
            // Create the transaction and assign it to the Transaction property
            this.Transaction = this.Connection.BeginTransaction();
            // Attach the transaction to the Adapters
            foreach (SqlCommand command in this.CommandCollection)
            {
                command.Transaction = this.Transaction;
            }
            this.Adapter.InsertCommand.Transaction = this.Transaction;
            this.Adapter.UpdateCommand.Transaction = this.Transaction;
            this.Adapter.DeleteCommand.Transaction = this.Transaction;
        }
        public void CommitTransaction()
        {
            // Commit the transaction
            this.Transaction.Commit();
            // Close the connection
            this.Connection.Close();
        }
        public void RollbackTransaction()
        {
            // Rollback the transaction
            this.Transaction.Rollback();
            // Close the connection
            this.Connection.Close();
        }
   }
}

partial Buradaki sınıf bildirimindeki anahtar sözcük, derleyiciye, içinde eklenen üyelerin ad alanında NorthwindTableAdapters sınıfına ProductsTableAdapter ekleneceğini belirtir. using System.Data.SqlClient Dosyanın en üstündeki deyimini not edin. TableAdapter, SqlClient sağlayıcısını kullanacak şekilde yapılandırıldığından, dahili olarak veritabanına komutlarını vermek için bir SqlDataAdapter nesnesi kullanır. Sonuç olarak, işlemi başlatmak ve ardından işlemek veya geri almak için sınıfını kullanmamız SqlTransaction gerekir. Microsoft SQL Server dışında bir veri deposu kullanıyorsanız uygun sağlayıcıyı kullanmanız gerekir.

Bu yöntemler bir işlemi başlatmak, geri almak ve işlemek için gereken yapı taşları sağlar. olarak işaretlenir public, dal'daki başka bir sınıftan ProductsTableAdapterveya mimarideki BLL gibi başka bir katmandan kullanılmasını sağlar. BeginTransaction TableAdapter'ın iç SqlConnection öğesini açar (gerekirse), işlemi başlatır ve özelliğine Transaction atar ve işlemi iç SqlDataAdapter s SqlCommand nesnelerine ekler. CommitTransactionve RollbackTransactionConnection nesneyi kapatmadan önce sırasıyla nesne s Commit ve Rollback yöntemlerini çağırınTransaction.

3. Adım: İşlem Şemsiyesi Altında Verileri Güncelleştirmek ve Silmek için Yöntemler Ekleme

Bu yöntemler tamamlandıktan sonra, bir işlem şemsiyesi altında bir dizi komut gerçekleştiren veya BLL'ye ProductsDataTable yöntemler eklemeye hazırız. Aşağıdaki yöntem, bir işlemi kullanarak bir ProductsDataTable örneği güncelleştirmek için Batch Update desenini kullanır. yöntemini çağırarak BeginTransaction bir işlem başlatır ve ardından veri değişikliği deyimlerini vermek için bir try...catch blok kullanır. Nesnenin Adapter Update yöntemine yapılan çağrı bir özel durumla sonuçlanırsa yürütme, işlemin geri alınacağı ve özel durumun yeniden oluşturulacağı bloğa aktarılır catch . Yönteminin Update , sağlanan ProductsDataTable satırları numaralandırarak ve gerekli InsertCommand, UpdateCommandve DeleteCommand s değerlerini gerçekleştirerek Batch Update desenini uyguladığını hatırlayın. Bu komutlardan herhangi biri hatayla sonuçlanırsa işlem geri alınır ve işlem ömrü boyunca yapılan önceki değişiklikler geri alınır. Update Deyim hatasız tamamlanırsa, işlem tamamen işlenir.

public int UpdateWithTransaction(Northwind.ProductsDataTable dataTable)
{
    this.BeginTransaction();
    try
    {
        // Perform the update on the DataTable
        int returnValue = this.Adapter.Update(dataTable);
        // If we reach here, no errors, so commit the transaction
        this.CommitTransaction();
        return returnValue;
    }
    catch
    {
        // If we reach here, there was an error, so rollback the transaction
        this.RollbackTransaction();
        throw;
    }
}

UpdateWithTransaction yöntemini ProductsTableAdapter içindeki kısmi sınıf aracılığıyla sınıfına ProductsTableAdapter.TransactionSupport.csekleyin. Alternatif olarak, bu yöntem birkaç küçük söz dizimsel değişiklikle İş Mantığı Katmanı ProductsBLL sınıfına eklenebilir. Yani , ve içindeki this.BeginTransaction()bu anahtar sözcüğü ile değiştirilmesi Adapter gerekir (türünde bir özelliğin ProductsBLL ProductsTableAdapteradı olduğunu Adapter hatırlayın). this.CommitTransaction()this.RollbackTransaction()

UpdateWithTransaction yöntemi Batch Update desenini kullanır, ancak aşağıdaki yöntemde gösterildiği gibi bir işlem kapsamında bir dizi DB-Direct çağrısı da kullanılabilir. DeleteProductsWithTransaction yöntemi, silinecek s türünde bir List<T> intgiriş olarak kabul ederProductID. yöntemi işlemi bir çağrısıyla BeginTransaction başlatır ve blokta try her ProductID değer için DB-Direct desen Delete yöntemini çağıran sağlanan listede yinelenir. Çağrısından Delete herhangi biri başarısız olursa denetim, işlemin geri alındığı ve özel durumun yeniden oluştuğu bloğa aktarılır catch . Başarılı olmak için Delete tüm çağrılar yapılırsa işlem işlenir. Bu yöntemi sınıfına ProductsBLL ekleyin.

public void DeleteProductsWithTransaction
    (System.Collections.Generic.List<int> productIDs)
{
    // Start the transaction
    Adapter.BeginTransaction();
    try
    {
        // Delete each product specified in the list
        foreach (int productID in productIDs)
        {
            Adapter.Delete(productID);
        }
        // Commit the transaction
        Adapter.CommitTransaction();
    }
    catch
    {
        // There was an error - rollback the transaction
        Adapter.RollbackTransaction();
        throw;
    }
}

Birden Çok TableAdapter Arasında İşlem Uygulama

Bu öğreticide incelenen işlemle ilgili kod, öğesine karşı birden çok deyimin ProductsTableAdapter atomik işlem olarak ele alınmasına olanak tanır. Peki ya farklı veritabanı tablolarında birden çok değişikliğin atomik olarak gerçekleştirilmesi gerekiyorsa? Örneğin, bir kategoriyi silerken önce geçerli ürünlerini başka bir kategoriye yeniden atamak isteyebiliriz. Ürünleri yeniden atamak ve kategoriyi silmek için bu iki adım atomik işlem olarak yürütülmelidir. Ancak, ProductsTableAdapter yalnızca tabloyu değiştirme Products yöntemlerini ve CategoriesTableAdapter yalnızca tabloyu değiştirme Categories yöntemlerini içerir. Peki bir işlem iki TableAdapter'ı da nasıl kaplayabilir?

Bir seçenek, adlandırılmış DeleteCategoryAndReassignProducts(categoryIDtoDelete, reassignToCategoryID) öğesine CategoriesTableAdapter bir yöntem eklemek ve bu yöntemin hem ürünleri yeniden atadan hem de saklı yordam içinde tanımlanan bir işlem kapsamında kategoriyi silen bir saklı yordam çağırmasını sağlamaktır. Gelecekteki bir öğreticide saklı yordamlarda işlemleri başlatma, işleme ve geri alma işlemlerinin nasıl başlayacağını inceleyeceğiz.

Bir diğer seçenek de DAL'de yöntemini içeren bir yardımcı sınıf oluşturmaktır DeleteCategoryAndReassignProducts(categoryIDtoDelete, reassignToCategoryID) . Bu yöntem ve öğesinin CategoriesTableAdapter bir örneğini oluşturur ve ardından bu iki TableAdapters Connection özelliğini aynı SqlConnection örneğe ProductsTableAdapter ayarlar. Bu noktada, iki TableAdapter'den biri çağrısıyla BeginTransactionişlemi başlatır. Ürünleri yeniden atamak ve kategoriyi silmek için TableAdapters yöntemleri, işlem gerektiği gibi işlenen veya geri alınan bir try...catch blokta çağrılır.

4. Adım: Yöntemi İş Mantığı Katmanına EklemeUpdateWithTransaction

3. Adımda DAL'de öğesine ProductsTableAdapter bir UpdateWithTransaction yöntem ekledik. BLL'ye karşılık gelen bir yöntem eklemeliyiz. Sunu Katmanı, yöntemini çağırmak UpdateWithTransaction için doğrudan DAL'ye çağrıda bulunabilir ancak bu öğreticiler DAL'yi Sunu Katmanı'ndan yalıtan katmanlı bir mimari tanımlamaya çalışır. Bu nedenle, bu yaklaşımı sürdürmek bizi cezbetir.

ProductsBLL Sınıf dosyasını açın ve yalnızca ilgili DAL yöntemine çağıran adlı UpdateWithTransaction bir yöntem ekleyin. Şimdi içinde iki yeni yöntem ProductsBLLolmalıdır: UpdateWithTransactionyeni eklediğiniz ve DeleteProductsWithTransaction3. Adımda eklenen .

public int UpdateWithTransaction(Northwind.ProductsDataTable products)
{
    return Adapter.UpdateWithTransaction(products);
}
public void DeleteProductsWithTransaction
    (System.Collections.Generic.List<int> productIDs)
{
    // Start the transaction
    Adapter.BeginTransaction();
    try
    {
        // Delete each product specified in the list
        foreach (int productID in productIDs)
            Adapter.Delete(productID);
        // Commit the transaction
        Adapter.CommitTransaction();
    }
    catch
    {
        // There was an error - rollback the transaction
        Adapter.RollbackTransaction();
        throw;
    }
}

Not

Bu yöntemler sınıftaki ProductsBLL diğer yöntemlerin DataObjectMethodAttribute çoğuna atanan özniteliği içermez, çünkü bu yöntemleri doğrudan arka planda kod kodlu sınıfların ASP.NET sayfalarından çağıracağız. DataObjectMethodAttribute ObjectDataSource'un Veri Kaynağını Yapılandırma sihirbazında ve hangi sekmenin altında (SELECT, UPDATE, INSERT veya DELETE) hangi yöntemlerin görüneceğini işaretlemek için kullanıldığını hatırlayın. GridView'da toplu düzenleme veya silme için yerleşik destek olmadığından, kod içermeyen bildirim temelli yaklaşımı kullanmak yerine bu yöntemleri program aracılığıyla çağırmamız gerekir.

5. Adım: Sunu Katmanından Veritabanı Verilerini Atomik Olarak Güncelleştirme

Bir grup kaydı güncelleştirirken işlemin etkisini göstermek için, GridView'daki tüm ürünleri listeleyen ve tıklandığında ürün CategoryID değerlerini yeniden atayabilen bir Button Web denetimi içeren bir kullanıcı arabirimi oluşturalım. Özellikle, kategori yeniden ataması ilerlerken, ilk birkaç ürüne geçerli CategoryID bir değer atanırken diğerlerine bilerek var CategoryID olmayan bir değer atanır. Veritabanını mevcut bir kategoriyle CategoryIDeşleşmeyen CategoryID bir ürünle güncelleştirmeye çalışırsak yabancı anahtar kısıtlama ihlali oluşur ve bir özel durum oluşur. Bu örnekte göreceğimiz şey, bir işlem kullanılırken yabancı anahtar kısıtlama ihlalinden kaynaklanan özel durumun önceki geçerli CategoryID değişikliklerin geri alınmasına neden olacağıdır. Ancak, bir işlem kullanmadığınızda, ilk kategorilerde yapılan değişiklikler kalır.

İlk olarak klasördeki sayfayı Transactions.aspx açın ve Araç Kutusu'ndan BatchData Tasarımcı'ya bir GridView sürükleyin. ID Products akıllı etiketinden ve olarak ayarlayın, bunu adlı ProductsDataSourceyeni bir ObjectDataSource'a bağlayın. ObjectDataSource'un verilerini sınıf GetProducts yönteminden ProductsBLL çekecek şekilde yapılandırın. Bu salt okunur bir GridView olacaktır, bu nedenle UPDATE, INSERT ve DELETE sekmelerindeki açılan listeleri (Yok) olarak ayarlayın ve Son'a tıklayın.

Şekil 5: ObjectDataSource'ı ProductsBLL Sınıfının GetProducts Yöntemini Kullanacak Şekilde Yapılandırma

Şekil 5: Şekil 5: ObjectDataSource'un GetProducts Sınıf Yöntemini Kullanacak ProductsBLL Şekilde Yapılandırılması (Tam boyutlu görüntüyü görüntülemek için tıklayın)

UPDATE, INSERT ve DELETE Sekmelerindeki Açılan Listeleri (Yok) olarak ayarlayın

Şekil 6: UPDATE, INSERT ve DELETE Sekmelerindeki Açılan Listeleri (Yok) olarak ayarlayın (Tam boyutlu görüntüyü görüntülemek için tıklayın)

Veri Kaynağını Yapılandırma sihirbazını tamamladıktan sonra Visual Studio, ürün veri alanları için BoundFields ve CheckBoxField oluşturur. , , CategoryIDProductNameve dışındaki ProductIDtüm bu alanları kaldırın ve CategoryName ve CategoryName BoundFields HeaderText özelliklerini sırasıyla Product ve Category olarak yeniden adlandırınProductName. Akıllı etiketten Sayfalandırmayı Etkinleştir seçeneğini işaretleyin. Bu değişiklikleri yaptıktan sonra GridView ve ObjectDataSource bildirim temelli işaretleme aşağıdaki gibi görünmelidir:

<asp:GridView ID="Products" runat="server" AllowPaging="True" 
    AutoGenerateColumns="False" DataKeyNames="ProductID" 
    DataSourceID="ProductsDataSource">
    <Columns>
        <asp:BoundField DataField="ProductID" HeaderText="ProductID" 
            InsertVisible="False" ReadOnly="True" 
            SortExpression="ProductID" />
        <asp:BoundField DataField="ProductName" HeaderText="Product" 
            SortExpression="ProductName" />
        <asp:BoundField DataField="CategoryID" HeaderText="CategoryID" 
            SortExpression="CategoryID" />
        <asp:BoundField DataField="CategoryName" HeaderText="Category" 
            SortExpression="CategoryName" />
    </Columns>
</asp:GridView>
<asp:ObjectDataSource ID="ProductsDataSource" runat="server" 
    OldValuesParameterFormatString="original_{0}"
    SelectMethod="GetProducts" TypeName="ProductsBLL">
</asp:ObjectDataSource>

Ardından, GridView'un üzerine üç Düğme Web denetimi ekleyin. İlk Düğmenin Metin özelliğini Refresh Grid, ikinci sn'leri Kategorileri Değiştir (İLE İşlem) ve üçüncüsü de Kategorileri Değiştir (İŞLEM OLMADAN) olarak ayarlayın.

<p>
    <asp:Button ID="RefreshGrid" runat="server" Text="Refresh Grid" />
</p>
<p>
    <asp:Button ID="ModifyCategoriesWithTransaction" runat="server"
        Text="Modify Categories (WITH TRANSACTION)" />
</p>
<p>
    <asp:Button ID="ModifyCategoriesWithoutTransaction" runat="server"
        Text="Modify Categories (WITHOUT TRANSACTION)" />
</p>

Bu noktada Visual Studio'daki Tasarım görünümü, Şekil 7'de gösterilen ekran görüntüsüne benzer olmalıdır.

Sayfada GridView ve Üç Düğmeli Web Denetimleri Var

Şekil 7: Sayfa GridView ve Üç Düğmeli Web Denetimleri İçerir (Tam boyutlu görüntüyü görüntülemek için tıklayın)

Üç Button Click olayının her biri için olay işleyicileri oluşturun ve aşağıdaki kodu kullanın:

protected void RefreshGrid_Click(object sender, EventArgs e)
{
    Products.DataBind();
}
protected void ModifyCategoriesWithTransaction_Click(object sender, EventArgs e)
{
    // Get the set of products
    ProductsBLL productsAPI = new ProductsBLL();
    Northwind.ProductsDataTable products = productsAPI.GetProducts();
    // Update each product's CategoryID
    foreach (Northwind.ProductsRow product in products)
    {
        product.CategoryID = product.ProductID;
    }
    // Update the data using a transaction
    productsAPI.UpdateWithTransaction(products);
    // Refresh the Grid
    Products.DataBind();
}
protected void ModifyCategoriesWithoutTransaction_Click(object sender, EventArgs e)
{
    // Get the set of products
    ProductsBLL productsAPI = new ProductsBLL();
    Northwind.ProductsDataTable products = productsAPI.GetProducts();
    // Update each product's CategoryID
    foreach (Northwind.ProductsRow product in products)
    {
        product.CategoryID = product.ProductID;
    }
    // Update the data WITHOUT using a transaction
    NorthwindTableAdapters.ProductsTableAdapter productsAdapter = 
        new NorthwindTableAdapters.ProductsTableAdapter();
    productsAdapter.Update(products);
    // Refresh the Grid
    Products.DataBind();
}

Refresh Button olay Click işleyicisi, GridView s yöntemini çağırarak Products verileri GridView'a DataBind yeniden bağlamanız yeterlidir.

İkinci olay işleyicisi ürünleri CategoryID yeniden atar ve veritabanı güncelleştirmelerini bir işlem şemsiyesi altında gerçekleştirmek için BLL'den yeni işlem yöntemini kullanır. Her ürünün CategoryID rastgele olarak kendi ProductIDile aynı değere ayarlandığını unutmayın. Bu, geçerli ürünlerle eşlenecek değerlere sahip ProductID olduğundan, ilk birkaç ürün için CategoryID uygun olacaktır. Ancak s sayısı ProductID çok fazla artmaya başladıktan sonra, s ve CategoryID s'lerin ProductID bu tesadüfi çakışması artık geçerli değildir.

Üçüncü Click olay işleyicisi, ürünleri CategoryID aynı şekilde güncelleştirir, ancak s varsayılan Update yöntemini kullanarak ProductsTableAdapter güncelleştirmeyi veritabanına gönderir. Bu Update yöntem bir işlem içindeki komut serisini sarmalamaz, bu nedenle bu değişiklikler ilk karşılaşılan yabancı anahtar kısıtlama ihlali hatasından önce yapılır.

Bu davranışı göstermek için bu sayfayı bir tarayıcı üzerinden ziyaret edin. Başlangıçta, Şekil 8'de gösterildiği gibi verilerin ilk sayfasını görmeniz gerekir. Ardından Kategorileri Değiştir (İŞLEMLE) düğmesine tıklayın. Bu bir geri göndermeye neden olur ve tüm ürün CategoryID değerlerini güncelleştirmeye çalışır, ancak yabancı anahtar kısıtlama ihlaline neden olur (bkz. Şekil 9).

Ürünler Sayfalanabilir GridView'da Görüntülenir

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

Kategorileri Yeniden Atama, Yabancı Anahtar Kısıtlama İhlaline Neden Olur

Şekil 9: Kategorileri Yeniden Atama Yabancı Anahtar Kısıtlama İhlaline Neden Olur (Tam boyutlu görüntüyü görüntülemek için tıklayın)

Şimdi tarayıcınızın Geri düğmesine basın ve ardından Kılavuzu Yenile düğmesine tıklayın. Verileri yeniledikten sonra Şekil 8'de gösterildiği gibi tam olarak aynı çıkışı görmeniz gerekir. Diğer bir ifadeyle, bazı ürünler CategoryID yasal değerlere değiştirilip veritabanında güncelleştirilmiş olsa da, yabancı anahtar kısıtlama ihlali oluştuğunda geri alınmıştır.

Şimdi Kategorileri Değiştir (İşlem OLMADAN) düğmesine tıklamayı deneyin. Bu, aynı yabancı anahtar kısıtlama ihlali hatasına neden olur (bkz. Şekil 9), ancak bu kez değerleri yasal bir değerle değiştirilen ürünler CategoryID geri alınmaz. Tarayıcınızın Geri düğmesine ve ardından Kılavuzu Yenile düğmesine basın. Şekil 10'da gösterildiği gibi, CategoryID ilk sekiz ürünün sn'leri yeniden atanmıştır. Örneğin, Şekil 8'de Chang'in 1 sayısı vardı CategoryID , ancak Şekil 10'da 2'ye yeniden atandı.

Bazı Ürünler CategoryID Değerleri Güncelleştirilirken Diğerleri Güncelleştirilmedi

Şekil 10: Bazı Ürün CategoryID Değerleri Güncelleştirilirken Diğerleri Güncelleştirilmedi (Tam boyutlu görüntüyü görüntülemek için tıklayın)

Özet

Varsayılan olarak, TableAdapter yöntemleri yürütülen veritabanı deyimlerini bir işlem kapsamında sarmalamaz, ancak biraz çalışmayla bir işlem oluşturacak, işleyecek ve geri alacak yöntemler ekleyebiliriz. Bu öğreticide ProductsTableAdapter sınıfında üç yöntem oluşturduk: BeginTransaction, CommitTransactionve RollbackTransaction. Bir dizi veri değişikliği deyimini atomik hale getirmek için bir blokla try...catch birlikte bu yöntemlerin nasıl kullanılacağını gördük. Özellikle, sağlanan ProductsDataTablebir öğesinin UpdateWithTransaction ProductsTableAdaptersatırlarında gerekli değişiklikleri yapmak için Batch Update desenini kullanan yöntemini oluşturduk. Ayrıca BLL'deki sınıfına ProductsBLL yöntemini ekledikDeleteProductsWithTransaction. Bu yöntem giriş olarak değerlerden ProductID birini List kabul eder ve her ProductIDiçin DB-Direct desen yöntemini Delete çağırır. Her iki yöntem de bir işlem oluşturarak ve ardından veri değişikliği deyimlerini bir try...catch blok içinde yürüterek başlar. Bir özel durum oluşursa, işlem geri alınır, aksi takdirde işlenir.

5. adım, işlem toplu güncelleştirmelerinin ve bir işlemi kullanmayı ihmal eden toplu güncelleştirmelerin etkisini gösterir. Sonraki üç öğreticide, bu öğreticide temeli temel alarak toplu güncelleştirmeler, silmeler ve eklemeler gerçekleştirmek için kullanıcı arabirimleri oluşturacağız.

Mutlu Programlama!

Daha Fazla Bilgi

Bu öğreticide ele alınan konular hakkında daha fazla bilgi için aşağıdaki kaynaklara bakın:

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ışır. Son kitabı Sams Teach Yourself ASP.NET 24 Hours 2.0'dır. Adresine adresinden veya adresinden ulaşabileceğiniz blogu aracılığıyla ulaşabilirsinizmitchell@4GuysFromRolla.com.http://ScottOnWriting.NET

Ö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 Dave Gardner, Hilton Giesenow ve Teresa Murphy'ydi. Yaklaşan MSDN makalelerimi gözden geçirmek istiyor musunuz? Öyleyse, bana adresine mitchell@4GuysFromRolla.combir satır bırakın.