Delen via


.NET-gebeurtenissen in EF Core

Aanbeveling

U kunt het voorbeeld van gebeurtenissen downloaden vanuit GitHub.

Met Entity Framework Core (EF Core) worden .NET-gebeurtenissen beschikbaar gesteld om als callbacks te fungeren wanneer bepaalde dingen plaatsvinden in de EF Core-code. Gebeurtenissen zijn eenvoudiger dan interceptors en maken flexibelere registratie mogelijk. Ze zijn echter strikt synchroon en kunnen daarom geen niet-blokkerende asynchrone I/O uitvoeren.

Gebeurtenissen worden geregistreerd per DbContext exemplaar. Gebruik een diagnostische listener om dezelfde informatie op te halen, maar voor alle DbContext-exemplaren in het proces.

Gebeurtenissen die door EF Core worden uitgelokt

De volgende gebeurtenissen worden gegenereerd door EF Core:

Gebeurtenis Wanneer deze wordt verhoogd
DbContext.SavingChanges Aan het begin van SaveChanges of SaveChangesAsync
DbContext.SavedChanges Aan het einde van een geslaagde SaveChanges of SaveChangesAsync
DbContext.SaveChangesFailed Aan het einde van een mislukte SaveChanges of SaveChangesAsync
ChangeTracker.Tracked Wanneer een entiteit wordt bijgehouden door de context
ChangeTracker.StateChanged Wanneer een bijgehouden entiteit de status wijzigt

Voorbeeld: wijzigingen van tijdstempelstatus

Elke entiteit die wordt bijgehouden door een DbContext heeft een EntityState. De status geeft bijvoorbeeld Added aan dat de entiteit wordt ingevoegd in de database.

In dit voorbeeld worden de Tracked en StateChanged gebeurtenissen gebruikt om te detecteren wanneer een entiteit de status wijzigt. Vervolgens wordt de entiteit gestempeld met de huidige tijd die aangeeft wanneer deze wijziging is opgetreden. Dit resulteert in tijdstempels die aangeven wanneer de entiteit is ingevoegd, verwijderd en/of voor het laatst is bijgewerkt.

De entiteitstypen in dit voorbeeld implementeren een interface waarmee de tijdstempeleigenschappen worden gedefinieerd:

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

Een methode op dbContext van de toepassing kan vervolgens tijdstempels instellen voor elke entiteit die deze interface implementeert:

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;
        }
    }
}

Deze methode heeft de juiste signatuur om te gebruiken als een gebeurtenis-handler voor zowel de Tracked- als de StateChanged-gebeurtenissen. De handler is geregistreerd voor beide gebeurtenissen in de DbContext-constructor. Houd er rekening mee dat gebeurtenissen op elk gewenst moment aan een DbContext kunnen worden gekoppeld; dit is niet vereist in de contextconstructor.

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

Beide gebeurtenissen zijn nodig omdat nieuwe entiteiten gebeurtenissen activeren Tracked wanneer ze voor het eerst worden bijgehouden. StateChanged gebeurtenissen worden alleen geactiveerd voor entiteiten die de status wijzigen terwijl ze al worden bijgehouden.

Het voorbeeld voor dit voorbeeld bevat een eenvoudige consoletoepassing die wijzigingen aanbrengt in de blogdatabase:

using (var context = new BlogsContext())
{
    await context.Database.EnsureDeletedAsync();
    await context.Database.EnsureCreatedAsync();

    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!" } }
        });

    await context.SaveChangesAsync();
}

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

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

    await context.SaveChangesAsync();
}

De uitvoer van deze code toont de statuswijzigingen en de tijdstempels die worden toegepast:

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