< 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
95%
Covered lines: 38
Uncovered lines: 2
Coverable lines: 40
Total lines: 101
Line coverage: 95%
Branch coverage
67%
Covered branches: 19
Total branches: 28
Branch coverage: 67.8%
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(...)58.33%121288.88%
SaveChangesAsync()100%11100%
OnModelCreating(...)80%1010100%
OnBeforeSavingAsync()75%4485.71%
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
 77121    protected IServiceProvider ServiceProvider { get; }
 22    private readonly ElsaDbContextOptions? _elsaDbContextOptions;
 1266323    public string? TenantId { get; set; }
 24
 25    /// <summary>
 26    /// The default schema used by Elsa.
 27    /// </summary>
 765328    public static string ElsaSchema { get; set; } = "Elsa";
 29
 30    /// <inheritdoc/>
 31231    public string Schema { get; }
 32
 33    /// <summary>
 34    /// The table used to store the migrations history.
 35    /// </summary>
 165436    public static string MigrationsHistoryTable { get; set; } = "__EFMigrationsHistory";
 37
 38    /// <summary>
 39    /// Initializes a new instance of the <see cref="ElsaDbContextBase"/> class.
 40    /// </summary>
 599941    protected ElsaDbContextBase(DbContextOptions options, IServiceProvider serviceProvider) : base(options)
 42    {
 599943        ServiceProvider = serviceProvider;
 599944        _elsaDbContextOptions = options.FindExtension<ElsaDbContextOptionsExtension>()?.Options;
 45
 46        // ReSharper disable once VirtualMemberCallInConstructor
 599947        Schema = !string.IsNullOrWhiteSpace(_elsaDbContextOptions?.SchemaName) ? _elsaDbContextOptions.SchemaName : Elsa
 48
 599949        var tenantAccessor = serviceProvider.GetService<ITenantAccessor>();
 599950        var tenantId = tenantAccessor?.Tenant?.Id;
 51
 599952        if (!string.IsNullOrWhiteSpace(tenantId))
 053            TenantId = tenantId.NullIfEmpty();
 599954    }
 55
 56    /// <inheritdoc/>
 57    public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
 58    {
 76759        await OnBeforeSavingAsync(cancellationToken);
 76760        return await base.SaveChangesAsync(cancellationToken);
 76761    }
 62
 63    /// <inheritdoc />
 64    protected override void OnModelCreating(ModelBuilder modelBuilder)
 65    {
 466        if (!string.IsNullOrWhiteSpace(Schema))
 467            modelBuilder.HasDefaultSchema(Schema);
 68
 469        var additionalConfigurations = _elsaDbContextOptions?.GetModelConfigurations(this);
 70
 471        additionalConfigurations?.Invoke(modelBuilder);
 72
 473        using var scope = ServiceProvider.CreateScope();
 474        var entityTypeHandlers = scope.ServiceProvider.GetServices<IEntityModelCreatingHandler>().ToList();
 75
 6676        foreach (var entityType in modelBuilder.Model.GetEntityTypes().ToList())
 77        {
 17478            foreach (var handler in entityTypeHandlers)
 5879                handler.Handle(this, modelBuilder, entityType);
 80        }
 481    }
 82
 83    private async Task OnBeforeSavingAsync(CancellationToken cancellationToken)
 84    {
 76785        using var scope = ServiceProvider.CreateScope();
 76786        var handlers = scope.ServiceProvider.GetServices<IEntitySavingHandler>().ToList();
 1196087        foreach (var entry in ChangeTracker.Entries().Where(IsModifiedEntity))
 88        {
 1042689            foreach (var handler in handlers)
 090                await handler.HandleAsync(this, entry, cancellationToken);
 521391        }
 76792    }
 93
 94    /// <summary>
 95    /// Determine if an entity was modified.
 96    /// </summary>
 97    private bool IsModifiedEntity(EntityEntry entityEntry)
 98    {
 521399        return ModifiedEntityStates.Contains(entityEntry.State) && entityEntry.Entity is Entity;
 100    }
 101}