Skip to content

Commit

Permalink
Merge pull request #6359 from elsa-workflows/bug/6355
Browse files Browse the repository at this point in the history
Fix Oracle EF Core Migrations
  • Loading branch information
sfmskywalker authored Feb 5, 2025
2 parents 2bac946 + 73ab3c9 commit bce31b6
Show file tree
Hide file tree
Showing 57 changed files with 403 additions and 301 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,5 @@ unlist.sh

# build artifacts
/artifacts

/docker/data/
8 changes: 7 additions & 1 deletion Elsa.sln
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docker", "docker", "{986E54
docker\ElsaServer.Dockerfile = docker\ElsaServer.Dockerfile
docker\ElsaServerAndStudio.Dockerfile = docker\ElsaServerAndStudio.Dockerfile
docker\ElsaStudio.Dockerfile = docker\ElsaStudio.Dockerfile
docker\init-db.sh = docker\init-db.sh
docker\otel-collector-config.yaml = docker\otel-collector-config.yaml
docker\docker-compose-kafka.yml = docker\docker-compose-kafka.yml
docker\init-db-postgres.sh = docker\init-db-postgres.sh
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Elasticsearch", "src\modules\Elsa.Elasticsearch\Elsa.Elasticsearch.csproj", "{3246883E-2FA7-4B4A-BDC5-99039A2869BC}"
Expand Down Expand Up @@ -387,6 +387,11 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Agents.Persistence.Ent
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Kafka", "src\modules\Elsa.Kafka\Elsa.Kafka.csproj", "{BF934627-F531-44FB-BEC2-ECA801FF31E7}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "oracle-setup", "oracle-setup", "{66E2E2CF-967F-4564-89E8-F46FA973C99B}"
ProjectSection(SolutionItems) = preProject
docker\oracle-setup\setup.sql = docker\oracle-setup\setup.sql
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -968,6 +973,7 @@ Global
{2B939AC9-03A4-479E-AA0D-CB58F4A7F480} = {50470834-4CD8-479A-8B58-0A1869BA5D37}
{2CDF3E1C-267D-4198-B1C7-7E1F548FC120} = {5BA4A8FA-F7F4-45B3-AEC8-8886D35AAC79}
{BF934627-F531-44FB-BEC2-ECA801FF31E7} = {DD089B8B-DA73-492A-9010-F772D1C178DA}
{66E2E2CF-967F-4564-89E8-F46FA973C99B} = {986E5482-0482-448C-B9E4-EC67A9474B85}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {D4B5CEAA-7D70-4FCB-A68E-B03FBE5E0E5E}
Expand Down
14 changes: 13 additions & 1 deletion docker/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,18 @@
- "3306:3306"
volumes:
- mysql_data2:/var/lib/mysql

oracle:
image: container-registry.oracle.com/database/free:latest
container_name: oracle-db
environment:
ORACLE_PWD: elsa
ports:
- "1521:1521"
- "5500:5500"
volumes:
- ./data/oracle-data:/opt/oracle/oradata
- ./setup/oracle-setup:/opt/oracle/scripts/setup

mongodb:
image: mongo:latest
Expand Down Expand Up @@ -84,7 +96,6 @@
- ASPNETCORE_URLS=http://+:80
- Logging__LogLevel__Default=Information


elsa-server:
build:
context: ../.
Expand Down Expand Up @@ -116,6 +127,7 @@

volumes:
postgres-data:
oracle-data-free1:
mysql_data2:
cockroachdb-data:
mongodb_data:
File renamed without changes.
3 changes: 3 additions & 0 deletions docker/setup/oracle-setup/setup.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
alter session set "_ORACLE_SCRIPT"=true;
CREATE USER ELSA IDENTIFIED BY elsa;
GRANT ALL PRIVILEGES TO ELSA;
1 change: 1 addition & 0 deletions src/apps/Elsa.Server.Web/Elsa.Server.Web.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
<ProjectReference Include="..\..\modules\Elsa.Caching.Distributed.MassTransit\Elsa.Caching.Distributed.MassTransit.csproj" />
<ProjectReference Include="..\..\modules\Elsa.Caching.Distributed.ProtoActor\Elsa.Caching.Distributed.ProtoActor.csproj" />
<ProjectReference Include="..\..\modules\Elsa.EntityFrameworkCore.MySql\Elsa.EntityFrameworkCore.MySql.csproj" Condition=" '$(TargetFramework)' != 'net9.0' " />
<ProjectReference Include="..\..\modules\Elsa.EntityFrameworkCore.Oracle\Elsa.EntityFrameworkCore.Oracle.csproj" />
<ProjectReference Include="..\..\modules\Elsa.EntityFrameworkCore.PostgreSql\Elsa.EntityFrameworkCore.PostgreSql.csproj"/>
<ProjectReference Include="..\..\modules\Elsa.Kafka\Elsa.Kafka.csproj" />
<ProjectReference Include="..\..\modules\Elsa.MassTransit.AzureServiceBus\Elsa.MassTransit.AzureServiceBus.csproj"/>
Expand Down
1 change: 1 addition & 0 deletions src/apps/Elsa.Server.Web/Enums/SqlDatabaseProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@ public enum SqlDatabaseProvider
Sqlite,
MySql,
PostgreSql,
Oracle,
CockroachDb
}
15 changes: 13 additions & 2 deletions src/apps/Elsa.Server.Web/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using Elsa.Dapper.Extensions;
using Elsa.Dapper.Services;
using Elsa.DropIns.Extensions;
using Elsa.EntityFrameworkCore;
using Elsa.EntityFrameworkCore.Extensions;
using Elsa.EntityFrameworkCore.Modules.Alterations;
using Elsa.EntityFrameworkCore.Modules.Identity;
Expand Down Expand Up @@ -99,6 +100,7 @@
var sqliteConnectionString = configuration.GetConnectionString("Sqlite")!;
var sqlServerConnectionString = configuration.GetConnectionString("SqlServer")!;
var postgresConnectionString = configuration.GetConnectionString("PostgreSql")!;
var oracleConnectionString = configuration.GetConnectionString("Oracle")!;
var mySqlConnectionString = configuration.GetConnectionString("MySql")!;
var cockroachDbConnectionString = configuration.GetConnectionString("CockroachDb")!;
var mongoDbConnectionString = configuration.GetConnectionString("MongoDb")!;
Expand Down Expand Up @@ -195,6 +197,8 @@
#endif
else if (sqlDatabaseProvider == SqlDatabaseProvider.CockroachDb)
ef.UsePostgreSql(cockroachDbConnectionString!);
else if (sqlDatabaseProvider == SqlDatabaseProvider.Oracle)
ef.UseOracle(oracleConnectionString, new ElsaDbContextOptions{ SchemaName = "ELSA"});
else
ef.UseSqlite(sp => sp.GetSqliteConnectionString());

Expand Down Expand Up @@ -231,6 +235,8 @@
#endif
else if (sqlDatabaseProvider == SqlDatabaseProvider.CockroachDb)
ef.UsePostgreSql(cockroachDbConnectionString!);
else if (sqlDatabaseProvider == SqlDatabaseProvider.Oracle)
ef.UseOracle(oracleConnectionString, new ElsaDbContextOptions{ SchemaName = "ELSA"});
else
ef.UseSqlite(sp => sp.GetSqliteConnectionString());

Expand Down Expand Up @@ -276,7 +282,9 @@
ef.UseMySql(mySqlConnectionString);
#endif
else if (sqlDatabaseProvider == SqlDatabaseProvider.CockroachDb)
ef.UsePostgreSql(cockroachDbConnectionString!);
ef.UsePostgreSql(cockroachDbConnectionString);
else if (sqlDatabaseProvider == SqlDatabaseProvider.Oracle)
ef.UseOracle(oracleConnectionString, new ElsaDbContextOptions{ SchemaName = "ELSA"});
else
ef.UseSqlite(sp => sp.GetSqliteConnectionString());

Expand Down Expand Up @@ -411,7 +419,9 @@
ef.UseMySql(mySqlConnectionString);
#endif
else if (sqlDatabaseProvider == SqlDatabaseProvider.CockroachDb)
ef.UsePostgreSql(cockroachDbConnectionString!);
ef.UsePostgreSql(cockroachDbConnectionString);
else if (sqlDatabaseProvider == SqlDatabaseProvider.Oracle)
ef.UseOracle(oracleConnectionString, new ElsaDbContextOptions{ SchemaName = "ELSA"});
else
ef.UseSqlite(sp => sp.GetSqliteConnectionString());

Expand Down Expand Up @@ -614,6 +624,7 @@
if (sqlDatabaseProvider == SqlDatabaseProvider.Sqlite) ef.UseSqlite(sqliteConnectionString);
if (sqlDatabaseProvider == SqlDatabaseProvider.SqlServer) ef.UseSqlServer(sqlServerConnectionString);
if (sqlDatabaseProvider == SqlDatabaseProvider.PostgreSql) ef.UsePostgreSql(postgresConnectionString);
if (sqlDatabaseProvider == SqlDatabaseProvider.Oracle) ef.UseOracle(oracleConnectionString, new ElsaDbContextOptions{ SchemaName = "ELSA"});
#if !NET9_0
if (sqlDatabaseProvider == SqlDatabaseProvider.MySql)
ef.UseMySql(mySqlConnectionString);
Expand Down
1 change: 1 addition & 0 deletions src/apps/Elsa.Server.Web/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"Sqlite": "Data Source=App_Data/elsa.sqlite.db;Cache=Shared;",
"MySql": "Server=localhost;Database=elsa;Uid=admin;Pwd=password;",
"PostgreSql": "Server=localhost;Username=elsa;Database=elsa;Port=5432;Password=elsa;SSLMode=Prefer;MaxPoolSize=2000;Timeout=60",
"Oracle": "Data Source=(DESCRIPTION = (ADDRESS_LIST = (FAILOVER =ON) (LOAD_BALANCE = OFF) (ADDRESS = (PROTOCOL =TCP)(HOST=localhost)(PORT=1521))) (CONNECT_DATA = (SID= FREE) ));User Id=ELSA;Password=elsa;",
"CockroachDb": "Host=localhost;Port=26257;Database=elsa;SslMode=Disable;Username=root;IncludeErrorDetail=true",
"MongoDb": "mongodb://localhost:27017/elsa-workflows",
"AzureServiceBus": "",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,5 @@ public override void Apply()
AddEntityStore<ApiKeyDefinition, EFCoreApiKeyStore>();
AddEntityStore<ServiceDefinition, EFCoreServiceStore>();
AddEntityStore<AgentDefinition, EFCoreAgentStore>();
Services.AddScoped<IEntityModelCreatingHandler, SetupForOracle>();
}
}

This file was deleted.

37 changes: 37 additions & 0 deletions src/modules/Elsa.Common/Extensions/ServiceCollectionExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
namespace Elsa.Extensions;

using Microsoft.Extensions.DependencyInjection;
using System;
using System.Linq;

public static class ServiceCollectionExtensions
{
/// <summary>
/// Adds the service with a specific implementation type only if the combination
/// of service and implementation does not already exist in the service collection.
/// </summary>
public static IServiceCollection TryAddScopedImplementation<TService, TImplementation>(
this IServiceCollection services)
where TService : class
where TImplementation : class, TService
{
if (!services.Any(sd => sd.ServiceType == typeof(TService) && sd.ImplementationType == typeof(TImplementation)))
services.AddScoped<TService, TImplementation>();

return services;
}

/// <summary>
/// Adds the service with a specific implementation factory only if the combination
/// of service and implementation already doesn't exist.
/// </summary>
public static IServiceCollection TryAddScopedImplementation<TService>(
this IServiceCollection services, Func<IServiceProvider, TService> implementationFactory)
where TService : class
{
if (services.All(sd => sd.ServiceType != typeof(TService)))
services.AddScoped(implementationFactory);

return services;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,5 @@ public override void Apply()
{
Services.AddScoped<IEntitySavingHandler, ApplyTenantId>();
Services.AddScoped<IEntityModelCreatingHandler, SetTenantIdFilter>();
Services.AddScoped<IEntityModelCreatingHandler, SetupForSqlite>();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,14 @@ namespace Elsa.EntityFrameworkCore;
/// <summary>
/// Class That enable Schema change for Migration
/// </summary>
public class DbSchemaAwareMigrationAssembly : MigrationsAssembly
public class DbSchemaAwareMigrationAssembly(
ICurrentDbContext currentContext,
IDbContextOptions options,
IMigrationsIdGenerator idGenerator,
IDiagnosticsLogger<DbLoggerCategory.Migrations> logger)
: MigrationsAssembly(currentContext, options, idGenerator, logger)
{
private readonly DbContext _context;

public DbSchemaAwareMigrationAssembly(ICurrentDbContext currentContext,
IDbContextOptions options, IMigrationsIdGenerator idGenerator,
IDiagnosticsLogger<DbLoggerCategory.Migrations> logger)
: base(currentContext, options, idGenerator, logger)
{
_context = currentContext.Context;
}
private readonly DbContext _context = currentContext.Context;

public override Migration CreateMigration(TypeInfo migrationClass, string activeProvider)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
<PackageReference Include="Microsoft.EntityFrameworkCore" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" PrivateAssets="all" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" />
<PackageReference Include="Open.Linq.AsyncExtensions" />
<PackageReference Include="System.CommandLine" />
Expand Down
47 changes: 28 additions & 19 deletions src/modules/Elsa.EntityFrameworkCore.Common/ElsaDbContextBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using Elsa.Common.Multitenancy;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using Microsoft.EntityFrameworkCore.Diagnostics;
using Microsoft.Extensions.DependencyInjection;

namespace Elsa.EntityFrameworkCore;
Expand All @@ -16,8 +17,9 @@ public abstract class ElsaDbContextBase : DbContext, IElsaDbContextSchema
EntityState.Added,
EntityState.Modified,
};

protected readonly IServiceProvider ServiceProvider;

protected IServiceProvider ServiceProvider { get; }
private readonly ElsaDbContextOptions? _elsaDbContextOptions;
public string? TenantId { get; set; }

/// <summary>
Expand All @@ -39,45 +41,52 @@ public abstract class ElsaDbContextBase : DbContext, IElsaDbContextSchema
protected ElsaDbContextBase(DbContextOptions options, IServiceProvider serviceProvider) : base(options)
{
ServiceProvider = serviceProvider;
var elsaDbContextOptions = options.FindExtension<ElsaDbContextOptionsExtension>()?.Options;

// ReSharper disable once VirtualMemberCallInConstructor
Schema = !string.IsNullOrWhiteSpace(elsaDbContextOptions?.SchemaName) ? elsaDbContextOptions.SchemaName : ElsaSchema;
_elsaDbContextOptions = options.FindExtension<ElsaDbContextOptionsExtension>()?.Options;

// ReSharper disable once VirtualMemberCallInConstructor
Schema = !string.IsNullOrWhiteSpace(_elsaDbContextOptions?.SchemaName) ? _elsaDbContextOptions.SchemaName : ElsaSchema;

var tenantAccessor = serviceProvider.GetService<ITenantAccessor>();
var tenantId = tenantAccessor?.Tenant?.Id;
if(!string.IsNullOrWhiteSpace(tenantId))

if (!string.IsNullOrWhiteSpace(tenantId))
TenantId = tenantId;
}

/// <inheritdoc/>
public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
{
await OnBeforeSavingAsync(cancellationToken);
return await base.SaveChangesAsync(cancellationToken);
}

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.EnableSensitiveDataLogging();
#if NET9_0_OR_GREATER
optionsBuilder.ConfigureWarnings(w => w.Ignore(RelationalEventId.PendingModelChangesWarning));
#endif
}

/// <inheritdoc />
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
if (!string.IsNullOrWhiteSpace(Schema))
{
if (!Database.IsSqlite())
modelBuilder.HasDefaultSchema(Schema);
}
if (!string.IsNullOrWhiteSpace(Schema))
modelBuilder.HasDefaultSchema(Schema);

var additionalConfigurations = _elsaDbContextOptions?.GetModelConfigurations(this);

additionalConfigurations?.Invoke(modelBuilder);

var entityTypeHandlers = ServiceProvider.GetServices<IEntityModelCreatingHandler>().ToList();

foreach (var entityType in modelBuilder.Model.GetEntityTypes())
foreach (var entityType in modelBuilder.Model.GetEntityTypes().ToList())
{
foreach (var handler in entityTypeHandlers)
{
foreach (var handler in entityTypeHandlers)
handler.Handle(this, modelBuilder, entityType);
}
}
}

private async Task OnBeforeSavingAsync(CancellationToken cancellationToken)
{
var handlers = ServiceProvider.GetServices<IEntitySavingHandler>().ToList();
Expand Down
Loading

0 comments on commit bce31b6

Please sign in to comment.