iToverDose/Yazılım· 13 HAZIRAN 2026 · 08:04

EF Core Interceptor’da CommandText Değiştirmek Neden Tehlikeli?

EF Core interceptor’larında CommandText’i değiştirmek, SQLite ve SQL Server’da beklenmeyen sorunlara yol açıyor. İşte yapılan yaygın bir hatanın ardındaki gerçekler ve doğru yaklaşım.

DEV Community3 dk okuma0 Yorumlar

EF Core uygulamalarında veri tabanı sorgularını izlemek ve performanslarını analiz etmek için sıklıkla DbCommandInterceptor kullanılır. Ancak bu interceptor’larda yapılan basit bir hata, hem veritabanı loglarını bozabilir hem de kullanıcıların karşılaştığı beklenmedik istisnalarla sonuçlanabilir. Özellikle SQLite ile çalışan geliştiriciler, aylar boyunca gizli bir sorunla karşılaşmış olabilirler.

Sessizce Yayımlanan Bir Hata: SQLite’de Çöken Debug Aracı

Bir yılı aşkın süredir kullanılan bir debug aracı, SQLite’ye yönlendirildiğinde anında çöküyordu. Ancak sorun, yalnızca SQL Server’da test edildiği için gizli kalmıştı. Araç, EF Core’un çalıştırdığı SQL sorgularını kaydediyor ve bir gösterge paneeli üzerinden görüntülüyordu. Bunun için DbCommandInterceptor kullanılmış ve her sorgunun yürütülme süresini ölçmek amacıyla bir yöntem geliştirilmişti. İşte o yöntemin kod parçası:

public override InterceptionResult<DbDataReader> ReaderExecuting(
    DbCommand command,
    CommandEventData eventData,
    InterceptionResult<DbDataReader> result)
{
    var id = Guid.NewGuid();
    command.CommandText += $" /* {id}:{DateTime.UtcNow.Ticks} */";
    return result;
}

Bu kod, her sorgunun sonuna benzersiz bir kimlik ve zaman damgası ekliyordu. Daha sonra, sorgunun tamamlanmasının ardından ReaderExecuted metodunda bu bilgiyi parse ederek yürütme süresini hesaplıyordu. Basit bir şekilde çalışan bu sistem, aslında iki ciddi sorunu beraberinde getiriyordu.

Veritabanının Loglarını Bozan ve SQLite’yi Bozan Yaklaşım

İlk sorun, sorgunun veritabanına gönderilen içeriğini değiştirmekti. Her sorgunun sonuna eklenen yorum satırı, SQL Server tarafından sorunsuzca çalıştırılsa da, veritabanının kendi loglarını bozuyordu. Bu durum, aslında geliştiricinin veritabanına ait olmayan veriyi yazmasına neden oluyordu.

İkinci ve daha kritik sorun ise SQLite’de ortaya çıktı. Açık bir okuyucuya sahip olan bir komut üzerinde CommandText özelliğini değiştirmeye çalışmak, System.InvalidOperationException istisnasına yol açıyordu. Yerel geliştirme ortamında SQLite kullanıldığında, bu durum debug aracının kendisinin çökmesine neden oluyordu. Kullanıcılar, sorunlarını analiz etmek için kullandıkları aracın kendisinden bir istisna alıyordu.

EF Core’un Zaten Çözmüş Olduğu Bir Sorunu Yeniden İcat Etmek

Geliştirici, ReaderExecuting ve ReaderExecuted metodları arasında veri taşımak için karmaşık bir sistem geliştirmişti. Ancak aslında, EF Core’un zaten sunduğu bir çözüm vardı. ReaderExecuted metodu, sorgunun yürütülme süresini (eventData.Duration) ve komut nesnesini doğrudan sağlıyordu. Yani, geliştiricinin yaptığı ekleme gereksizdi ve sadece sorunlara yol açıyordu.

public override DbDataReader ReaderExecuted(
    DbCommand command,
    CommandExecutedEventData eventData,
    DbDataReader result)
{
    Record(command.CommandText, eventData.Duration);
    return result;
}

Bu kod parçası, sorgunun içeriğini değiştirmeye gerek kalmadan, doğrudan eventData.Duration üzerinden yürütme süresini kaydediyor. Geliştiricinin yaptığı eklemeler, hem veritabanının loglarını bozmuş hem de SQLite’de istisnalar oluşturmuştu.

Durum Taşıma için Doğru Yaklaşım: CommandId Kullanımı

Eğer interceptor’larda, komut yürütülmeden önce elde edilen verileri taşımanız gerekiyorsa, CommandId kullanmak en doğru yöntemdir. Bu kimlik, hem ReaderExecuting hem de ReaderExecuted metodlarında aynı kalır ve verileri güvenli bir şekilde taşımak için kullanılabilir.

private readonly ConcurrentDictionary<Guid, MyState> _inflight = new();

public override InterceptionResult<DbDataReader> ReaderExecuting(
    DbCommand command,
    CommandEventData eventData,
    InterceptionResult<DbDataReader> result)
{
    _inflight[eventData.CommandId] = CaptureWhateverYouNeed();
    return result;
}

public override DbDataReader ReaderExecuted(
    DbCommand command,
    CommandExecutedEventData eventData,
    DbDataReader result)
{
    if (_inflight.TryRemove(eventData.CommandId, out var state))
    {
        // state ve eventData.Duration kullanarak işlem yapın
    }
    return result;
}

Bu yaklaşım, komut nesnesini değiştirmek yerine, verileri interceptor’un kendi tarafında taşıyarak sorunları ortadan kaldırır.

Yeniden Yapılandırılan Bir Çözüm ve Gelecek Adımlar

Geliştirici, bu hatalardan ders çıkararak aracını yeniden yapılandırmış ve EF Core’un sunduğu doğal yöntemleri kullanmaya başlamıştır. Yeniden yayınlanan araç, artık sorguların gerçek parametre değerleriyle birlikte görüntülenmesini, logları, istisnaları ve N+1 sorguları tespit etmeyi sağlayan gelişmiş bir debug panelini içeriyor. .NET 8, 9 ve 10 sürümleriyle uyumlu olan bu araç, basitçe entegre edilebiliyor ve /_debug yolundan erişilebiliyor.

Eğer siz de EF Core interceptor’ları kullanıyorsanız, komut nesnesini değiştirip değiştirmediğinize dikkat edin. Basit görünen bu hata, hem veritabanı loglarını bozabilir hem de kullanıcıların karşılaşabileceği ciddi sorunlara yol açabilir. Unutmayın: komut nesnesi, okuma amacıyla kullanılmalıdır. İhtiyacınız olan verileri kendi tarafınızda taşıyın ve SQL sorgularınızı bozmaktan kaçının.

Yapay zeka özeti

EF Core interceptor’larında CommandText’i değiştirmek, SQLite çökmelerine ve SQL Server log sorunlarına yol açabilir. Doğru yaklaşım ve çözüm yöntemleri hakkında bilgi edinin.

Yorumlar

00
YORUM BIRAK
ID #CXHIRY

0 / 1200 KARAKTER

İnsan doğrulaması

3 + 8 = ?

Editör onayı sonrası yayına girer

Moderasyon · Spam koruması aktif

Henüz onaylı yorum yok. İlk yorumu sen bırak.