< Summary

Information
Class: Elsa.Persistence.EFCore.ElsaDbContextBase
Assembly: Elsa.Persistence.EFCore.Common
File(s): /home/runner/work/elsa-core/elsa-core/src/modules/Elsa.Persistence.EFCore.Common/ElsaDbContextBase.cs
Line coverage
100%
Covered lines: 39
Uncovered lines: 0
Coverable lines: 39
Total lines: 99
Line coverage: 100%
Branch coverage
73%
Covered branches: 19
Total branches: 26
Branch coverage: 73%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.cctor()100%11100%
get_ServiceProvider()100%11100%
get_TenantId()100%11100%
get_ElsaSchema()100%11100%
get_Schema()100%11100%
get_MigrationsHistoryTable()100%11100%
.ctor(...)60%1010100%
SaveChangesAsync()100%11100%
OnModelCreating(...)80%1010100%
OnBeforeSavingAsync()100%44100%
IsModifiedEntity(...)50%22100%

File(s)

/home/runner/work/elsa-core/elsa-core/src/modules/Elsa.Persistence.EFCore.Common/ElsaDbContextBase.cs

#LineLine coverage
 1using Elsa.Common.Entities;
 2using Elsa.Common.Multitenancy;
 3using Elsa.Extensions;
 4using Microsoft.EntityFrameworkCore;
 5using Microsoft.EntityFrameworkCore.ChangeTracking;
 6using Microsoft.Extensions.DependencyInjection;
 7
 8namespace Elsa.Persistence.EFCore;
 9
 10/// <summary>
 11/// An optional base class to implement with some opinions on certain converters to install for certain DB providers.
 12/// </summary>
 13public abstract class ElsaDbContextBase : DbContext, IElsaDbContextSchema
 14{
 115    private static readonly ISet<EntityState> ModifiedEntityStates = new HashSet<EntityState>
 116    {
 117        EntityState.Added,
 118        EntityState.Modified,
 119    };
 20
 92521    protected IServiceProvider ServiceProvider { get; }
 22    private readonly ElsaDbContextOptions? _elsaDbContextOptions;
 26247223    public string? TenantId { get; set; }
 24
 25    /// <summary>
 26    /// The default schema used by Elsa.
 27    /// </summary>
 4990328    public static string ElsaSchema { get; set; } = "Elsa";
 29
 30    /// <inheritdoc/>
 16331    public string Schema { get; }
 32
 33    /// <summary>
 34    /// The table used to store the migrations history.
 35    /// </summary>
 305236    public static string MigrationsHistoryTable { get; set; } = "__EFMigrationsHistory";
 37
 38    /// <summary>
 39    /// Initializes a new instance of the <see cref="ElsaDbContextBase"/> class.
 40    /// </summary>
 4685141    protected ElsaDbContextBase(DbContextOptions options, IServiceProvider serviceProvider) : base(options)
 42    {
 4685143        ServiceProvider = serviceProvider;
 4685144        _elsaDbContextOptions = options.FindExtension<ElsaDbContextOptionsExtension>()?.Options;
 45
 46        // ReSharper disable once VirtualMemberCallInConstructor
 4685147        Schema = !string.IsNullOrWhiteSpace(_elsaDbContextOptions?.SchemaName) ? _elsaDbContextOptions.SchemaName : Elsa
 48
 4685149        var tenantAccessor = serviceProvider.GetService<ITenantAccessor>();
 4685150        var tenantId = (tenantAccessor?.TenantId).NormalizeTenantId();
 4685151        TenantId ??= tenantId;
 4685152    }
 53
 54    /// <inheritdoc/>
 55    public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
 56    {
 92157        await OnBeforeSavingAsync(cancellationToken);
 92158        return await base.SaveChangesAsync(cancellationToken);
 92059    }
 60
 61    /// <inheritdoc />
 62    protected override void OnModelCreating(ModelBuilder modelBuilder)
 63    {
 464        if (!string.IsNullOrWhiteSpace(Schema))
 465            modelBuilder.HasDefaultSchema(Schema);
 66
 467        var additionalConfigurations = _elsaDbContextOptions?.GetModelConfigurations(this);
 68
 469        additionalConfigurations?.Invoke(modelBuilder);
 70
 471        using var scope = ServiceProvider.CreateScope();
 472        var entityTypeHandlers = scope.ServiceProvider.GetServices<IEntityModelCreatingHandler>().ToList();
 73
 6674        foreach (var entityType in modelBuilder.Model.GetEntityTypes().ToList())
 75        {
 46476            foreach (var handler in entityTypeHandlers)
 20377                handler.Handle(this, modelBuilder, entityType);
 78        }
 479    }
 80
 81    private async Task OnBeforeSavingAsync(CancellationToken cancellationToken)
 82    {
 92183        using var scope = ServiceProvider.CreateScope();
 92184        var handlers = scope.ServiceProvider.GetServices<IEntitySavingHandler>().ToList();
 1347885        foreach (var entry in ChangeTracker.Entries().Where(IsModifiedEntity))
 86        {
 8145287            foreach (var handler in handlers)
 3490888                await handler.HandleAsync(this, entry, cancellationToken);
 581889        }
 92190    }
 91
 92    /// <summary>
 93    /// Determine if an entity was modified.
 94    /// </summary>
 95    private bool IsModifiedEntity(EntityEntry entityEntry)
 96    {
 581897        return ModifiedEntityStates.Contains(entityEntry.State) && entityEntry.Entity is Entity;
 98    }
 99}