using System.Reflection; using CShells.Features; using Elsa.Common.Entities; using Elsa.Extensions; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Diagnostics; using Microsoft.Extensions.DependencyInjection; // ReSharper disable once CheckNamespace namespace Elsa.Persistence.EFCore; public abstract class PersistenceShellFeatureBase : IShellFeature where TDbContext : ElsaDbContextBase { /// /// Gets or sets a value indicating whether to use context pooling. /// public bool UseContextPooling { get; set; } /// /// Gets or sets a value indicating whether to run migrations. /// public bool RunMigrations { get; set; } = true; /// /// Gets or sets the lifetime of the . Defaults to . /// public ServiceLifetime DbContextFactoryLifetime { get; set; } = ServiceLifetime.Scoped; /// /// Gets or sets the connection string to use for the database. /// public string ConnectionString { get; set; } = null!; /// /// Gets or sets additional options to configure the database context. /// public ElsaDbContextOptions? DbContextOptions { get; set; } /// /// Gets or sets the callback used to configure the . /// protected virtual Action DbContextOptionsBuilder { get; set; } = (_, _) => { }; public void ConfigureServices(IServiceCollection services) { Action setup = (sp, opts) => { opts.ConfigureWarnings(w => w.Ignore(RelationalEventId.PendingModelChangesWarning)); // Configure the database provider var migrationsAssembly = GetMigrationsAssembly(); ConfigureProvider(opts, migrationsAssembly, ConnectionString, DbContextOptions); // Allow derived classes to further configure DbContextOptionsBuilder(sp, opts); }; if (UseContextPooling) services.AddPooledDbContextFactory(setup); else services.AddDbContextFactory(setup, DbContextFactoryLifetime); services.Decorate, TenantAwareDbContextFactory>(); services.Configure(options => { options.RunMigrations[typeof(TDbContext)] = RunMigrations; }); services.AddStartupTask>(); OnConfiguring(services); } /// /// Gets the assembly containing migrations for this provider. /// By default, returns the assembly of the concrete feature type. /// protected virtual Assembly GetMigrationsAssembly() => GetType().Assembly; /// /// Configures the database provider for the specified . /// /// The options builder to configure. /// The assembly containing migrations. /// The connection string to use. /// Additional options to configure the database context. protected abstract void ConfigureProvider( DbContextOptionsBuilder builder, Assembly migrationsAssembly, string connectionString, ElsaDbContextOptions? options); protected virtual void OnConfiguring(IServiceCollection services) { } /// /// Adds a store to the service collection. /// /// The type of the entity. /// The type of the store. protected void AddStore(IServiceCollection services) where TEntity : class, new() where TStore : class { services .AddScoped>() .AddScoped() ; } /// /// Adds an entity store to the service collection. /// /// The type of the entity. /// The type of the store. protected void AddEntityStore(IServiceCollection services) where TEntity : Entity, new() where TStore : class { services .AddScoped>() .AddScoped() ; } }