Veritabanı Değişikliklerini Bir İşlemin İçinde Sarmalama (C#)
tarafından Scott Mitchell
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ı INSERT
altında yürütülen , UPDATE
ve 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:
- İşlemin başlangıcını belirtin.
- İşlemi oluşturan SQL deyimlerini yürütür.
- 2. Adım'daki deyimlerden birinde hata varsa işlemi geri alın.
- 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 SqlConnection
yapı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
Ş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.
Ş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.sitemap
sonra, öğ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.
Ş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 InsertCommand
için , UpdateCommand
veya 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
, UpdateCommand
veya 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 InsertCommand
yeni 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.
Ş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 ProductsTableAdapter
veya 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. CommitTransaction
ve RollbackTransaction
iç Connection
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
, UpdateCommand
ve 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.cs
ekleyin. 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
ProductsTableAdapter
adı 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>
int
giriş 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 BeginTransaction
iş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 ProductsBLL
olmalıdır: UpdateWithTransaction
yeni eklediğiniz ve DeleteProductsWithTransaction
3. 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 CategoryID
eş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ı ProductsDataSource
yeni 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: Ş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)
Ş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. , , CategoryID
ProductName
ve dışındaki ProductID
tü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.
Ş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 ProductID
ile 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).
Ş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)
Ş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ı.
Ş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
, CommitTransaction
ve 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 ProductsDataTable
bir öğesinin UpdateWithTransaction
ProductsTableAdapter
satı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 ProductID
iç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:
- İşlemler Kolaylaştırdı:
System.Transactions
- TransactionScope ve DataAdapters
- .NET'te Oracle Veritabanı İşlemlerini Kullanma
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.