diff --git a/docs/en/Entity-Framework-Core.md b/docs/en/Entity-Framework-Core.md index cb9393b1aa..73efe7970a 100644 --- a/docs/en/Entity-Framework-Core.md +++ b/docs/en/Entity-Framework-Core.md @@ -139,6 +139,30 @@ Configure(options => }); ```` +Add actions for the `ConfigureConventions` and `OnModelCreating` methods of the `DbContext` as shown below: + +````csharp +options.DefaultConventionAction = (dbContext, builder) => +{ + // This action is called for ConfigureConventions method of all DbContexts. +}; + +options.ConfigureConventions((dbContext, builder) => +{ + // This action is called for ConfigureConventions method of specific DbContext. +}); + +options.DefaultOnModelCreatingAction = (dbContext, builder) => +{ + // This action is called for OnModelCreating method of all DbContexts. +}; + +options.ConfigureOnModelCreating((dbContext, builder) => +{ + // This action is called for OnModelCreating method of specific DbContext. +}); +```` + If you have a single `DbContext` or you have multiple `DbContext`s but want to use the same DBMS and configuration for all, you can leave it as is. However, if you need to configure a different DBMS or customize the configuration for a specific `DbContext`, you can specify it as shown below: ````csharp diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs index b06ba191dd..6c3ab12572 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs @@ -14,6 +14,7 @@ using Microsoft.EntityFrameworkCore.ChangeTracking; using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; +using Microsoft.Extensions.Options; using Volo.Abp.Auditing; using Volo.Abp.Data; using Volo.Abp.DependencyInjection; @@ -69,6 +70,8 @@ public abstract class AbpDbContext : DbContext, IAbpEfCoreDbContext, public ILogger> Logger => LazyServiceProvider.LazyGetService>>(NullLogger>.Instance); + public IOptions Options => LazyServiceProvider.LazyGetRequiredService>(); + private static readonly MethodInfo ConfigureBasePropertiesMethodInfo = typeof(AbpDbContext) .GetMethod( @@ -115,6 +118,33 @@ public abstract class AbpDbContext : DbContext, IAbpEfCoreDbContext, .MakeGenericMethod(entityType.ClrType) .Invoke(this, new object[] { modelBuilder, entityType }); } + + if (LazyServiceProvider == null || Options == null) + { + return; + } + + Options.Value.DefaultOnModelCreatingAction?.Invoke(this, modelBuilder); + foreach (var onModelCreatingAction in Options.Value.OnModelCreatingActions.GetOrDefault(typeof(TDbContext)) ?? []) + { + onModelCreatingAction.As>().Invoke(this, modelBuilder); + } + } + + protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder) + { + base.ConfigureConventions(configurationBuilder); + + if (LazyServiceProvider == null || Options == null) + { + return; + } + + Options.Value.DefaultConventionAction?.Invoke(this, configurationBuilder); + foreach (var conventionAction in Options.Value.ConventionActions.GetOrDefault(typeof(TDbContext)) ?? []) + { + conventionAction.As>().Invoke(this, configurationBuilder); + } } protected virtual void TrySetDatabaseProvider(ModelBuilder modelBuilder) diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContextOptions.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContextOptions.cs index cb5b258192..acde97340b 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContextOptions.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContextOptions.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using JetBrains.Annotations; +using Microsoft.EntityFrameworkCore; using Volo.Abp.DependencyInjection; using Volo.Abp.EntityFrameworkCore.DependencyInjection; using Volo.Abp.MultiTenancy; @@ -20,12 +21,22 @@ public class AbpDbContextOptions internal Dictionary DbContextReplacements { get; } + internal Action? DefaultConventionAction { get; set; } + + internal Dictionary> ConventionActions { get; } + + internal Action? DefaultOnModelCreatingAction { get; set; } + + internal Dictionary> OnModelCreatingActions { get; } + public AbpDbContextOptions() { DefaultPreConfigureActions = new List>(); PreConfigureActions = new Dictionary>(); ConfigureActions = new Dictionary(); DbContextReplacements = new Dictionary(); + ConventionActions = new Dictionary>(); + OnModelCreatingActions = new Dictionary>(); } public void PreConfigure([NotNull] Action action) @@ -42,6 +53,56 @@ public class AbpDbContextOptions DefaultConfigureAction = action; } + public void ConfigureDefaultConvention([NotNull] Action action) + { + Check.NotNull(action, nameof(action)); + + DefaultConventionAction = action; + } + + public void ConfigureConventions([NotNull] Action action) + where TDbContext : AbpDbContext + { + Check.NotNull(action, nameof(action)); + + var actions = ConventionActions.GetOrDefault(typeof(TDbContext)); + if (actions == null) + { + ConventionActions[typeof(TDbContext)] = new List + { + new Action((dbContext, builder) => action((TDbContext)dbContext, builder)) + }; + return; + } + + actions.Add(action); + } + + public void ConfigureDefaultOnModelCreating([NotNull] Action action) + { + Check.NotNull(action, nameof(action)); + + DefaultOnModelCreatingAction = action; + } + + public void ConfigureOnModelCreating([NotNull] Action action) + where TDbContext : AbpDbContext + { + Check.NotNull(action, nameof(action)); + + var actions = OnModelCreatingActions.GetOrDefault(typeof(TDbContext)); + if (actions == null) + { + OnModelCreatingActions[typeof(TDbContext)] = new List + { + new Action((dbContext, builder) => action((TDbContext)dbContext, builder)) + }; + return; + } + + actions.Add(action); + } + public bool IsConfiguredDefault() { return DefaultConfigureAction != null;