Closed debelidane closed 1 year ago
Is there a way to initialize my own instance of the trigger class on UseTriggers?
Certainly!
triggerOptions.AddTrigger(new MyTriggerClass(NullLogger.Instance));
However, this is now a singleton instance. Note how I was not able to pass in the DbContext
since none exists at the moment of registering that trigger instance.
But probably, you would want to ensure that EF Core has an ApplicationServiceProvider where it can provide services from. If you're resolving the DbContext from DI then all you need to do is call AddLogging()
on the ServiceCollection. However, in case you're manually newing up a DbContext instance, you can still provide it with a ServiceProvider in the OnConfiguring method:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
// Build an application service provider
var serviceProvider = new ServiceCollection()
.AddLogging() // Add Logging
.BuildServiceProvider();
optionsBuilder
.UseInMemoryDatabase("HelloWorld")
.UseTriggers(triggerOptions => {
triggerOptions.AddTrigger<MyTriggerClass>();
})
.UseApplicationServiceProvider(serviceProvider); // Register it so that DI can use it
}
Thanks for the quick and good response :) I have some follow up questions. I managed to register the way you described. Now when I run the test it goes good until i SaveChangesAsync and the trigger is fired. When this happens I get this error:
Message: System.InvalidOperationException : Unable to resolve service for type 'DbContexts.MyDBContext' while attempting to activate 'Triggers.MyTriggerClass'.
I am newing up the DbContext, but maybe I should try with DI. Currently it is like this:
DbContext = new MyDBContext();
My OnConfiguring looks like this: `protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { // Build an application service provider var serviceProvider = new ServiceCollection() .AddLogging() // Add Logging .BuildServiceProvider();
if (!optionsBuilder.IsConfigured)
{
optionsBuilder.UseSqlite($"Data Source={DbPath}")
.UseTriggers(triggerOptions =>
{
triggerOptions
.UseTransactionTriggers()
.AddTrigger<MyTriggerClass>();
})
.UseApplicationServiceProvider(serviceProvider);
}
}`
This is because it's trying to grab the DbContext from dependency injection where it's not registered. The simplest solution would be to register the DbContext ServiceProvider
however your trigger will then NOT receive the same DbContext
instance as the one that was used to invoke the trigger to begin with.
Instead, you can install EntityFrameworkCore.Triggered.Extensions. This comes with an extension method that lets you grab the DbContext from the ChangeContext:
class MyTriggerClass : IBeforeSaveTrigger<MyEntity> {
public Task BeforeSaveChanges(TriggerContext<MyEntity> context, CancellationToken _) {
var dbContext = (MyDbContext)context.GetDbContext();
...
}
}
I have a trigger class called MyTriggerClass that takes a constructor with params DbContext and ILogger. This works great in my application. But now I want to run unit test against the DBContext and I registered the trigger and the trigger should fire. But when I try to run the unit tests I get an error saying: Unable to resolve service for type ILogger while attempting to activate MyTriggerClass
Is there a way to initialize my own instance of the trigger class on UseTriggers? Or do you know how I should dependency inject my instance of Logger to MyTriggerClass in unit tests?