* Refactor: Update namespaces and add TenantExtensions Updated namespaces throughout the project to improve clarity and consistency by moving from 'Common' to appropriate modules. Added TenantExtensions class to simplify fetching connection strings for tenants. * Implement multitenant DB connection strings Redesign tenant-specific classes to support multitenancy more effectively. Introduce `MultitenantBackgroundService` and `MultitenantHostedService` for handling tasks per tenant. * Refactor constructors and remove redundant code Simplified the constructor parameters for `MultitenantBackgroundService` and `List` class. Removed the unused parameter in `MultitenantBackgroundService` and redundant folder inclusion in the project file. Updated the method calls to use direct parameters in `List` class. * Remove unused import in ActivityDescriptors Endpoint The Elsa.Common.Multitenancy import was removed as it is unused in the List/Endpoint.cs file. Removing unused imports helps to improve code readability and maintainability. This change does not affect functionality.
96 lines
3.3 KiB
C#
96 lines
3.3 KiB
C#
using Elsa.Common.Entities;
|
|
using Elsa.Common.Multitenancy;
|
|
using Elsa.EntityFrameworkCore.Contracts;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using Microsoft.EntityFrameworkCore.ChangeTracking;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
|
|
namespace Elsa.EntityFrameworkCore;
|
|
|
|
/// <summary>
|
|
/// An optional base class to implement with some opinions on certain converters to install for certain DB providers.
|
|
/// </summary>
|
|
public abstract class ElsaDbContextBase : DbContext, IElsaDbContextSchema
|
|
{
|
|
private static readonly ISet<EntityState> ModifiedEntityStates = new HashSet<EntityState>
|
|
{
|
|
EntityState.Added,
|
|
EntityState.Modified,
|
|
};
|
|
|
|
protected readonly IServiceProvider ServiceProvider;
|
|
public string? TenantId { get; set; }
|
|
|
|
/// <summary>
|
|
/// The default schema used by Elsa.
|
|
/// </summary>
|
|
public static string ElsaSchema { get; set; } = "Elsa";
|
|
|
|
/// <inheritdoc/>
|
|
public string Schema { get; }
|
|
|
|
/// <summary>
|
|
/// The table used to store the migrations history.
|
|
/// </summary>
|
|
public static string MigrationsHistoryTable { get; set; } = "__EFMigrationsHistory";
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="ElsaDbContextBase"/> class.
|
|
/// </summary>
|
|
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;
|
|
|
|
var tenantAccessor = serviceProvider.GetService<ITenantAccessor>();
|
|
TenantId = tenantAccessor?.CurrentTenant?.Id;
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
|
|
{
|
|
await OnBeforeSavingAsync(cancellationToken);
|
|
return await base.SaveChangesAsync(cancellationToken);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
|
{
|
|
if (!string.IsNullOrWhiteSpace(Schema))
|
|
{
|
|
if (!Database.IsSqlite())
|
|
modelBuilder.HasDefaultSchema(Schema);
|
|
}
|
|
|
|
var entityTypeHandlers = ServiceProvider.GetServices<IEntityModelCreatingHandler>().ToList();
|
|
|
|
foreach (var entityType in modelBuilder.Model.GetEntityTypes())
|
|
{
|
|
foreach (var handler in entityTypeHandlers)
|
|
{
|
|
handler.Handle(this, modelBuilder, entityType);
|
|
}
|
|
}
|
|
}
|
|
|
|
private async Task OnBeforeSavingAsync(CancellationToken cancellationToken)
|
|
{
|
|
var handlers = ServiceProvider.GetServices<IEntitySavingHandler>().ToList();
|
|
foreach (var entry in ChangeTracker.Entries().Where(IsModifiedEntity))
|
|
{
|
|
foreach (var handler in handlers)
|
|
await handler.HandleAsync(this, entry, cancellationToken);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determine if an entity was modified.
|
|
/// </summary>
|
|
private bool IsModifiedEntity(EntityEntry entityEntry)
|
|
{
|
|
return ModifiedEntityStates.Contains(entityEntry.State) && entityEntry.Entity is Entity;
|
|
}
|
|
} |