Aracılığıyla paylaş


EF Core'da Tanılama Dinleyicilerini Kullanma

Bahşiş

Bu makalenin örneğini GitHub'dan indirebilirsiniz.

Tanılama dinleyicileri geçerli .NET işleminde gerçekleşen tüm EF Core olayları için dinleme sağlar. DiagnosticListener sınıfı, çalışan uygulamalardan tanılama bilgilerini almak için .NET genelinde ortak bir mekanizmanın bir parçasıdır.

Tanılama dinleyicileri tek bir DbContext örneğinden olayları almaya uygun değildir. EF Core kesiciler , bağlam başına kayıt ile aynı olaylara erişim sağlar.

Tanılama dinleyicileri günlüğe kaydetme için tasarlanmamıştır. Günlük kaydı için basit günlüğe kaydetmeyi veya Microsoft.Extensions.Logging'u kullanmayı göz önünde bulundurun.

Örnek: Tanılama olaylarını gözlemleme

EF Core olaylarını çözümlemek iki adımlı bir işlemdir. İlk olarak, kendisi için DiagnosticListener bir gözlemci oluşturulmalıdır:

public class DiagnosticObserver : IObserver<DiagnosticListener>
{
    public void OnCompleted()
        => throw new NotImplementedException();

    public void OnError(Exception error)
        => throw new NotImplementedException();

    public void OnNext(DiagnosticListener value)
    {
        if (value.Name == DbLoggerCategory.Name) // "Microsoft.EntityFrameworkCore"
        {
            value.Subscribe(new KeyValueObserver());
        }
    }
}

OnNext yöntemi EF Core'dan gelen DiagnosticListener'ı arar. Bu dinleyicinin adı "Microsoft.EntityFrameworkCore", gösterildiği gibi sınıfından DbLoggerCategory alınabilir.

Bu gözlemcinin genel olarak kaydedilmesi gerekir, örneğin uygulamanın Main yönteminde:

DiagnosticListener.AllListeners.Subscribe(new DiagnosticObserver());

İkincisi, EF Core DiagnosticListener bulunduktan sonra, gerçek EF Core olaylarına abone olmak için yeni bir anahtar-değer gözlemcisi oluşturulur. Örnek:

public class KeyValueObserver : IObserver<KeyValuePair<string, object>>
{
    public void OnCompleted()
        => throw new NotImplementedException();

    public void OnError(Exception error)
        => throw new NotImplementedException();

    public void OnNext(KeyValuePair<string, object> value)
    {
        if (value.Key == CoreEventId.ContextInitialized.Name)
        {
            var payload = (ContextInitializedEventData)value.Value;
            Console.WriteLine($"EF is initializing {payload.Context.GetType().Name} ");
        }

        if (value.Key == RelationalEventId.ConnectionOpening.Name)
        {
            var payload = (ConnectionEventData)value.Value;
            Console.WriteLine($"EF is opening a connection to {payload.Connection.ConnectionString} ");
        }
    }
}

OnNext yöntemi bu kez her EF Core olayı için bir anahtar/değer çifti ile çağrılır. Anahtar, aşağıdakilerden birinden elde edilebilen olayın adıdır:

  • CoreEventId tüm EF Core veritabanı sağlayıcıları için ortak olaylar için
  • RelationalEventId tüm ilişkisel veritabanı sağlayıcılarının ortak olduğu olaylar için
  • Geçerli veritabanı sağlayıcısına özgü olaylar için benzer bir sınıf. Örneğin, SqlServerEventId SQL Server sağlayıcısı için.

Anahtar/değer çiftinin değeri, olaya özgü bir yük türüdür. Bekleyebileceğiniz yük türü, bu olay sınıflarında tanımlanan her olayda belgelenmiştir.

Örneğin, yukarıdaki kod ve olaylarını ContextInitialized ConnectionOpening işler. Bunlardan ilki için yük şeklindedir ContextInitializedEventData. İkincisi ise.ConnectionEventData

Bahşiş

ToString, her EF Core olay veri sınıfında geçersiz kılınarak olay için eşdeğer günlük iletisi oluşturulur. Örneğin, çağrısı ContextInitializedEventData.ToString "Microsoft.EntityFrameworkCore.Sqlite' sağlayıcısını kullanarak "Entity Framework Core 5.0.0 tarafından başlatılan 'BlogsContext' oluşturur ve seçenekler: Yok".

Örnek, blog veritabanında değişiklik yapan ve karşılaşılan tanılama olaylarını yazdıran basit bir konsol uygulaması içerir.

public static void Main()
{
    DiagnosticListener.AllListeners.Subscribe(new DiagnosticObserver());

    using (var context = new BlogsContext())
    {
        context.Database.EnsureDeleted();
        context.Database.EnsureCreated();

        context.Add(
            new Blog { Name = "EF Blog", Posts = { new Post { Title = "EF Core 3.1!" }, new Post { Title = "EF Core 5.0!" } } });

        context.SaveChanges();
    }

    using (var context = new BlogsContext())
    {
        var blog = context.Blogs.Include(e => e.Posts).Single();

        blog.Name = "EF Core Blog";
        context.Remove(blog.Posts.First());
        blog.Posts.Add(new Post { Title = "EF Core 6.0!" });

        context.SaveChanges();
    }

Bu koddan elde edilen çıkışta algılanan olaylar gösterilir:

EF is initializing BlogsContext
EF is opening a connection to Data Source=blogs.db;Mode=ReadOnly
EF is opening a connection to DataSource=blogs.db
EF is opening a connection to Data Source=blogs.db;Mode=ReadOnly
EF is opening a connection to DataSource=blogs.db
EF is opening a connection to DataSource=blogs.db
EF is opening a connection to DataSource=blogs.db
EF is initializing BlogsContext
EF is opening a connection to DataSource=blogs.db
EF is opening a connection to DataSource=blogs.db