EntityFrameworkCore.Triggered icon indicating copy to clipboard operation
EntityFrameworkCore.Triggered copied to clipboard

Another instance for IAfterSaveCompletedTrigger and IAfterSaveTrigger<T>

Open possibility022 opened this issue 1 year ago • 4 comments

Hello

I have a problem with the triggers. According to examples I can implement two different interfaces

  • IAfterSaveTrigger<T>
  • IAfterSaveCompletedTrigger

From my understanding there can be many calls to AfterSave within one SaveChanges and there should be just one call to AfterSaveCompleted. What is important, it should be the same instance of a class. However, it is not in my case. All calls to AfterSave are done to instance [A] and call to AfterSaveCompleted is done to instance [B]. Is this a bug or is this indented? I am using DI on .net 7.

Here is repro code:

Output:

AfterSave from 4057632
AfterSave from 4057632
AfterSaveCompleted from 5223998

Program.cs

// See https://aka.ms/new-console-template for more information
using EntityFrameworkCore.Triggered;
using EntityFrameworkCore.Triggered.Lifecycles;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

HostBuilder builder = new();

builder.ConfigureServices(services =>
{
    services.AddDbContext<DB>(options =>
    {
        options.UseSqlite("DataSource=:memory:");
        options.UseTriggers(triggerOptions =>
        {
            triggerOptions.AddTrigger<EfTrigger>(ServiceLifetime.Scoped);
        });
    });
});

var host = builder.Build();
using var scope = host.Services.CreateScope();

var db = scope.ServiceProvider.GetRequiredService<DB>();
db.Database.OpenConnection();

db.Database.EnsureCreated();

db.Entities.Add(new Entity());
db.Entities.Add(new Entity());

db.SaveChanges();

class Entity
{
    public Guid Id { get; set; } = Guid.NewGuid();
}

class DB : DbContext
{

    public DB(DbContextOptions<DB> options) : base(options)
    {
        
    }

    public DbSet<Entity> Entities { get; set; }
}

class EfTrigger
    : IAfterSaveTrigger<Entity>,
    IAfterSaveCompletedTrigger
{
    public Task AfterSave(ITriggerContext<Entity> context, CancellationToken cancellationToken)
    {
        Console.WriteLine("AfterSave from " + this.GetHashCode());
        return Task.CompletedTask;
    }

    public Task AfterSaveCompleted(CancellationToken cancellationToken)
    {
        Console.WriteLine("AfterSaveCompleted from " + this.GetHashCode());
        return Task.CompletedTask;
    }
}


Project.cs:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net7.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="EntityFrameworkCore.Triggered" Version="3.2.2" />
    <PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.15" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.15" />
    <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0" />
    <PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1" />
  </ItemGroup>

</Project>

possibility022 avatar Feb 08 '24 13:02 possibility022

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

stale[bot] avatar Apr 12 '24 03:04 stale[bot]

I face the same problem with IBeforeSaveTrigger/IBeforeSaveCompletedTrigger

bercht-a avatar Apr 30 '24 12:04 bercht-a

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

stale[bot] avatar Jun 30 '24 05:06 stale[bot]

I have a WIP fix for this issue that I'm still testing out. Meanwhile, a temporary workaround is to register your triggers directly with the service provider. I plan on getting this fix merged within the coming days

koenbeuk avatar Aug 19 '24 00:08 koenbeuk