Zdarzenia platformy .NET w programie EF Core

Napiwek

Przykładowe zdarzenia można pobrać z usługi GitHub.

Program Entity Framework Core (EF Core) uwidacznia zdarzenia platformy .NET do działania jako wywołania zwrotnego, gdy w kodzie platformy EF Core występują pewne elementy. Zdarzenia są prostsze niż przechwytuje i umożliwiają bardziej elastyczną rejestrację. Jednak są one tylko do synchronizacji, dlatego nie mogą wykonywać nieblokujących asynchronicznych operacji we/wy.

Zdarzenia są rejestrowane na DbContext wystąpienie. Użyj odbiornika diagnostycznego, aby uzyskać te same informacje ale dla wszystkich wystąpień obiektu DbContext w procesie.

Zdarzenia zgłaszane przez program EF Core

Następujące zdarzenia są wywoływane przez program EF Core:

Wydarzenie Po podniesioniu
DbContext.SavingChanges Na początku SaveChanges lub SaveChangesAsync
DbContext.SavedChanges Na końcu powodzenia SaveChanges lub SaveChangesAsync
DbContext.SaveChangesFailed Na końcu błędu SaveChanges lub SaveChangesAsync
ChangeTracker.Tracked Kiedy jednostka jest śledzona przez kontekst
ChangeTracker.StateChanged Gdy śledzona jednostka zmienia swój stan

Przykład: zmiany stanu znacznika czasu

Każda jednostka śledzona przez element DbContext ma element EntityState. Na przykład stan wskazuje, Added że jednostka zostanie wstawiona do bazy danych.

W tym przykładzie użyto zdarzeń Tracked i StateChanged do wykrywania, kiedy jednostka zmienia stan. Następnie oznacza jednostkę bieżącą godziną wskazującą, kiedy ta zmiana się wydarzyła. Spowoduje to znaczniki czasu wskazujące, kiedy jednostka została wstawiona, usunięta i/lub ostatnia aktualizacja.

Typy jednostek w tym przykładzie implementują interfejs definiujący właściwości znacznika czasu:

public interface IHasTimestamps
{
    DateTime? Added { get; set; }
    DateTime? Deleted { get; set; }
    DateTime? Modified { get; set; }
}

Metoda w obiekcie DbContext aplikacji może następnie ustawić znaczniki czasu dla dowolnej jednostki, która implementuje ten interfejs:

private static void UpdateTimestamps(object sender, EntityEntryEventArgs e)
{
    if (e.Entry.Entity is IHasTimestamps entityWithTimestamps)
    {
        switch (e.Entry.State)
        {
            case EntityState.Deleted:
                entityWithTimestamps.Deleted = DateTime.UtcNow;
                Console.WriteLine($"Stamped for delete: {e.Entry.Entity}");
                break;
            case EntityState.Modified:
                entityWithTimestamps.Modified = DateTime.UtcNow;
                Console.WriteLine($"Stamped for update: {e.Entry.Entity}");
                break;
            case EntityState.Added:
                entityWithTimestamps.Added = DateTime.UtcNow;
                Console.WriteLine($"Stamped for insert: {e.Entry.Entity}");
                break;
        }
    }
}

Ta metoda ma odpowiedni podpis do użycia jako program obsługi zdarzeń zarówno dla zdarzeń, jak Tracked i StateChanged . Program obsługi jest rejestrowany dla obu zdarzeń w konstruktorze DbContext. Należy pamiętać, że zdarzenia mogą być dołączane do obiektu DbContext w dowolnym momencie; nie jest wymagane, aby miało to miejsce w konstruktorze kontekstu.

public BlogsContext()
{
    ChangeTracker.StateChanged += UpdateTimestamps;
    ChangeTracker.Tracked += UpdateTimestamps;
}

Oba zdarzenia są potrzebne, ponieważ nowe jednostki uruchamiają Tracked zdarzenia po pierwszym śledzeniu. StateChanged Zdarzenia są wyzwalane tylko dla jednostek, które zmieniają stan, gdy są już śledzone.

Przykład dla tego przykładu zawiera prostą aplikację konsolową, która wprowadza zmiany w bazie danych blogów:

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

    context.Add(
        new Blog
        {
            Id = 1,
            Name = "EF Blog",
            Posts = { new Post { Id = 1, Title = "EF Core 3.1!" }, new Post { Id = 2, 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 { Id = 3, Title = "EF Core 6.0!" });

    context.SaveChanges();
}

Dane wyjściowe z tego kodu pokazują zmiany stanu i zastosowane znaczniki czasu:

Stamped for insert: Blog 1 Added on: 10/15/2020 11:01:26 PM
Stamped for insert: Post 1 Added on: 10/15/2020 11:01:26 PM
Stamped for insert: Post 2 Added on: 10/15/2020 11:01:26 PM
Stamped for delete: Post 1 Added on: 10/15/2020 11:01:26 PM Deleted on: 10/15/2020 11:01:26 PM
Stamped for update: Blog 1 Added on: 10/15/2020 11:01:26 PM Modified on: 10/15/2020 11:01:26 PM
Stamped for insert: Post 3 Added on: 10/15/2020 11:01:26 PM