Yanıtlar:
İşte kod pasajı:
using System.Transactions;
....
using (var transactionScope = new TransactionScope())
{
DoYourDapperWork();
transactionScope.Complete();
}
System.TransactionsVarsayılan olarak referansta bulunulmadığından montaja referans eklemeniz gerektiğini unutmayın .
Dispose()yöntemde otomatik olarak yapar . Eğer Complete()çağrılmadıysa, işlem geri alınır alır.
TransctionScopeBu cevabı seçmeniz durumunda bloğun içinde bağlantı açılmalıdır .
İşlemi doğrudan bağlantıdan alarak daha sezgisel bir yaklaşım kullanmayı tercih ettim:
// This called method will get a connection, and open it if it's not yet open.
using (var connection = GetOpenConnection())
using (var transaction = connection.BeginTransaction())
{
connection.Execute(
"INSERT INTO data(Foo, Bar) values (@Foo, @Bar);", listOf5000Items, transaction);
transaction.Commit();
}
.BeginTransaction()
ExecuteGerekli olduğundan, işlemi bir parametre olarak dahil etmek iyi bir noktadır .
TransactionScopeDapper yalnızca ADO.NET komutlarını çalıştırdığı için kullanabilmeniz gerekir .
using (var scope = new TransactionScope())
{
// insert
// insert
scope.Complete();
}
Tüm tablolarınızın tek bir veritabanında olduğu göz önüne alındığında, TransactionScopeburadaki bazı cevaplarda önerilen çözüme katılmıyorum . Bu yanıta bakın .
TransactionScopegenellikle dağıtılmış işlemler için kullanılır; farklı veri tabanlarını kapsayan işlemler farklı sistemlerde olabilir. Bu, işletim sistemi ve SQL Server üzerinde bazı yapılandırmalara ihtiyaç duyar ve bunlar olmadan çalışmaz. Tüm sorgularınız tek bir veritabanı örneğiyle ilgiliyse bu önerilmez.
Ancak, tek bir veritabanıyla, kodu kontrolünüz altında olmayan işleme dahil etmeniz gerektiğinde bu yararlı olabilir. Tek veritabanı ile özel konfigürasyonlara da ihtiyaç duymaz.
connection.BeginTransactiontek bir veritabanına karşı işlem (C #, VB.NET vb.) uygulamak için ADO.NET sözdizimidir. Bu, birden çok veritabanında çalışmaz.
Yani, connection.BeginTransaction()daha iyi bir yol.
İşlemi gerçekleştirmenin daha iyi yolu bile bu cevapta açıklandığı gibi UnitOfWork'ü uygulamaktır .
TransactionScopeOP'nin istediği için verimsiz olanı kullanmayı önerir . Bunun TransactionScopebirçok durumda iyi bir araç olduğuna katılıyorum ; ama bu değil.
Daniel'in cevabı benim için beklendiği gibi çalıştı. Tamlık için, burada bir işlem kapsamı ve zarif kullanarak kaydetme ve geri almayı gösteren bir snippet var:
using System.Transactions;
// _sqlConnection has been opened elsewhere in preceeding code
using (var transactionScope = new TransactionScope())
{
try
{
long result = _sqlConnection.ExecuteScalar<long>(sqlString, new {Param1 = 1, Param2 = "string"});
transactionScope.Complete();
}
catch (Exception exception)
{
// Logger initialized elsewhere in code
_logger.Error(exception, $"Error encountered whilst executing SQL: {sqlString}, Message: {exception.Message}")
// re-throw to let the caller know
throw;
}
} // This is where Dispose is called
Disposeyöntemin birinci veya ikinci olarak adlandırıldığını, sadece iki kez çağrıldığını anlatmaya çalışmadım . "İkinci kez elden çıkarmak istemenin zararlı olmadığı" noktasına gelince, bu büyük bir varsayım. Dokümanların ve gerçek uygulamaların çoğu zaman uyuşmadığını öğrendim. Ancak Microsoft'un sözünü istiyorsanız: msdn.microsoft.com/en-us/library/…