From 32bf3930262e26665b56e20ea1238769733ccef2 Mon Sep 17 00:00:00 2001 From: Sipke Schoorstra Date: Wed, 27 Jan 2021 10:32:15 +0100 Subject: [PATCH] Update EF Core DB Context types to accept non-generic DbOptions --- .../DesignTimeDbContextFactoryBase.cs | 29 ------ .../DbContexts/MySqlContext.cs | 2 +- .../DbContexts/MySqlContextFactory.cs | 4 +- .../DbContexts/PostgreSqlContext.cs | 2 +- .../DbContexts/SqlServerContext.cs | 2 +- .../DbContexts/SqliteContext.cs | 2 +- .../EFCoreServiceCollectionExtensions.cs | 7 +- .../HostedServices/RunMigrations.cs | 28 ++++++ src/samples/README.md | 4 +- .../20191021193326_InitialCreate.Designer.cs | 95 ------------------- .../20191021193326_InitialCreate.cs | 68 ------------- .../Migrations/ElsaContextModelSnapshot.cs | 91 ------------------ src/samples/Sample14/Program.cs | 8 +- 13 files changed, 47 insertions(+), 295 deletions(-) delete mode 100644 src/persistence/Elsa.Persistence.EntityFrameworkCore/DbContexts/DesignTimeDbContextFactoryBase.cs create mode 100644 src/persistence/Elsa.Persistence.EntityFrameworkCore/HostedServices/RunMigrations.cs delete mode 100644 src/samples/Sample14/Migrations/20191021193326_InitialCreate.Designer.cs delete mode 100644 src/samples/Sample14/Migrations/20191021193326_InitialCreate.cs delete mode 100644 src/samples/Sample14/Migrations/ElsaContextModelSnapshot.cs diff --git a/src/persistence/Elsa.Persistence.EntityFrameworkCore/DbContexts/DesignTimeDbContextFactoryBase.cs b/src/persistence/Elsa.Persistence.EntityFrameworkCore/DbContexts/DesignTimeDbContextFactoryBase.cs deleted file mode 100644 index 16f9e7629..000000000 --- a/src/persistence/Elsa.Persistence.EntityFrameworkCore/DbContexts/DesignTimeDbContextFactoryBase.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Design; - -namespace Elsa.Persistence.EntityFrameworkCore.DbContexts -{ - public abstract class DesignTimeDbContextFactoryBase : IDesignTimeDbContextFactory where TDbContext : DbContext - { - public TDbContext CreateDbContext(string[] args) - { - var optionsBuilder = new DbContextOptionsBuilder(); - var migrationAssembly = typeof(TDbContext).Assembly.FullName; - var connectionString = Environment.GetEnvironmentVariable("EF_CONNECTIONSTRING"); - - if(connectionString == null) - { - var providerName = typeof(TDbContext).Name.Replace("Context", ""); - throw new InvalidOperationException($"Set the EF_CONNECTIONSTRING environment variable to a valid {providerName} connection string."); - } - - optionsBuilder.UseSqlite( - connectionString, - x => x.MigrationsAssembly(migrationAssembly) - ); - - return (TDbContext)Activator.CreateInstance(typeof(TDbContext), optionsBuilder.Options); - } - } -} \ No newline at end of file diff --git a/src/persistence/Elsa.Persistence.EntityFrameworkCore/DbContexts/MySqlContext.cs b/src/persistence/Elsa.Persistence.EntityFrameworkCore/DbContexts/MySqlContext.cs index 51c9253b5..d651aadeb 100644 --- a/src/persistence/Elsa.Persistence.EntityFrameworkCore/DbContexts/MySqlContext.cs +++ b/src/persistence/Elsa.Persistence.EntityFrameworkCore/DbContexts/MySqlContext.cs @@ -4,7 +4,7 @@ namespace Elsa.Persistence.EntityFrameworkCore.DbContexts { public class MySqlContext : ElsaContext { - public MySqlContext(DbContextOptions options) : base(options) + public MySqlContext(DbContextOptions options) : base(options) { } } diff --git a/src/persistence/Elsa.Persistence.EntityFrameworkCore/DbContexts/MySqlContextFactory.cs b/src/persistence/Elsa.Persistence.EntityFrameworkCore/DbContexts/MySqlContextFactory.cs index 22af097f7..530fc5d05 100644 --- a/src/persistence/Elsa.Persistence.EntityFrameworkCore/DbContexts/MySqlContextFactory.cs +++ b/src/persistence/Elsa.Persistence.EntityFrameworkCore/DbContexts/MySqlContextFactory.cs @@ -12,9 +12,9 @@ namespace Elsa.Persistence.EntityFrameworkCore.DbContexts var migrationAssembly = typeof(MySqlContext).Assembly.FullName; var connectionString = Environment.GetEnvironmentVariable("EF_CONNECTIONSTRING"); - if(connectionString == null) + if (connectionString == null) throw new InvalidOperationException("Set the EF_CONNECTIONSTRING environment variable to a valid MySQL connection string. E.g. SET EF_CONNECTIONSTRING=Server=localhost;Database=Elsa;User=sa;Password=Secret_password123!;"); - + optionsBuilder.UseMySql( new MySqlServerVersion(ServerVersion.AutoDetect(connectionString)), x => x.MigrationsAssembly(migrationAssembly) diff --git a/src/persistence/Elsa.Persistence.EntityFrameworkCore/DbContexts/PostgreSqlContext.cs b/src/persistence/Elsa.Persistence.EntityFrameworkCore/DbContexts/PostgreSqlContext.cs index 3ce1366e3..7774d8ac9 100644 --- a/src/persistence/Elsa.Persistence.EntityFrameworkCore/DbContexts/PostgreSqlContext.cs +++ b/src/persistence/Elsa.Persistence.EntityFrameworkCore/DbContexts/PostgreSqlContext.cs @@ -4,7 +4,7 @@ namespace Elsa.Persistence.EntityFrameworkCore.DbContexts { public class PostgreSqlContext : ElsaContext { - public PostgreSqlContext(DbContextOptions options) : base(options) + public PostgreSqlContext(DbContextOptions options) : base(options) { } } diff --git a/src/persistence/Elsa.Persistence.EntityFrameworkCore/DbContexts/SqlServerContext.cs b/src/persistence/Elsa.Persistence.EntityFrameworkCore/DbContexts/SqlServerContext.cs index 51de1ba41..36cffcae8 100644 --- a/src/persistence/Elsa.Persistence.EntityFrameworkCore/DbContexts/SqlServerContext.cs +++ b/src/persistence/Elsa.Persistence.EntityFrameworkCore/DbContexts/SqlServerContext.cs @@ -4,7 +4,7 @@ namespace Elsa.Persistence.EntityFrameworkCore.DbContexts { public class SqlServerContext : ElsaContext { - public SqlServerContext(DbContextOptions options) : base(options) + public SqlServerContext(DbContextOptions options) : base(options) { } } diff --git a/src/persistence/Elsa.Persistence.EntityFrameworkCore/DbContexts/SqliteContext.cs b/src/persistence/Elsa.Persistence.EntityFrameworkCore/DbContexts/SqliteContext.cs index 2dea096c3..121a008e5 100644 --- a/src/persistence/Elsa.Persistence.EntityFrameworkCore/DbContexts/SqliteContext.cs +++ b/src/persistence/Elsa.Persistence.EntityFrameworkCore/DbContexts/SqliteContext.cs @@ -4,7 +4,7 @@ namespace Elsa.Persistence.EntityFrameworkCore.DbContexts { public class SqliteContext : ElsaContext { - public SqliteContext(DbContextOptions options) : base(options) + public SqliteContext(DbContextOptions options) : base(options) { } } diff --git a/src/persistence/Elsa.Persistence.EntityFrameworkCore/Extensions/EFCoreServiceCollectionExtensions.cs b/src/persistence/Elsa.Persistence.EntityFrameworkCore/Extensions/EFCoreServiceCollectionExtensions.cs index 79b0c0867..48beb210d 100644 --- a/src/persistence/Elsa.Persistence.EntityFrameworkCore/Extensions/EFCoreServiceCollectionExtensions.cs +++ b/src/persistence/Elsa.Persistence.EntityFrameworkCore/Extensions/EFCoreServiceCollectionExtensions.cs @@ -2,6 +2,7 @@ using System; using Elsa.Extensions; using Elsa.Mapping; using Elsa.Persistence.EntityFrameworkCore.DbContexts; +using Elsa.Persistence.EntityFrameworkCore.HostedServices; using Elsa.Persistence.EntityFrameworkCore.Mapping; using Elsa.Persistence.EntityFrameworkCore.Services; using Microsoft.EntityFrameworkCore; @@ -14,7 +15,8 @@ namespace Elsa.Persistence.EntityFrameworkCore.Extensions public static EntityFrameworkCoreElsaBuilder AddEntityFrameworkCoreProvider( this ElsaBuilder configuration, Action configureOptions, - bool usePooling = true) + bool usePooling = true, + bool autoRunMigrations = false) where TElsaContext : ElsaContext { var services = configuration.Services; @@ -26,6 +28,9 @@ namespace Elsa.Persistence.EntityFrameworkCore.Extensions services .AddMapperProfile(ServiceLifetime.Singleton) .AddMapperProfile(ServiceLifetime.Singleton); + + if (autoRunMigrations) + services.AddHostedService(); return new EntityFrameworkCoreElsaBuilder(configuration.Services); } diff --git a/src/persistence/Elsa.Persistence.EntityFrameworkCore/HostedServices/RunMigrations.cs b/src/persistence/Elsa.Persistence.EntityFrameworkCore/HostedServices/RunMigrations.cs new file mode 100644 index 000000000..f4d77694d --- /dev/null +++ b/src/persistence/Elsa.Persistence.EntityFrameworkCore/HostedServices/RunMigrations.cs @@ -0,0 +1,28 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Elsa.Persistence.EntityFrameworkCore.DbContexts; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; + +namespace Elsa.Persistence.EntityFrameworkCore.HostedServices +{ + /// + /// Executes EF Core migrations. + /// + public class RunMigrations : IHostedService + { + private readonly IServiceProvider serviceProvider; + public RunMigrations(IServiceProvider serviceProvider) => this.serviceProvider = serviceProvider; + + public async Task StartAsync(CancellationToken cancellationToken) + { + using var scope = serviceProvider.CreateScope(); + var elsaContext = scope.ServiceProvider.GetRequiredService(); + await elsaContext.Database.MigrateAsync(cancellationToken); + } + + public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask; + } +} \ No newline at end of file diff --git a/src/samples/README.md b/src/samples/README.md index 0602de7f1..5b3213520 100644 --- a/src/samples/README.md +++ b/src/samples/README.md @@ -11,11 +11,11 @@ This list of sample implementations showcase a variety of workflows using ELSA. 7. [Document Approval](Sample07) - Example of a Document Approval workflow. 8. [Create and Handle Orders](Sample08) - Example of a workflow that creates and handles orders. Uses Mass Transit and RabbitMq. 9. [Calculator: Defined in Json](Sample9) - A simple console program that loads & executes a workflow designed with the HTML5 workflow designer. -10. [Hellow World: YesSql](Sample10) - A simple demonstration of using YesSql persistence providers. +10. [Hello World: YesSql](Sample10) - A simple demonstration of using YesSql persistence providers. 11. [Correlation](Sample11) - Demonstrates workflow correlation. 12. [User Task](Sample12) - Demonstrates workflow correlation & user tasks. 13. [Activity Output](Sample13) - A strongly-typed workflows program demonstrating scripting, and branching. -14. [Hellow World: Entity Framework Core](Sample14) - A simple demonstration of using Entity Framework Core persistence providers. +14. [Hello World: Entity Framework Core](Sample14) - A simple demonstration of using Entity Framework Core persistence providers. 15. [Hello World: MongoDb](Sample15) - A simple demonstration of using the MongoDB persistence providers. Docker(optional) 16. [ELSA Dashboard: Web App, MongoDb Persistence](Sample16) - ELSA Dashboard MVC wep application. 17. [Create Person: Console Application](Sample17) - Example of a workflow that creates a Person entity. diff --git a/src/samples/Sample14/Migrations/20191021193326_InitialCreate.Designer.cs b/src/samples/Sample14/Migrations/20191021193326_InitialCreate.Designer.cs deleted file mode 100644 index 960401c4b..000000000 --- a/src/samples/Sample14/Migrations/20191021193326_InitialCreate.Designer.cs +++ /dev/null @@ -1,95 +0,0 @@ -// -using System; -using Elsa.Persistence.EntityFrameworkCore; -using Elsa.Persistence.EntityFrameworkCore.DbContexts; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; - -namespace Sample14.Migrations -{ - [DbContext(typeof(ElsaContext))] - [Migration("20191021193326_InitialCreate")] - partial class InitialCreate - { - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "2.2.6-servicing-10079"); - - modelBuilder.Entity("Elsa.Persistence.EntityFrameworkCore.Documents.WorkflowDefinitionVersionDocument", b => - { - b.Property("Id"); - - b.Property("Activities"); - - b.Property("Connections"); - - b.Property("DefinitionId"); - - b.Property("Description"); - - b.Property("IsDisabled"); - - b.Property("IsLatest"); - - b.Property("IsPublished"); - - b.Property("IsSingleton"); - - b.Property("Name"); - - b.Property("Variables"); - - b.Property("Version"); - - b.HasKey("Id"); - - b.ToTable("WorkflowDefinitionVersions"); - }); - - modelBuilder.Entity("Elsa.Persistence.EntityFrameworkCore.Documents.WorkflowInstanceDocument", b => - { - b.Property("Id"); - - b.Property("AbortedAt"); - - b.Property("Activities"); - - b.Property("BlockingActivities"); - - b.Property("CorrelationId"); - - b.Property("CreatedAt"); - - b.Property("DefinitionId"); - - b.Property("ExecutionLog"); - - b.Property("Fault"); - - b.Property("FaultedAt"); - - b.Property("FinishedAt"); - - b.Property("Input"); - - b.Property("Scopes"); - - b.Property("StartedAt"); - - b.Property("Status") - .IsRequired(); - - b.Property("Version"); - - b.HasKey("Id"); - - b.ToTable("WorkflowInstances"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/src/samples/Sample14/Migrations/20191021193326_InitialCreate.cs b/src/samples/Sample14/Migrations/20191021193326_InitialCreate.cs deleted file mode 100644 index 5f1dd0cb2..000000000 --- a/src/samples/Sample14/Migrations/20191021193326_InitialCreate.cs +++ /dev/null @@ -1,68 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore.Migrations; - -namespace Sample14.Migrations -{ - public partial class InitialCreate : Migration - { - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateTable( - name: "WorkflowDefinitionVersions", - columns: table => new - { - Id = table.Column(nullable: false), - DefinitionId = table.Column(nullable: true), - Version = table.Column(nullable: false), - Name = table.Column(nullable: true), - Description = table.Column(nullable: true), - Activities = table.Column(nullable: true), - Connections = table.Column(nullable: true), - Variables = table.Column(nullable: true), - IsSingleton = table.Column(nullable: false), - IsDisabled = table.Column(nullable: false), - IsPublished = table.Column(nullable: false), - IsLatest = table.Column(nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_WorkflowDefinitionVersions", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "WorkflowInstances", - columns: table => new - { - Id = table.Column(nullable: false), - DefinitionId = table.Column(nullable: true), - Version = table.Column(nullable: false), - Status = table.Column(nullable: false), - CorrelationId = table.Column(nullable: true), - CreatedAt = table.Column(nullable: false), - StartedAt = table.Column(nullable: true), - FinishedAt = table.Column(nullable: true), - FaultedAt = table.Column(nullable: true), - AbortedAt = table.Column(nullable: true), - Activities = table.Column(nullable: true), - Scopes = table.Column(nullable: true), - Input = table.Column(nullable: true), - BlockingActivities = table.Column(nullable: true), - ExecutionLog = table.Column(nullable: true), - Fault = table.Column(nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_WorkflowInstances", x => x.Id); - }); - } - - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "WorkflowDefinitionVersions"); - - migrationBuilder.DropTable( - name: "WorkflowInstances"); - } - } -} diff --git a/src/samples/Sample14/Migrations/ElsaContextModelSnapshot.cs b/src/samples/Sample14/Migrations/ElsaContextModelSnapshot.cs deleted file mode 100644 index 9ef6061f9..000000000 --- a/src/samples/Sample14/Migrations/ElsaContextModelSnapshot.cs +++ /dev/null @@ -1,91 +0,0 @@ -// -using System; -using Elsa.Persistence.EntityFrameworkCore.DbContexts; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; - -namespace Sample14.Migrations -{ - [DbContext(typeof(ElsaContext))] - internal partial class ElsaContextModelSnapshot : ModelSnapshot - { - protected override void BuildModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "2.2.6-servicing-10079"); - - modelBuilder.Entity("Elsa.Persistence.EntityFrameworkCore.Documents.WorkflowDefinitionVersionDocument", b => - { - b.Property("Id"); - - b.Property("Activities"); - - b.Property("Connections"); - - b.Property("DefinitionId"); - - b.Property("Description"); - - b.Property("IsDisabled"); - - b.Property("IsLatest"); - - b.Property("IsPublished"); - - b.Property("IsSingleton"); - - b.Property("Name"); - - b.Property("Variables"); - - b.Property("Version"); - - b.HasKey("Id"); - - b.ToTable("WorkflowDefinitionVersions"); - }); - - modelBuilder.Entity("Elsa.Persistence.EntityFrameworkCore.Documents.WorkflowInstanceDocument", b => - { - b.Property("Id"); - - b.Property("AbortedAt"); - - b.Property("Activities"); - - b.Property("BlockingActivities"); - - b.Property("CorrelationId"); - - b.Property("CreatedAt"); - - b.Property("DefinitionId"); - - b.Property("ExecutionLog"); - - b.Property("Fault"); - - b.Property("FaultedAt"); - - b.Property("FinishedAt"); - - b.Property("Input"); - - b.Property("Scopes"); - - b.Property("StartedAt"); - - b.Property("Status") - .IsRequired(); - - b.Property("Version"); - - b.HasKey("Id"); - - b.ToTable("WorkflowInstances"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/src/samples/Sample14/Program.cs b/src/samples/Sample14/Program.cs index 8ffdb8e9e..a5099b007 100644 --- a/src/samples/Sample14/Program.cs +++ b/src/samples/Sample14/Program.cs @@ -28,7 +28,7 @@ namespace Sample14 await startupRunner.StartupAsync(); // Create a workflow definition. - var registry = services.GetService(); + var registry = services.GetRequiredService(); var workflowDefinition = await registry.GetWorkflowDefinitionAsync(); // Mark this definition as the "latest" version. @@ -70,9 +70,11 @@ namespace Sample14 { return new ServiceCollection() .AddElsa( - x => x.AddEntityFrameworkStores( + x => x.AddEntityFrameworkCoreProvider( options => options - .UseSqlite(@"Data Source=c:\data\elsa.entity-framework-core.db;Cache=Shared"))) + .UseSqlite( + @"Data Source=c:\data\elsa.entity-framework-core.db;Cache=Shared", + db => db.MigrationsAssembly(typeof(SqliteContextFactory).Assembly.GetName().Name)), autoRunMigrations: true)) .AddStartupRunner() .AddConsoleActivities() .AddWorkflow()