Bagikan melalui


Membungkus Modifikasi Database dalam Transaksi (C#)

oleh Scott Mitchell

Unduh PDF

Tutorial ini adalah yang pertama dari empat yang melihat memperbarui, menghapus, dan menyisipkan batch data. Dalam tutorial ini kita mempelajari bagaimana transaksi database memungkinkan modifikasi batch dilakukan sebagai operasi atomik, yang memastikan bahwa semua langkah berhasil atau semua langkah gagal.

Pendahuluan

Seperti yang kita lihat dimulai dengan tutorial Gambaran Umum Menyisipkan, Memperbarui, dan Menghapus Data , GridView menyediakan dukungan bawaan untuk pengeditan dan penghapusan tingkat baris. Dengan beberapa klik mouse dimungkinkan untuk membuat antarmuka modifikasi data yang kaya tanpa menulis baris kode, selama Anda puas dengan pengeditan dan penghapusan berdasarkan per baris. Namun, dalam skenario tertentu ini tidak mencukupi dan kami perlu memberi pengguna kemampuan untuk mengedit atau menghapus batch rekaman.

Misalnya, sebagian besar klien email berbasis web menggunakan kisi untuk mencantumkan setiap pesan di mana setiap baris menyertakan kotak centang bersama dengan informasi email (subjek, pengirim, dan sebagainya). Antarmuka ini mengizinkan pengguna untuk menghapus beberapa pesan dengan memeriksanya lalu mengklik tombol Hapus Pesan yang Dipilih. Antarmuka pengeditan batch sangat ideal dalam situasi di mana pengguna biasanya mengedit banyak rekaman yang berbeda. Daripada memaksa pengguna untuk mengklik Edit, buat perubahan mereka, lalu klik Perbarui untuk setiap rekaman yang perlu dimodifikasi, antarmuka pengeditan batch merender setiap baris dengan antarmuka pengeditannya. Pengguna dapat dengan cepat mengubah kumpulan baris yang perlu diubah lalu menyimpan perubahan ini dengan mengklik tombol Perbarui Semua. Dalam set tutorial ini kita akan memeriksa cara membuat antarmuka untuk menyisipkan, mengedit, dan menghapus batch data.

Saat melakukan operasi batch, penting untuk menentukan apakah mungkin beberapa operasi dalam batch berhasil sementara yang lain gagal. Pertimbangkan antarmuka penghapusan batch - apa yang harus terjadi jika rekaman pertama yang dipilih berhasil dihapus, tetapi yang kedua gagal, katakanlah, karena pelanggaran batasan kunci asing? Haruskah penghapusan rekaman pertama digulung balik atau dapat diterima agar rekaman pertama tetap dihapus?

Jika Anda ingin operasi batch diperlakukan sebagai operasi atomik, salah satu di mana semua langkah berhasil atau semua langkah gagal, maka Lapisan Akses Data perlu ditambah untuk menyertakan dukungan untuk transaksi database. Transaksi database menjamin atomitas untuk serangkaian INSERTpernyataan , , UPDATEdan DELETE yang dijalankan di bawah payung transaksi dan merupakan fitur yang didukung oleh sebagian besar semua sistem database modern.

Dalam tutorial ini kita akan melihat cara memperluas DAL untuk menggunakan transaksi database. Tutorial berikutnya akan memeriksa penerapan halaman web untuk menyisipkan, memperbarui, dan menghapus antarmuka batch. Mari kita mulai!

Catatan

Saat memodifikasi data dalam transaksi batch, atomitas tidak selalu diperlukan. Dalam beberapa skenario, mungkin dapat diterima agar beberapa modifikasi data berhasil dan yang lain dalam batch yang sama gagal, seperti saat menghapus sekumpulan email dari klien email berbasis web. Jika ada kesalahan database di tengah proses penghapusan, mungkin dapat diterima bahwa rekaman tersebut diproses tanpa kesalahan tetap dihapus. Dalam kasus seperti itu, DAL tidak perlu dimodifikasi untuk mendukung transaksi database. Namun, ada skenario operasi batch lainnya, di mana atomitas sangat penting. Ketika pelanggan memindahkan dananya dari satu rekening bank ke rekening bank lain, dua operasi harus dilakukan: dana harus dikurangi dari rekening pertama dan kemudian ditambahkan ke yang kedua. Meskipun bank mungkin tidak keberatan memiliki langkah pertama berhasil tetapi langkah kedua gagal, pelanggannya akan marah. Saya mendorong Anda untuk bekerja melalui tutorial ini dan menerapkan peningkatan ke DAL untuk mendukung transaksi database bahkan jika Anda tidak berencana menggunakannya dalam batch menyisipkan, memperbarui, dan menghapus antarmuka yang akan kita bangun dalam tiga tutorial berikut.

Gambaran Umum Transaksi

Sebagian besar database menyertakan dukungan untuk transaksi, yang memungkinkan beberapa perintah database dikelompokkan ke dalam satu unit kerja logis. Perintah database yang terdiri dari transaksi dijamin atomik, yang berarti bahwa semua perintah akan gagal atau semua akan berhasil.

Secara umum, transaksi diimplementasikan melalui pernyataan SQL menggunakan pola berikut:

  1. Menunjukkan awal transaksi.
  2. Jalankan pernyataan SQL yang terdiri dari transaksi.
  3. Jika ada kesalahan dalam salah satu pernyataan dari Langkah 2, gulung balik transaksi.
  4. Jika semua pernyataan dari Langkah 2 selesai tanpa kesalahan, lakukan transaksi.

Pernyataan SQL yang digunakan untuk membuat, menerapkan, dan mengembalikan transaksi dapat dimasukkan secara manual saat menulis skrip SQL atau membuat prosedur tersimpan, atau melalui cara terprogram menggunakan ADO.NET atau kelas di System.Transactions namespace. Dalam tutorial ini kami hanya akan memeriksa pengelolaan transaksi menggunakan ADO.NET. Dalam tutorial di masa mendatang kita akan melihat cara menggunakan prosedur tersimpan di Lapisan Akses Data, pada saat itu kita akan menjelajahi pernyataan SQL untuk membuat, menggulung balik, dan melakukan transaksi.

Catatan

Kelas TransactionScope di System.Transactions namespace memungkinkan pengembang untuk secara terprogram membungkus serangkaian pernyataan dalam cakupan transaksi dan menyertakan dukungan untuk transaksi kompleks yang melibatkan beberapa sumber, seperti dua database yang berbeda atau bahkan jenis penyimpanan data heterogen, seperti database Microsoft SQL Server, database Oracle, dan layanan Web. Saya telah memutuskan untuk menggunakan transaksi ADO.NET untuk tutorial ini alih-alih TransactionScope kelas karena ADO.NET lebih spesifik untuk transaksi database dan, dalam banyak kasus, jauh lebih sedikit sumber daya intensif. Selain itu, dalam skenario TransactionScope tertentu kelas menggunakan Koordinator Transaksi Terdistribusi Microsoft (MSDTC). Masalah konfigurasi, implementasi, dan performa yang mengelilingi MSDTC menjadikannya topik yang agak khusus dan canggih dan di luar cakupan tutorial ini.

Saat bekerja dengan penyedia SqlClient di ADO.NET, transaksi dimulai melalui panggilan ke SqlConnection, yang mengembalikan BeginTransaction objek. Pernyataan modifikasi data yang membuat transaksi ditempatkan dalam blok try...catch . Jika kesalahan terjadi dalam pernyataan di try blok, eksekusi akan ditransfer ke catch blok tempat transaksi dapat digulung balik melalui SqlTransaction metodeRollback. Jika semua pernyataan berhasil diselesaikan, panggilan ke SqlTransaction metodeCommit di akhir try blok melakukan transaksi. Cuplikan kode berikut menggambarkan pola ini. Lihat Mempertahankan Konsistensi Database dengan Transaksi.

// 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;
}

Secara default, TableAdapters dalam Himpunan Data Yang Dititik tidak menggunakan transaksi. Untuk memberikan dukungan untuk transaksi, kita perlu menambah kelas TableAdapter untuk menyertakan metode tambahan yang menggunakan pola di atas untuk melakukan serangkaian pernyataan modifikasi data dalam cakupan transaksi. Di Langkah 2 kita akan melihat cara menggunakan kelas parsial untuk menambahkan metode ini.

Langkah 1: Membuat Halaman Web Bekerja dengan Data Batch

Sebelum kita mulai menjelajahi cara menambah DAL untuk mendukung transaksi database, mari kita luangkan waktu sejenak terlebih dahulu untuk membuat halaman web ASP.NET yang akan kita butuhkan untuk tutorial ini dan ketiganya setelahnya. Mulailah dengan menambahkan folder baru bernama BatchData lalu tambahkan halaman ASP.NET berikut, mengaitkan setiap halaman dengan Site.master halaman master.

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

Menambahkan Halaman ASP.NET untuk Tutorial Terkait SqlDataSource

Gambar 1: Tambahkan Halaman ASP.NET untuk Tutorial Terkait SqlDataSource

Seperti halnya folder lain, Default.aspx akan menggunakan SectionLevelTutorialListing.ascx Kontrol Pengguna untuk mencantumkan tutorial di dalam bagiannya. Oleh karena itu, tambahkan Kontrol Pengguna ini ke Default.aspx dengan menyeretnya dari Penjelajah Solusi ke tampilan Desain halaman.

Tambahkan Kontrol Pengguna SectionLevelTutorialListing.ascx ke Default.aspx

Gambar 2: Tambahkan SectionLevelTutorialListing.ascx Kontrol Pengguna ke Default.aspx (Klik untuk melihat gambar ukuran penuh)

Terakhir, tambahkan keempat halaman ini sebagai entri ke Web.sitemap file. Secara khusus, tambahkan markup berikut setelah Kustomisasi Peta <siteMapNode>Situs :

<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>

Setelah memperbarui Web.sitemap, luangkan waktu sejenak untuk melihat situs web tutorial melalui browser. Menu di sebelah kiri sekarang menyertakan item untuk bekerja dengan tutorial data batch.

Peta Situs Sekarang Menyertakan Entri untuk Tutorial Bekerja dengan Data Batch

Gambar 3: Peta Situs Sekarang Menyertakan Entri untuk Tutorial Bekerja dengan Data Batch

Langkah 2: Memperbarui Lapisan Akses Data untuk Mendukung Transaksi Database

Seperti yang kita bahas kembali di tutorial pertama, Membuat Lapisan Akses Data, Himpunan Data Yang Dieksa di DAL kami terdiri dari DataTables dan TableAdapters. DataTable menyimpan data saat TableAdapters menyediakan fungsionalitas untuk membaca data dari database ke dalam DataTables, untuk memperbarui database dengan perubahan yang dibuat pada DataTables, dan sebagainya. Ingat bahwa TableAdapters menyediakan dua pola untuk memperbarui data, yang saya sebut sebagai Batch Update dan DB-Direct. Dengan pola Pembaruan Batch, TableAdapter melewati Himpunan Data, DataTable, atau kumpulan DataRows. Data ini dijumlahkan dan untuk setiap baris yang disisipkan, dimodifikasi, atau dihapus, InsertCommand, UpdateCommand, atau DeleteCommand dijalankan. Dengan pola DB-Direct, TableAdapter malah meneruskan nilai kolom yang diperlukan untuk menyisipkan, memperbarui, atau menghapus satu rekaman. Metode pola DB Direct kemudian menggunakan nilai yang diteruskan untuk menjalankan pernyataan , , InsertCommandatau UpdateCommand yang sesuaiDeleteCommand.

Terlepas dari pola pembaruan yang digunakan, metode yang dihasilkan secara otomatis TableAdapters tidak menggunakan transaksi. Secara default setiap sisipan, pembaruan, atau penghapusan yang dilakukan oleh TableAdapter diperlakukan sebagai operasi diskrit tunggal. Misalnya, bayangkan pola DB-Direct digunakan oleh beberapa kode di BLL untuk menyisipkan sepuluh rekaman ke dalam database. Kode ini akan memanggil metode TableAdapter s Insert sepuluh kali. Jika lima sisipan pertama berhasil, tetapi yang keenam menghasilkan pengecualian, lima rekaman pertama yang disisipkan akan tetap berada dalam database. Demikian pula, jika pola Pembaruan Batch digunakan untuk melakukan penyisipan, pembaruan, dan penghapusan ke baris yang disisipkan, dimodifikasi, dan dihapus dalam DataTable, jika beberapa modifikasi pertama berhasil tetapi yang kemudian mengalami kesalahan, modifikasi sebelumnya yang selesai akan tetap ada di database.

Dalam skenario tertentu, kami ingin memastikan atomitas di serangkaian modifikasi. Untuk mencapai hal ini, kita harus memperluas TableAdapter secara manual dengan menambahkan metode baru yang menjalankan InsertCommand, , UpdateCommanddan DeleteCommand di bawah payung transaksi. Dalam Membuat Lapisan Akses Data, kami melihat menggunakan kelas parsial untuk memperluas fungsionalitas DataTables dalam Himpunan Data Yang Dititik. Teknik ini juga dapat digunakan dengan TableAdapters.

Himpunan Data Northwind.xsd Bertitik terletak di App_Code subfolder folder DAL . Buat subfolder di DAL folder bernama TransactionSupport dan tambahkan file kelas baru bernama ProductsTableAdapter.TransactionSupport.cs (lihat Gambar 4). File ini akan menyimpan implementasi parsial dari ProductsTableAdapter yang mencakup metode untuk melakukan modifikasi data menggunakan transaksi.

Menambahkan Folder Bernama TransactionSupport dan File Kelas Bernama ProductsTableAdapter.TransactionSupport.cs

Gambar 4: Tambahkan Folder Bernama TransactionSupport dan File Kelas Bernama ProductsTableAdapter.TransactionSupport.cs

Masukkan kode berikut ke ProductsTableAdapter.TransactionSupport.cs dalam file:

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();
        }
   }
}

Kata partial kunci dalam deklarasi kelas di sini menunjukkan kepada pengkompilasi bahwa anggota yang ditambahkan di dalamnya akan ditambahkan ke ProductsTableAdapter kelas di NorthwindTableAdapters namespace layanan. using System.Data.SqlClient Perhatikan pernyataan di bagian atas file. Karena TableAdapter dikonfigurasi untuk menggunakan penyedia SqlClient, secara internal menggunakan SqlDataAdapter objek untuk mengeluarkan perintahnya ke database. Akibatnya, kita perlu menggunakan SqlTransaction kelas untuk memulai transaksi dan kemudian menerapkannya atau menggulungnya kembali. Jika Anda menggunakan penyimpanan data selain Microsoft SQL Server, Anda harus menggunakan penyedia yang sesuai.

Metode ini menyediakan blok penyusun yang diperlukan untuk memulai, memutar kembali, dan melakukan transaksi. Mereka ditandai public, memungkinkan mereka untuk digunakan dari dalam ProductsTableAdapter, dari kelas lain di DAL, atau dari lapisan lain dalam arsitektur, seperti BLL. BeginTransaction membuka internal SqlConnection TableAdapter (jika diperlukan), memulai transaksi dan menetapkannya ke Transaction properti, dan melampirkan transaksi ke objek internal SqlDataAdapterSqlCommand . CommitTransaction dan RollbackTransaction panggil Transaction objek s Commit dan Rollback metode, masing-masing, sebelum menutup objek internal Connection .

Langkah 3: Menambahkan Metode untuk Memperbarui dan Menghapus Data Di Bawah Payung Transaksi

Dengan metode ini selesai, kami siap untuk menambahkan metode ke ProductsDataTable atau BLL yang melakukan serangkaian perintah di bawah payung transaksi. Metode berikut menggunakan pola Pembaruan Batch untuk memperbarui ProductsDataTable instans menggunakan transaksi. Ini memulai transaksi dengan memanggil BeginTransaction metode dan kemudian menggunakan try...catch blok untuk mengeluarkan pernyataan modifikasi data. Jika panggilan ke Adapter metode objek s Update menghasilkan pengecualian, eksekusi akan ditransfer ke catch blok tempat transaksi akan digulung balik dan pengecualian dilemparkan kembali. Ingat bahwa metode mengimplementasikan Update pola Batch Update dengan menghitung baris yang disediakan ProductsDataTable dan melakukan yang diperlukan InsertCommand, UpdateCommand, dan DeleteCommand s. Jika salah satu perintah ini menghasilkan kesalahan, transaksi digulung balik, membatalkan modifikasi sebelumnya yang dilakukan selama masa pakai transaksi. Update Jika pernyataan selesai tanpa kesalahan, transaksi dilakukan secara keseluruhan.

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 Tambahkan metode ke ProductsTableAdapter kelas melalui kelas parsial di ProductsTableAdapter.TransactionSupport.cs. Atau, metode ini dapat ditambahkan ke kelas Lapisan ProductsBLL Logika Bisnis dengan beberapa perubahan sindikasi kecil. Yaitu, kata kunci ini dalam this.BeginTransaction(), , dan this.CommitTransaction() perlu diganti dengan this.RollbackTransaction() (ingat bahwa Adapter adalah nama properti dalam Adapter jenis ProductsBLLProductsTableAdapter).

Metode ini UpdateWithTransaction menggunakan pola Pembaruan Batch, tetapi serangkaian panggilan DB-Direct juga dapat digunakan dalam cakupan transaksi, seperti yang ditunjukkan metode berikut. Metode DeleteProductsWithTransaction ini menerima sebagai input List<T> jenis int, yang merupakan metode yang ProductID akan dihapus. Metode ini memulai transaksi melalui panggilan ke BeginTransaction dan kemudian, di try blok, melakukan iterasi melalui daftar yang disediakan yang memanggil metode pola Delete DB-Direct untuk setiap ProductID nilai. Jika salah satu panggilan gagal Delete , kontrol ditransfer ke catch blok tempat transaksi digulung balik dan pengecualian dilemparkan kembali. Jika semua panggilan berhasil Delete , maka transaksi dilakukan. Tambahkan metode ini ke ProductsBLL kelas .

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;
    }
}

Menerapkan Transaksi di Beberapa TableAdapters

Kode terkait transaksi yang diperiksa dalam tutorial ini memungkinkan beberapa pernyataan terhadap ProductsTableAdapter diperlakukan sebagai operasi atomik. Tetapi bagaimana jika beberapa modifikasi pada tabel database yang berbeda perlu dilakukan secara atomik? Misalnya, saat menghapus kategori, kami mungkin pertama-tama ingin menetapkan ulang produknya saat ini ke beberapa kategori lain. Kedua langkah ini menetapkan ulang produk dan menghapus kategori harus dijalankan sebagai operasi atomik. ProductsTableAdapter Tetapi hanya mencakup metode untuk memodifikasi Products tabel dan CategoriesTableAdapter hanya menyertakan metode untuk memodifikasi Categories tabel. Jadi bagaimana transaksi dapat mencakup kedua TableAdapters?

Salah satu opsinya adalah menambahkan metode ke CategoriesTableAdapter metode bernama DeleteCategoryAndReassignProducts(categoryIDtoDelete, reassignToCategoryID) dan meminta metode tersebut memanggil prosedur tersimpan yang keduanya menetapkan ulang produk dan menghapus kategori dalam cakupan transaksi yang ditentukan dalam prosedur tersimpan. Kita akan melihat cara memulai, menerapkan, dan memutar kembali transaksi dalam prosedur tersimpan dalam tutorial mendatang.

Opsi lain adalah membuat kelas pembantu di DAL yang berisi DeleteCategoryAndReassignProducts(categoryIDtoDelete, reassignToCategoryID) metode . Metode ini akan membuat instans CategoriesTableAdapter dan ProductsTableAdapter lalu mengatur dua properti TableAdapters Connection ini ke instans yang sama SqlConnection . Pada saat itu, salah satu dari dua TableAdapters akan memulai transaksi dengan panggilan ke BeginTransaction. Metode TableAdapters untuk menetapkan ulang produk dan menghapus kategori akan dipanggil dalam try...catch blok dengan transaksi yang dilakukan atau digulung balik sesuai kebutuhan.

Langkah 4: MenambahkanUpdateWithTransactionMetode ke Lapisan Logika Bisnis

Di Langkah 3 kami menambahkan UpdateWithTransaction metode ke ProductsTableAdapter dalam DAL. Kita harus menambahkan metode yang sesuai ke BLL. Meskipun Lapisan Presentasi dapat memanggil langsung ke DAL untuk memanggil UpdateWithTransaction metode , tutorial ini telah berusaha untuk menentukan arsitektur berlapis yang mengisolasi DAL dari Lapisan Presentasi. Oleh karena itu, kami harus melanjutkan pendekatan ini.

ProductsBLL Buka file kelas dan tambahkan metode bernama UpdateWithTransaction yang hanya memanggil ke metode DAL yang sesuai. Sekarang harus ada dua metode baru di ProductsBLL: UpdateWithTransaction, yang baru saja Anda tambahkan, dan DeleteProductsWithTransaction, yang ditambahkan di Langkah 3.

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;
    }
}

Catatan

Metode ini tidak menyertakan atribut yang DataObjectMethodAttribute ditetapkan ke sebagian besar metode lain di ProductsBLL kelas karena kami akan memanggil metode ini langsung dari kelas kode halaman ASP.NET di belakang. Ingat yang DataObjectMethodAttribute digunakan untuk menandai metode apa yang akan muncul di wizard Konfigurasi Sumber Data ObjectDataSource dan di bawah tab apa (SELECT, UPDATE, INSERT, atau DELETE). Karena GridView tidak memiliki dukungan bawaan untuk pengeditan atau penghapusan batch, kita harus memanggil metode ini secara terprogram daripada menggunakan pendekatan deklaratif bebas kode.

Langkah 5: Memperbarui Data Database secara Atomik dari Lapisan Presentasi

Untuk mengilustrasikan efek yang dimiliki transaksi saat memperbarui batch rekaman, mari kita buat antarmuka pengguna yang mencantumkan semua produk dalam GridView dan menyertakan kontrol Web Tombol yang, saat diklik, menetapkan ulang nilai produk CategoryID . Secara khusus, penetapan ulang kategori akan berlangsung sehingga beberapa produk pertama diberi nilai yang valid CategoryID sementara yang lain dengan sengaja diberi nilai yang tidak ada CategoryID . Jika kita mencoba memperbarui database dengan produk yang CategoryID tidak cocok dengan kategori CategoryIDyang ada, pelanggaran batasan kunci asing akan terjadi dan pengecualian akan dinaikkan. Apa yang akan kita lihat dalam contoh ini adalah bahwa saat menggunakan transaksi, pengecualian yang dimunculkan dari pelanggaran batasan kunci asing akan menyebabkan perubahan valid CategoryID sebelumnya digulung balik. Namun, ketika tidak menggunakan transaksi, modifikasi pada kategori awal akan tetap ada.

Mulailah dengan membuka Transactions.aspx halaman di BatchData folder dan seret GridView dari Kotak Alat ke Perancang. ID Atur ke Products dan, dari tag pintarnya, ikat ke ObjectDataSource baru bernama ProductsDataSource. Konfigurasikan ObjectDataSource untuk menarik datanya dari ProductsBLL metode kelas.GetProducts Ini akan menjadi GridView baca-saja, jadi atur daftar drop-down di tab PERBARUI, SISIPKAN, dan HAPUS ke (Tidak Ada) dan klik Selesai.

Gambar 5: Konfigurasikan ObjectDataSource untuk Menggunakan Metode GetProducts Kelas ProductsBLL

Gambar 5: Gambar 5: Konfigurasikan ObjectDataSource untuk Menggunakan ProductsBLL Metode Kelas (GetProductsKlik untuk melihat gambar ukuran penuh)

Atur Daftar Drop-Down di Tab PERBARUI, SISIPKAN, dan HAPUS ke (Tidak Ada)

Gambar 6: Atur Daftar Drop-Down di Tab PERBARUI, SISIPKAN, dan HAPUS ke (Tidak Ada) (Klik untuk melihat gambar ukuran penuh)

Setelah menyelesaikan wizard Konfigurasi Sumber Data, Visual Studio akan membuat BoundFields dan CheckBoxField untuk bidang data produk. Hapus semua bidang ini kecuali untuk ProductID, , ProductNameCategoryID, dan dan CategoryName ganti nama ProductName properti dan CategoryName BoundFields HeaderText menjadi Produk dan Kategori, masing-masing. Dari tag pintar, centang opsi Aktifkan Halaman. Setelah melakukan modifikasi ini, markup deklaratif GridView dan ObjectDataSource akan terlihat seperti berikut ini:

<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>

Selanjutnya, tambahkan tiga kontrol Web Tombol di atas GridView. Atur properti Teks Tombol pertama ke Refresh Grid, yang kedua ke Ubah Kategori (WITH TRANSACTION), dan yang ketiga ke Modifikasi Kategori (TANPA TRANSAKSI) .

<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>

Pada titik ini tampilan Desain di Visual Studio akan terlihat mirip dengan cuplikan layar yang ditampilkan di Gambar 7.

Halaman Berisi Kontrol Web GridView dan Tiga Tombol

Gambar 7: Halaman Berisi Tampilan Kisi dan Kontrol Web Tiga Tombol (Klik untuk melihat gambar ukuran penuh)

Buat penanganan aktivitas untuk masing-masing dari tiga peristiwa Tombol dan Click gunakan kode berikut:

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();
}

Handler peristiwa Tombol Click refresh hanya mengikat ulang data ke GridView dengan memanggil Products metode GridView DataBind .

Penanganan aktivitas kedua menetapkan ulang produk CategoryID dan menggunakan metode transaksi baru dari BLL untuk melakukan pembaruan database di bawah payung transaksi. Perhatikan bahwa setiap produk CategoryID secara segan-segan diatur ke nilai yang sama dengan ProductID. Ini akan berfungsi dengan baik untuk beberapa produk pertama, karena produk tersebut memiliki ProductID nilai yang terjadi untuk memetakan ke yang valid CategoryID . Tetapi setelah ProductID mulai terlalu besar, tumpang tindih ProductID kebetulan ini dan CategoryID tidak lagi berlaku.

Penanganan aktivitas ketiga Click memperbarui produk CategoryID dengan cara yang sama, tetapi mengirim pembaruan ke database menggunakan ProductsTableAdapter metode default Update s. Metode ini Update tidak membungkus rangkaian perintah dalam transaksi, sehingga perubahan tersebut dilakukan sebelum kesalahan pelanggaran batasan kunci asing pertama yang ditemui akan bertahan.

Untuk menunjukkan perilaku ini, kunjungi halaman ini melalui browser. Awalnya Anda akan melihat halaman pertama data seperti yang ditunjukkan pada Gambar 8. Selanjutnya, klik tombol Ubah Kategori (DENGAN TRANSAKSI). Ini akan menyebabkan postback dan mencoba memperbarui semua nilai produk CategoryID , tetapi akan mengakibatkan pelanggaran batasan kunci asing (lihat Gambar 9).

Produk Ditampilkan dalam Tampilan Kisi yang Dapat Di-Pageable

Gambar 8: Produk Ditampilkan dalam Tampilan Kisi yang Dapat Di-Pageable (Klik untuk melihat gambar ukuran penuh)

Menetapkan Ulang Kategori Menghasilkan Pelanggaran Batasan Kunci Asing

Gambar 9: Menetapkan Ulang Kategori Menghasilkan Pelanggaran Batasan Kunci Asing (Klik untuk melihat gambar ukuran penuh)

Sekarang tekan tombol Kembali browser Anda lalu klik tombol Refresh Grid. Setelah me-refresh data, Anda akan melihat output yang sama persis seperti yang ditunjukkan pada Gambar 8. Artinya, meskipun beberapa produk CategoryID diubah menjadi nilai hukum dan diperbarui dalam database, produk tersebut digulirkan kembali ketika pelanggaran batasan kunci asing terjadi.

Sekarang coba klik tombol Ubah Kategori (TANPA TRANSAKSI). Ini akan mengakibatkan kesalahan pelanggaran batasan kunci asing yang sama (lihat Gambar 9), tetapi kali ini produk yang nilainya CategoryID diubah menjadi nilai hukum tidak akan digulung balik. Tekan tombol Kembali browser Anda lalu tombol Refresh Grid. Seperti yang ditunjukkan Gambar 10, CategoryID dari delapan produk pertama telah ditetapkan kembali. Misalnya, di Gambar 8, Chang memiliki CategoryID 1, tetapi pada Gambar 10 telah ditetapkan kembali menjadi 2.

Beberapa Nilai CategoryID Produk Diperbarui Sementara Yang Lain Tidak

Gambar 10: Beberapa Nilai Produk CategoryID Diperbarui Sementara Yang Lain Tidak (Klik untuk melihat gambar ukuran penuh)

Ringkasan

Secara default, metode TableAdapter s tidak membungkus pernyataan database yang dijalankan dalam cakupan transaksi, tetapi dengan sedikit pekerjaan kita dapat menambahkan metode yang akan membuat, menerapkan, dan memutar kembali transaksi. Dalam tutorial ini kita membuat tiga metode seperti itu ProductsTableAdapter di kelas : BeginTransaction, CommitTransaction, dan RollbackTransaction. Kami melihat cara menggunakan metode ini bersama dengan try...catch blok untuk membuat serangkaian pernyataan modifikasi data atomik. Secara khusus, kami membuat UpdateWithTransaction metode dalam ProductsTableAdapter, yang menggunakan pola Batch Update untuk melakukan modifikasi yang diperlukan pada baris yang disediakan ProductsDataTable. Kami juga menambahkan DeleteProductsWithTransaction metode ke ProductsBLL kelas di BLL, yang menerima List nilai ProductID sebagai inputnya dan memanggil metode Delete pola DB-Direct untuk setiap ProductID. Kedua metode dimulai dengan membuat transaksi dan kemudian menjalankan pernyataan modifikasi data dalam blok try...catch . Jika terjadi pengecualian, transaksi digulung balik, jika tidak, maka akan dilakukan.

Langkah 5 menggambarkan efek pembaruan batch transaksional versus pembaruan batch yang diabaikan untuk menggunakan transaksi. Dalam tiga tutorial berikutnya kita akan membangun pada fondasi yang diletakkan dalam tutorial ini dan membuat antarmuka pengguna untuk melakukan pembaruan batch, penghapusan, dan sisipan.

Selamat Pemrograman!

Bacaan lebih lanjut

Untuk informasi selengkapnya tentang topik yang dibahas dalam tutorial ini, lihat sumber daya berikut:

Tentang Penulis

Scott Mitchell, penulis tujuh buku ASP/ASP.NET dan pendiri 4GuysFromRolla.com, telah bekerja sama dengan teknologi Microsoft Web sejak 1998. Scott bekerja sebagai konsultan, pelatih, dan penulis independen. Buku terbarunya adalah Sams Teach Yourself ASP.NET 2.0 dalam 24 Jam. Dia dapat dijangkau di mitchell@4GuysFromRolla.com.

Terima kasih khusus untuk

Seri tutorial ini ditinjau oleh banyak peninjau yang bermanfaat. Peninjau utama untuk tutorial ini adalah Dave Gardner, Hilton Giesenow, dan Teresa Murphy. Tertarik untuk meninjau artikel MSDN saya yang akan datang? Jika demikian, hubungi saya di mitchell@4GuysFromRolla.com.