Bağlantı Dayanıklılığı
Bağlantı dayanıklılığı başarısız veritabanı komutlarını otomatik olarak yeniden dener. Özelliği, hataların algılanması ve yeniden denenmesinin gerekli mantığını kapsülleyen bir "yürütme stratejisi" sağlayarak herhangi bir veritabanı ile birlikte kullanılabilir. EF Core sağlayıcılar, belirli veritabanı hata koşulları ve en iyi yeniden deneme ilkelerine uyarlanmış yürütme stratejileri sağlayabilir.
örnek olarak, SQL Server sağlayıcısı, SQL Server (SQL Azure dahil) özel olarak uyarlanmış bir yürütme stratejisi içerir. Yeniden denenebilecek ve en fazla yeniden deneme sayısı, yeniden denemeler arasındaki gecikme (vb.) için izin verilen özel durum türlerinden haberdar değildir.
İçeriğiniz için seçenekler yapılandırılırken bir yürütme stratejisi belirtildi. Bu, genellikle OnConfiguring türetilmiş bağlamınızın yönteminde bulunur:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder
.UseSqlServer(
@"Server=(localdb)\mssqllocaldb;Database=EFMiscellanous.ConnectionResiliency;Trusted_Connection=True",
options => options.EnableRetryOnFailure());
}
Startup.csASP.NET Core bir uygulama için:
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<PicnicContext>(
options => options.UseSqlServer(
"<connection string>",
providerOptions => providerOptions.EnableRetryOnFailure()));
}
Not
Hatada yeniden denenmesinin etkinleştirilmesi, EF 'in, büyük sonuç kümeleri döndüren sorgulara yönelik bellek gereksinimlerini önemli ölçüde artırabileceği, sonuç kümesini dahili olarak arabelleğe almasına neden olur Daha fazla ayrıntı için bkz. arabelleğe alma ve akış .
Özel yürütme stratejisi
Varsayılandan herhangi birini değiştirmek istiyorsanız, kendi özel bir yürütme stratejisini kaydetme mekanizması vardır.
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder
.UseMyProvider(
"<connection string>",
options => options.ExecutionStrategy(...));
}
Yürütme stratejileri ve işlemler
Hatalarda otomatik olarak yeniden deneme yapan bir yürütme stratejisi, başarısız olan bir yeniden deneme bloğunda her işlemi kayıttan yürütmeyi gerektirir. Yeniden denemeler etkinleştirildiğinde, EF Core aracılığıyla gerçekleştirdiğiniz her işlem kendi yeniden kullanılabilir işlem haline gelir. Diğer bir deyişle, her sorgu ve her bir çağrı, SaveChanges() geçici bir hata oluşursa birim olarak yeniden denenir.
Ancak, kodunuz bir işlem başlatıyorsa, BeginTransaction() bir birim olarak değerlendirilmesi gereken kendi işlem grubunuzu tanımlamanız, işlem içindeki her şeyin geri yürütülmesi bir hata oluşmasına neden olacaktır. Bir yürütme stratejisi kullanırken bunu yapmayı denerseniz, aşağıdaki gibi bir özel durum alırsınız:
InvalidOperationException: yapılandırılan ' Sqlserverretryingexecutionstrateji ' yürütme stratejisi Kullanıcı tarafından başlatılan işlemleri desteklemiyor. İşlemdeki tüm işlemleri yeniden kullanılabilir bir birim olarak yürütmek için ' DbContext. Database. Createexecutionstrateji () ' tarafından döndürülen yürütme stratejisini kullanın.
Çözüm, yürütülmesi gereken her şeyi temsil eden bir temsilciyle yürütme stratejisini el ile çağırmalıdır. Geçici bir hata oluşursa yürütme stratejisi temsilciyi yeniden çağırır.
using (var db = new BloggingContext())
{
var strategy = db.Database.CreateExecutionStrategy();
strategy.Execute(
() =>
{
using (var context = new BloggingContext())
{
using (var transaction = context.Database.BeginTransaction())
{
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();
transaction.Commit();
}
}
});
}
Bu yaklaşım, Ambient işlemler ile de kullanılabilir.
using (var context1 = new BloggingContext())
{
context1.Blogs.Add(new Blog { Url = "http://blogs.msdn.com/visualstudio" });
var strategy = context1.Database.CreateExecutionStrategy();
strategy.Execute(
() =>
{
using (var context2 = new BloggingContext())
{
using (var transaction = new TransactionScope())
{
context2.Blogs.Add(new Blog { Url = "http://blogs.msdn.com/dotnet" });
context2.SaveChanges();
context1.SaveChanges();
transaction.Complete();
}
}
});
}
İşlem işleme hatası ve teklik sorunu
Genel olarak, bir bağlantı hatası olduğunda geçerli işlem geri alınır. Ancak, işlem yürütülürken bağlantı kesildiğinde işlemin sonuç durumu bilinmez.
Varsayılan olarak, yürütme stratejisi işlem geri alınmış gibi işlemi yeniden dener, ancak böyle bir durum yoksa, yeni veritabanı durumu uyumsuzsa ya da işlem belirli bir duruma bağlı değilse veri bozulmasına yol açacağından, otomatik olarak oluşturulan anahtar değerleriyle yeni bir satır eklenirken bir özel durumla sonuçlanacaktır.
Bu konuyla başa çıkmak için birkaç yol vardır.
Seçenek 1-do (neredeyse) Nothing
İşlem işleme sırasında bağlantı hatası olasılığı düşük olduğundan, bu durum aslında gerçekleşirse uygulamanızın başarısız olması için kabul edilebilir hale gelebilir.
Ancak, yinelenen bir satır eklemek yerine bir özel durumun yapıldığından emin olmak için mağaza tarafından oluşturulan anahtarları kullanmaktan kaçının. İstemci tarafından oluşturulan bir GUID değeri veya bir istemci tarafı değer Oluşturucu kullanmayı düşünün.
Seçenek 2-uygulama durumunu yeniden derle
- Geçerli dosyayı atın
DbContext. - Yeni bir oluşturun
DbContextve uygulamanızın durumunu veritabanından geri yükleyin. - Kullanıcıya son işlemin başarıyla tamamlanmamış olabileceğini bildirin.
Seçenek 3-durum doğrulama ekleme
Veritabanı durumunu değiştiren işlemlerin çoğu için başarılı olup olmadığını denetleyen kodu eklemek mümkündür. EF, bu sayede daha kolay hale getirmek için bir genişletme yöntemi sağlar IExecutionStrategy.ExecuteInTransaction .
Bu yöntem başlar ve bir işlemi tamamlar ve ayrıca verifySucceeded işlem işlemesi sırasında geçici bir hata oluştuğunda çağrılan parametresindeki bir işlevi kabul eder.
using (var db = new BloggingContext())
{
var strategy = db.Database.CreateExecutionStrategy();
var blogToAdd = new Blog { Url = "http://blogs.msdn.com/dotnet" };
db.Blogs.Add(blogToAdd);
strategy.ExecuteInTransaction(
db,
operation: context => { context.SaveChanges(acceptAllChangesOnSuccess: false); },
verifySucceeded: context => context.Blogs.AsNoTracking().Any(b => b.BlogId == blogToAdd.BlogId));
db.ChangeTracker.AcceptAllChanges();
}
Not
Burada, SaveChangesacceptAllChangesOnSuccessfalseBlog varlık durumunun başarılı olursa olarak değiştirilmesini önlemek için olarak ayarlanmış olarak çağrılır UnchangedSaveChanges . Bu, işleme başarısız olursa ve işlem geri alınırsa aynı işlemi yeniden denemeye izin verir.
Seçenek 4-işlemi el Ile izleme
Mağaza tarafından oluşturulan anahtarları kullanmanız gerekiyorsa veya işleme bağlı olmayan işlem başarısızlıklarını işlemek için genel bir yönteme ihtiyaç duyuyorsanız, işleme başarısız olduğunda denetlenen bir KIMLIK atanabilir.
- İşlemin durumunu izlemek için kullanılan veritabanına tablo ekleyin.
- Her bir işlemin başındaki tabloya bir satır ekleyin.
- Kayıt sırasında bağlantı başarısız olursa, veritabanında karşılık gelen satırın varolup olmadığını kontrol edin.
- Kayıt başarılı olursa, tablonun büyümesini önlemek için karşılık gelen satırı silin.
using (var db = new BloggingContext())
{
var strategy = db.Database.CreateExecutionStrategy();
db.Blogs.Add(new Blog { Url = "http://blogs.msdn.com/dotnet" });
var transaction = new TransactionRow { Id = Guid.NewGuid() };
db.Transactions.Add(transaction);
strategy.ExecuteInTransaction(
db,
operation: context => { context.SaveChanges(acceptAllChangesOnSuccess: false); },
verifySucceeded: context => context.Transactions.AsNoTracking().Any(t => t.Id == transaction.Id));
db.ChangeTracker.AcceptAllChanges();
db.Transactions.Remove(transaction);
db.SaveChanges();
}
Not
Doğrulama için kullanılan bağlamın bağlantı, işlem kaydı sırasında başarısız olduysa doğrulama sırasında yeniden başarısız olması nedeniyle tanımlanmış bir yürütme stratejisi olduğundan emin olun.