Starts in:
2 DAYS
16 HRS
21 MIN
46 SEC
Starts in:
2 D
16 H
21 M
46 S
Open Closed

EntityFrameworkCore.Triggered and ABP? #1417


User avatar
0
hansmogren created

I want to use https://github.com/koenbeuk/EntityFrameworkCore.Triggered in my ABP solution but I can't figure out how to register the triggers with my AbpDbContext.

This is what the documentation for EntityFrameworkCore.Triggered suggests:

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services
            .AddDbContext<ApplicationContext>(options => {
                options.UseTriggers(triggerOptions => {
                    triggerOptions.AddTrigger<MyTrigger>();
                });
            })
    }
}

How can I use this library with with ABP?


10 Answer(s)
  • User Avatar
    0
    liangshiwei created
    Support Team Fullstack Developer

    Hi,

    Open *.EntityFrameworkCoreModule and find Configure<AbpDbContextOptions>:

    Configure<AbpDbContextOptions>(options =>
    {
        /* The main point to change your DBMS.
         * See also MyProjectNameMigrationsDbContextFactory for EF Core tooling. */
        options.UseSqlServer();
    
        options.Configure(c =>
        {
            c.DbContextOptions.UseTriggers();
        });
    });
    
  • User Avatar
    0
    hansmogren created

    Thanks! However, when I try that I get an error on application start:

    An unhandled exception occurred while processing the request. InvalidOperationException: No database provider has been configured for this DbContext. A provider can be configured by overriding the 'DbContext.OnConfiguring' method or by using 'AddDbContext' on the application service provider. If 'AddDbContext' is used, then also ensure that your DbContext type accepts a DbContextOptions<TContext> object in its constructor and passes it to the base constructor for DbContext.

    Microsoft.EntityFrameworkCore.Internal.DbContextServices.Initialize(IServiceProvider scopedProvider, IDbContextOptions contextOptions, DbContext context)

    Stack trace:

    <br>

    InvalidOperationException: No database provider has been configured for this DbContext. A provider can be configured by overriding the 'DbContext.OnConfiguring' method or by using 'AddDbContext' on the application service provider. If 'AddDbContext' is used, then also ensure that your DbContext type accepts a DbContextOptions<TContext> object in its constructor and passes it to the base constructor for DbContext.
    
        Microsoft.EntityFrameworkCore.Internal.DbContextServices.Initialize(IServiceProvider scopedProvider, IDbContextOptions contextOptions, DbContext context)
        Microsoft.EntityFrameworkCore.DbContext.get_InternalServiceProvider()
        Microsoft.EntityFrameworkCore.DbContext.get_ChangeTracker()
        Volo.Abp.EntityFrameworkCore.AbpDbContext<TDbContext>.Initialize(AbpEfCoreDbContextInitializationContext initializationContext)
        Volo.Abp.Uow.EntityFrameworkCore.UnitOfWorkDbContextProvider<TDbContext>.CreateDbContextAsync(IUnitOfWork unitOfWork, string connectionStringName, string connectionString)
        Volo.Abp.Uow.EntityFrameworkCore.UnitOfWorkDbContextProvider<TDbContext>.GetDbContextAsync()
        Volo.Abp.Domain.Repositories.EntityFrameworkCore.EfCoreRepository<TDbContext, TEntity>.GetDbSetAsync()
        Volo.Abp.LanguageManagement.EntityFrameworkCore.EfCoreLanguageRepository.GetListAsync(bool isEnabled)
        Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous<TResult>(IInvocation invocation, IInvocationProceedInfo proceedInfo)
        Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue<TResult>.ProceedAsync()
        Volo.Abp.Uow.UnitOfWorkInterceptor.InterceptAsync(IAbpMethodInvocation invocation)
        Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter<TInterceptor>.InterceptAsync<TResult>(IInvocation invocation, IInvocationProceedInfo proceedInfo, Func<IInvocation, IInvocationProceedInfo, Task<TResult>> proceed)
        Volo.Abp.LanguageManagement.DatabaseLanguageProvider.oBPl0rvdv()
        Volo.Abp.Caching.DistributedCache<TCacheItem, TCacheKey>.GetOrAddAsync(TCacheKey key, Func<Task<TCacheItem>> factory, Func<DistributedCacheEntryOptions> optionsFactory, Nullable<bool> hideErrors, bool considerUow, CancellationToken token)
        Volo.Abp.LanguageManagement.DatabaseLanguageProvider.GetLanguagesAsync()
        Microsoft.AspNetCore.RequestLocalization.DefaultAbpRequestLocalizationOptionsProvider.GetLocalizationOptionsAsync()
        Microsoft.AspNetCore.RequestLocalization.AbpRequestLocalizationMiddleware.InvokeAsync(HttpContext context, RequestDelegate next)
        Microsoft.AspNetCore.Builder.UseMiddlewareExtensions+<>c__DisplayClass6_1+<<UseMiddlewareInterface>b__1>d.MoveNext()
        Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
    
    
  • User Avatar
    0
    liangshiwei created
    Support Team Fullstack Developer

    Try:

    Configure<AbpDbContextOptions>(options =>
    {
        options.Configure(c =>
        {
            c.UseSqlServer();
            c.DbContextOptions.UseTriggers();
        });
    });
    
  • User Avatar
    0
    hansmogren created

    Thanks, that change made the trigger be registered and triggered.

    However the dependency injection failed while instantiating my trigger class. I am injecting an IRepository into it and got an exception: System.InvalidOperationException: 'Unable to resolve service for type 'MyProjectName.IMyEntityRepository' while attempting to activate 'MyProjectName.BeforeSaveTrigger'.'

    I solved this by including the line t.UseApplicationScopedServiceProviderAccessor(_ => context.Services.GetServiceProviderOrNull()); as below since the the documentation at https://github.com/koenbeuk/EntityFrameworkCore.Triggered/wiki/Dependency-injection mentions this solution:

    Configure a method that returns the current relevant ServiceProvider. This can be done by providing a method through: triggerOptions.UseApplicationScopedServiceProviderAccessor(sp => ...). The first argument will be either the application ServiceProvider if available or otherwise the internal service provider.

    Does this seem like a reasonable solution or will it break something?

                options.Configure(c =>
                {
                    c.UseSqlServer();
                    c.DbContextOptions.UseTriggers(t =>
                    {
                        t.UseApplicationScopedServiceProviderAccessor(_ => context.Services.GetServiceProviderOrNull());
                        t.AddTrigger&lt;BeforeSaveTrigger&gt;();
                    });
                });
    
  • User Avatar
    0
    liangshiwei created
    Support Team Fullstack Developer

    hi,

    This way will be better

    c.DbContextOptions.UseTriggers(t =>
    {
        t.UseApplicationScopedServiceProviderAccessor(_ => _.GetRequiredService<IHttpContextAccessor>().HttpContext?.RequestServices);
    });
    
  • User Avatar
    0
    hansmogren created
    c.DbContextOptions.UseTriggers(t => 
    { 
        t.UseApplicationScopedServiceProviderAccessor(_ => _.GetRequiredService<IHttpContextAccessor>().HttpContext?.RequestServices); 
    }); 
    

    Doing this way I get System.InvalidOperationException: 'No service for type 'Microsoft.AspNetCore.Http.IHttpContextAccessor' has been registered.' on application start.

  • User Avatar
    0
    liangshiwei created
    Support Team Fullstack Developer

    After my test, the following code is ok.

    Configure<AbpDbContextOptions>(options =>
    {
    
        options.Configure(c =>
        {
            c.UseSqlServer();
            c.DbContextOptions.UseTriggers(t =>
            {
                t.UseApplicationScopedServiceProviderAccessor(_ => _.CreateScope().ServiceProvider);
            });
    
        });
    });
    
  • User Avatar
    0
    hansmogren created

    After my test, the following code is ok.

    Sorry, but I get System.InvalidOperationException: 'Unable to resolve service for type 'MyProjectName.IMyEntityRepository' while attempting to activate 'MyProjectName.BeforeSaveTrigger'.' doing it this way as well.

  • User Avatar
    0
    liangshiwei created
    Support Team Fullstack Developer

    Can you share the full logs?

  • User Avatar
    0
    ServiceBot created
    Support Team Automatic process manager

    This question has been automatically marked as stale because it has not had recent activity.

Made with ❤️ on ABP v9.1.0-preview. Updated on November 20, 2024, 13:06