using Elsa.EntityFrameworkCore.Common.Contracts; using Elsa.EntityFrameworkCore.Extensions; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; namespace Elsa.EntityFrameworkCore.Common; /// /// An optional base class to implement with some opinions on certain converters to install for certain DB providers. /// public abstract class ElsaDbContextBase : DbContext, IElsaDbContextSchema { /// /// The default schema used by Elsa. /// public static string ElsaSchema { get; set; } = "Elsa"; private string _schema; /// public string Schema => _schema; /// /// The table used to store the migrations history. /// public static string MigrationsHistoryTable { get; set; } = "__EFMigrationsHistory"; /// /// Initializes a new instance of the class. /// protected ElsaDbContextBase(DbContextOptions options) : base(options) { var elsaDbContextOptions = options.FindExtension()?.Options; // ReSharper disable once VirtualMemberCallInConstructor _schema = !string.IsNullOrWhiteSpace(elsaDbContextOptions?.SchemaName) ? elsaDbContextOptions.SchemaName : ElsaSchema; } /// /// The schema used by Elsa. /// // protected virtual string Schema { get; set; } /// protected override void OnModelCreating(ModelBuilder modelBuilder) { if (!string.IsNullOrWhiteSpace(Schema)) { if (!Database.IsSqlite()) modelBuilder.HasDefaultSchema(Schema); } ApplyEntityConfigurations(modelBuilder); if(Database.IsSqlite()) SetupForSqlite(modelBuilder); if(Database.IsOracle()) SetupForOracle(modelBuilder); } /// /// Override this method to apply entity configurations. /// protected virtual void ApplyEntityConfigurations(ModelBuilder modelBuilder) { } /// /// Override this method to apply entity configurations. /// protected virtual void Configure(ModelBuilder modelBuilder) { } /// /// Override this method to apply entity configurations for the SQLite provider. /// protected virtual void SetupForSqlite(ModelBuilder modelBuilder) { // SQLite does not have proper support for DateTimeOffset via Entity Framework Core, see the limitations // here: https://docs.microsoft.com/en-us/ef/core/providers/sqlite/limitations#query-limitations foreach (var entityType in modelBuilder.Model.GetEntityTypes()) { var properties = entityType.ClrType.GetProperties().Where(p => p.PropertyType == typeof(DateTimeOffset) || p.PropertyType == typeof(DateTimeOffset?)); foreach (var property in properties) { modelBuilder .Entity(entityType.Name) .Property(property.Name) .HasConversion(new DateTimeOffsetToStringConverter()); } } } /// /// Override this method to apply entity configurations for the Oracle provider. /// protected virtual void SetupForOracle(ModelBuilder modelBuilder) { } }