Dayanıklı Entity Framework Core SQL bağlantıları uygulama
İpucu
Bu içerik, .NET Docs'ta veya çevrimdışı olarak okunabilen ücretsiz indirilebilir bir PDF olarak sağlanan Kapsayıcılı .NET Uygulamaları için .NET Mikro Hizmet Mimarisi e-Kitabı'ndan bir alıntıdır.
Azure SQL DB için Entity Framework (EF) Core zaten iç veritabanı bağlantısı dayanıklılığı ve yeniden deneme mantığı sağlar. Ancak dayanıklı EF Core bağlantılarına sahip olmak istiyorsanız her DbContext bağlantı için Entity Framework yürütme stratejisini etkinleştirmeniz gerekir.
Örneğin, EF Core bağlantı düzeyinde aşağıdaki kod, bağlantı başarısız olursa yeniden denenen dayanıklı SQL bağlantılarını etkinleştirir.
// Program.cs from any ASP.NET Core Web API
// Other code ...
builder.Services.AddDbContext<CatalogContext>(options =>
{
options.UseSqlServer(builder.Configuration["ConnectionString"],
sqlServerOptionsAction: sqlOptions =>
{
sqlOptions.EnableRetryOnFailure(
maxRetryCount: 10,
maxRetryDelay: TimeSpan.FromSeconds(30),
errorNumbersToAdd: null);
});
});
BeginTransaction ve birden çok DbContext kullanarak yürütme stratejileri ve açık işlemler
EF Core bağlantılarında yeniden denemeler etkinleştirildiğinde, EF Core kullanarak gerçekleştirdiğiniz her işlem kendi yeniden denenebilir işlemi olur. Her sorgu ve her çağrısı SaveChanges
, geçici bir hata oluşursa birim olarak yeniden denenir.
Ancak kodunuz kullanarak BeginTransaction
bir işlem başlatırsa, birim olarak ele alınması gereken kendi işlem grubunuzu tanımlarsınız. Bir hata oluşursa işlem içindeki her şeyin geri alınması gerekir.
EF yürütme stratejisini (yeniden deneme ilkesi) kullanırken bu işlemi yürütmeye çalışırsanız ve birden çok DbContexts'ten çağırırsanız SaveChanges
aşağıdakine benzer bir özel durumla karşı karşıyasınız:
System.InvalidOperationException: Yapılandırılan yürütme stratejisi 'SqlServerRetryingExecutionStrategy' kullanıcı tarafından başlatılan işlemleri desteklemiyor. İşlemdeki tüm işlemleri yeniden denenebilir bir birim olarak yürütmek için 'DbContext.Database.CreateExecutionStrategy()' tarafından döndürülen yürütme stratejisini kullanın.
Çözüm, EF yürütme stratejisini, yürütülmesi gereken her şeyi temsil eden bir temsilciyle el ile çağırmaktır. Geçici bir hata oluşursa yürütme stratejisi temsilciyi yeniden çağırır. Örneğin aşağıdaki kod, bir ürünü güncelleştirirken ve sonra farklı bir DbContext kullanması gereken ProductPriceChangedIntegrationEvent nesnesini kaydederken iki birden çok DbContext (_catalogContext ve IntegrationEventLogContext) içeren eShopOnContainers'da nasıl uygulandığını gösterir.
public async Task<IActionResult> UpdateProduct(
[FromBody]CatalogItem productToUpdate)
{
// Other code ...
var oldPrice = catalogItem.Price;
var raiseProductPriceChangedEvent = oldPrice != productToUpdate.Price;
// Update current product
catalogItem = productToUpdate;
// Save product's data and publish integration event through the Event Bus
// if price has changed
if (raiseProductPriceChangedEvent)
{
//Create Integration Event to be published through the Event Bus
var priceChangedEvent = new ProductPriceChangedIntegrationEvent(
catalogItem.Id, productToUpdate.Price, oldPrice);
// Achieving atomicity between original Catalog database operation and the
// IntegrationEventLog thanks to a local transaction
await _catalogIntegrationEventService.SaveEventAndCatalogContextChangesAsync(
priceChangedEvent);
// Publish through the Event Bus and mark the saved event as published
await _catalogIntegrationEventService.PublishThroughEventBusAsync(
priceChangedEvent);
}
// Just save the updated product because the Product's Price hasn't changed.
else
{
await _catalogContext.SaveChangesAsync();
}
}
Birincisi DbContext , _catalogContext
ikincisi DbContext
nesnenin _catalogIntegrationEventService
içindedir. İşleme eylemi, EF yürütme stratejisi kullanılarak tüm DbContext
nesneler arasında gerçekleştirilir.
Bu birden çok DbContext
işlemeyi SaveEventAndCatalogContextChangesAsync
başarmak için aşağıdaki kodda gösterildiği gibi bir ResilientTransaction
sınıf kullanır:
public class CatalogIntegrationEventService : ICatalogIntegrationEventService
{
//…
public async Task SaveEventAndCatalogContextChangesAsync(
IntegrationEvent evt)
{
// Use of an EF Core resiliency strategy when using multiple DbContexts
// within an explicit BeginTransaction():
// https://learn.microsoft.com/ef/core/miscellaneous/connection-resiliency
await ResilientTransaction.New(_catalogContext).ExecuteAsync(async () =>
{
// Achieving atomicity between original catalog database
// operation and the IntegrationEventLog thanks to a local transaction
await _catalogContext.SaveChangesAsync();
await _eventLogService.SaveEventAsync(evt,
_catalogContext.Database.CurrentTransaction.GetDbTransaction());
});
}
}
ResilientTransaction.ExecuteAsync
yöntemi temel olarak geçirilen DbContext
(_catalogContext
) işleminden bir işlem başlatır ve ardından dosyasındaki EventLogService
değişiklikleri IntegrationEventLogContext
kaydetmek için bu işlemi kullanır ve ardından işlemin tamamını işler.
public class ResilientTransaction
{
private DbContext _context;
private ResilientTransaction(DbContext context) =>
_context = context ?? throw new ArgumentNullException(nameof(context));
public static ResilientTransaction New (DbContext context) =>
new ResilientTransaction(context);
public async Task ExecuteAsync(Func<Task> action)
{
// Use of an EF Core resiliency strategy when using multiple DbContexts
// within an explicit BeginTransaction():
// https://learn.microsoft.com/ef/core/miscellaneous/connection-resiliency
var strategy = _context.Database.CreateExecutionStrategy();
await strategy.ExecuteAsync(async () =>
{
await using var transaction = await _context.Database.BeginTransactionAsync();
await action();
await transaction.CommitAsync();
});
}
}
Ek kaynaklar
ASP.NET MVC Uygulamasında EF ile Bağlan Ion Dayanıklılığı ve Komut Kesme
https://learn.microsoft.com/aspnet/mvc/overview/getting-started/getting-started-with-ef-using-mvc/connection-resiliency-and-command-interception-with-the-entity-framework-in-an-asp-net-mvc-applicationCesar de la Torre. Dayanıklı Entity Framework Core SQL Bağlan ions ve İşlemleri Kullanma
https://devblogs.microsoft.com/cesardelatorre/using-resilient-entity-framework-core-sql-connections-and-transactions-retries-with-exponential-backoff/
Geri Bildirim
https://aka.ms/ContentUserFeedback.
Çok yakında: 2024 boyunca, içerik için geri bildirim mekanizması olarak GitHub Sorunları’nı kullanımdan kaldıracak ve yeni bir geri bildirim sistemiyle değiştireceğiz. Daha fazla bilgi için bkz.Gönderin ve geri bildirimi görüntüleyin