İşlemleri Kullanma
İşlemler birkaç veritabanı işlemin atomik bir şekilde işlenmesine izin verir. İşlem yürütüolduysa, tüm işlemler veritabanına başarıyla uygulanır. İşlem geri alınırsa, hiçbir işlem veritabanına uygulanmaz.
İpucu
Bu makalenin örneğini GitHub görüntüleyebilirsiniz.
Varsayılan işlem davranışı
Varsayılan olarak, veritabanı sağlayıcısı işlemleri destekliyorsa, tek bir çağrıdaki tüm değişiklikler SaveChanges bir işlem içinde uygulanır. Değişikliklerden herhangi biri başarısız olursa, işlem geri alınır ve veritabanına hiçbir değişiklik uygulanmaz. Bu, SaveChanges tamamen başarılı veya bir hata oluşursa veritabanını değiştirilmemiş olarak bırakma garantisi veren anlamına gelir.
Çoğu uygulama için bu varsayılan davranış yeterlidir. İşlemleri yalnızca, uygulama gereksinimleriniz gerekli değilse el ile kontrol etmelisiniz.
İşlemleri denetleme
DbContext.Databaseİşlemleri başlatmak, yürütmek ve geri almak için API 'yi kullanabilirsiniz. Aşağıdaki örnekte, SaveChanges tek bir işlemde yürütülen iki işlem ve bır LINQ sorgusu gösterilmektedir:
using var context = new BloggingContext();
using var transaction = context.Database.BeginTransaction();
try
{
context.Blogs.Add(new Blog { Url = "http://blogs.msdn.com/dotnet" });
context.SaveChanges();
context.Blogs.Add(new Blog { Url = "http://blogs.msdn.com/visualstudio" });
context.SaveChanges();
var blogs = context.Blogs
.OrderBy(b => b.Url)
.ToList();
// Commit transaction if all commands succeed, transaction will auto-rollback
// when disposed if either commands fails
transaction.Commit();
}
catch (Exception)
{
// TODO: Handle failure
}
Tüm ilişkisel veritabanı sağlayıcıları işlemleri destekleirken, işlem API 'Leri çağrıldığında diğer sağlayıcı türleri throw veya No-Op olabilir.
İşlemi
Not
Bu özellik EF Core 5,0 ' de tanıtılmıştı.
SaveChangesÇağrıldığında ve bağlam üzerinde devam eden bir işlem varsa EF, verileri kaydetmeden önce otomatik olarak bir SaveChanges oluşturur. Savepoints, bir hata oluşursa veya herhangi bir nedenle daha sonra geri alınacak olan bir veritabanı işlemi içindeki noktalardır. SaveChangesHerhangi bir hatayla karşılaşırsa, işlemi otomatik olarak kayıt noktasına geri kaydeder ve işlemi hiç başlatılmamışsınız gibi aynı durumda bırakır. Bu, sorunları doğru bir şekilde düzeltmenize ve tasarruf etmenizi, özellikle de iyimser eşzamanlılık sorunları ortaya çıktığında yeniden denemeyi sağlar.
Uyarı
savepoints SQL Server birden çok etkin sonuç kümesiyle uyumsuzdur ve kullanılmaz. Sırasında bir hata oluşursa SaveChanges , işlem bilinmeyen bir durumda kalabilir.
Aynı zamanda, işlem ile olduğu gibi Savepoints 'i el ile yönetmek de mümkündür. Aşağıdaki örnek bir işlem içinde bir kayıt noktası oluşturur ve hata durumunda buna geri döner:
using var context = new BloggingContext();
using var transaction = context.Database.BeginTransaction();
try
{
context.Blogs.Add(new Blog { Url = "https://devblogs.microsoft.com/dotnet/" });
context.SaveChanges();
transaction.CreateSavepoint("BeforeMoreBlogs");
context.Blogs.Add(new Blog { Url = "https://devblogs.microsoft.com/visualstudio/" });
context.Blogs.Add(new Blog { Url = "https://devblogs.microsoft.com/aspnet/" });
context.SaveChanges();
transaction.Commit();
}
catch (Exception)
{
// If a failure occurred, we rollback to the savepoint and can continue the transaction
transaction.RollbackToSavepoint("BeforeMoreBlogs");
// TODO: Handle failure, possibly retry inserting blogs
}
Çapraz bağlam işlemi
Ayrıca, bir işlemi birden çok bağlam örneği arasında paylaşabilirsiniz. Bu işlevsellik yalnızca DbTransaction , ilişkisel veritabanlarına özgü olan ve kullanımını gerektirdiğinden ilişkisel bir veritabanı sağlayıcısı kullanılırken kullanılabilir DbConnection .
Bir işlemi paylaşmak için bağlamların hem a hem de DbConnection bir paylaşılması gerekir DbTransaction .
Bağlantının dışarıdan sağlanması için izin ver
' Nin paylaşılması, bir bağlantıyı oluştururken bir DbConnection bağlama geçirebilmesini gerektirir.
DbConnectionDışarıdan sağlanmanın en kolay yolu, DbContext.OnConfiguring bağlamını yapılandırmak ve içeriği dışarıdan oluşturmak DbContextOptions ve bağlam oluşturucusuna geçirmek için yöntemini kullanmayı durdurmaktır.
İpucu
DbContextOptionsBuilder , bağlamını yapılandırmak için ' de kullandığınız API 'dir DbContext.OnConfiguring , şimdi oluşturmak için bunu dışarıdan kullanacaksınız DbContextOptions .
public class BloggingContext : DbContext
{
public BloggingContext(DbContextOptions<BloggingContext> options)
: base(options)
{
}
public DbSet<Blog> Blogs { get; set; }
}
Diğer bir seçenek de kullanmaya devam DbContext.OnConfiguring etmesinin yanı sıra DbConnection içinde kullanılan ve daha sonra kullanılan bir DbContext.OnConfiguring .
public class BloggingContext : DbContext
{
private DbConnection _connection;
public BloggingContext(DbConnection connection)
{
_connection = connection;
}
public DbSet<Blog> Blogs { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(_connection);
}
}
Bağlantıyı ve işlemi paylaşma
Artık aynı bağlantıyı paylaşan birden çok bağlam örneği oluşturabilirsiniz. Daha sonra DbContext.Database.UseTransaction(DbTransaction) aynı işlemde her iki bağlamı da listeleme için API 'yi kullanın.
using var connection = new SqlConnection(connectionString);
var options = new DbContextOptionsBuilder<BloggingContext>()
.UseSqlServer(connection)
.Options;
using var context1 = new BloggingContext(options);
using var transaction = context1.Database.BeginTransaction();
try
{
context1.Blogs.Add(new Blog { Url = "http://blogs.msdn.com/dotnet" });
context1.SaveChanges();
using (var context2 = new BloggingContext(options))
{
context2.Database.UseTransaction(transaction.GetDbTransaction());
var blogs = context2.Blogs
.OrderBy(b => b.Url)
.ToList();
}
// Commit transaction if all commands succeed, transaction will auto-rollback
// when disposed if either commands fails
transaction.Commit();
}
catch (Exception)
{
// TODO: Handle failure
}
Dış DbTransactions kullanma (yalnızca ilişkisel veritabanları)
İlişkisel bir veritabanına erişmek için birden çok veri erişim teknolojisi kullanıyorsanız, bu farklı teknolojiler tarafından gerçekleştirilen işlemler arasında bir işlem paylaşmak isteyebilirsiniz.
aşağıdaki örnek, aynı işlemde bir ADO.NET SqlClient işleminin ve Entity Framework Core işleminin nasıl gerçekleştirileceğini gösterir.
using var connection = new SqlConnection(connectionString);
connection.Open();
using var transaction = connection.BeginTransaction();
try
{
// Run raw ADO.NET command in the transaction
var command = connection.CreateCommand();
command.Transaction = transaction;
command.CommandText = "DELETE FROM dbo.Blogs";
command.ExecuteNonQuery();
// Run an EF Core command in the transaction
var options = new DbContextOptionsBuilder<BloggingContext>()
.UseSqlServer(connection)
.Options;
using (var context = new BloggingContext(options))
{
context.Database.UseTransaction(transaction);
context.Blogs.Add(new Blog { Url = "http://blogs.msdn.com/dotnet" });
context.SaveChanges();
}
// Commit transaction if all commands succeed, transaction will auto-rollback
// when disposed if either commands fails
transaction.Commit();
}
catch (Exception)
{
// TODO: Handle failure
}
System. Transactions kullanma
Daha büyük bir kapsamda koordine etmeniz gerekiyorsa çevresel işlemler kullanmak mümkündür.
using (var scope = new TransactionScope(
TransactionScopeOption.Required,
new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted }))
{
using var connection = new SqlConnection(connectionString);
connection.Open();
try
{
// Run raw ADO.NET command in the transaction
var command = connection.CreateCommand();
command.CommandText = "DELETE FROM dbo.Blogs";
command.ExecuteNonQuery();
// Run an EF Core command in the transaction
var options = new DbContextOptionsBuilder<BloggingContext>()
.UseSqlServer(connection)
.Options;
using (var context = new BloggingContext(options))
{
context.Blogs.Add(new Blog { Url = "http://blogs.msdn.com/dotnet" });
context.SaveChanges();
}
// Commit transaction if all commands succeed, transaction will auto-rollback
// when disposed if either commands fails
scope.Complete();
}
catch (Exception)
{
// TODO: Handle failure
}
}
Ayrıca, açık bir işlemde listeleme de mümkündür.
using (var transaction = new CommittableTransaction(
new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted }))
{
var connection = new SqlConnection(connectionString);
try
{
var options = new DbContextOptionsBuilder<BloggingContext>()
.UseSqlServer(connection)
.Options;
using (var context = new BloggingContext(options))
{
context.Database.OpenConnection();
context.Database.EnlistTransaction(transaction);
// Run raw ADO.NET command in the transaction
var command = connection.CreateCommand();
command.CommandText = "DELETE FROM dbo.Blogs";
command.ExecuteNonQuery();
// Run an EF Core command in the transaction
context.Blogs.Add(new Blog { Url = "http://blogs.msdn.com/dotnet" });
context.SaveChanges();
context.Database.CloseConnection();
}
// Commit transaction if all commands succeed, transaction will auto-rollback
// when disposed if either commands fails
transaction.Commit();
}
catch (Exception)
{
// TODO: Handle failure
}
}
System. Transactions sınırlamaları
EF Core, System. Transactions desteğini uygulamak için veritabanı sağlayıcılarını kullanır. Bir sağlayıcı System. Transactions için destek uygulamaz, bu API 'lere yapılan çağrılar tamamen yok sayılır. SqlClient bunu destekler.
Önemli
İşlemleri yönetmek için kullanmadan önce API 'nin sağlayıcınızı doğru şekilde davrandığını test etmeniz önerilir. Veri tabanı sağlayıcının bakımınonu ile iletişim kurmanız önerilir.
System. Transactions 'ın .NET Core uygulamasında dağıtılmış işlemler için destek yoktur, bu nedenle
TransactionScopeCommittableTransactionbirden çok kaynak yöneticisi arasında işlem koordine edilemez. Destek, Bu soruntarafından izlenir.