diff --git a/samples/Sample.Migrations/EFCores/ShardingSqlServerMigrationsSqlGenerator.cs b/samples/Sample.Migrations/EFCores/ShardingSqlServerMigrationsSqlGenerator.cs index 8ed2a6de..ea3751cd 100644 --- a/samples/Sample.Migrations/EFCores/ShardingSqlServerMigrationsSqlGenerator.cs +++ b/samples/Sample.Migrations/EFCores/ShardingSqlServerMigrationsSqlGenerator.cs @@ -31,7 +31,7 @@ namespace Sample.Migrations.EFCores var newCmds = builder.GetCommandList().ToList(); var addCmds = newCmds.Where(x => !oldCmds.Contains(x)).ToList(); - MigrationHelper.Generate(_shardingRuntimeContext,operation, builder, Dependencies.SqlGenerationHelper, addCmds); + MigrationHelper.Generate(_shardingRuntimeContext,operation, builder, Dependencies.SqlGenerationHelper, addCmds); } } } diff --git a/samples/Sample.MySql/DIExtension.cs b/samples/Sample.MySql/DIExtension.cs index 56ead53f..c88dc3a4 100644 --- a/samples/Sample.MySql/DIExtension.cs +++ b/samples/Sample.MySql/DIExtension.cs @@ -32,7 +32,7 @@ namespace Sample.MySql { Id = id.ToString(), Age = id, - Name = $"name_{id}", + Name = $"ds{(id%3)}", }); } var userModMonths = new List(); diff --git a/samples/Sample.MySql/ShardingMySqlMigrationsSqlGenerator.cs b/samples/Sample.MySql/ShardingMySqlMigrationsSqlGenerator.cs new file mode 100644 index 00000000..44fa5380 --- /dev/null +++ b/samples/Sample.MySql/ShardingMySqlMigrationsSqlGenerator.cs @@ -0,0 +1,32 @@ +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Migrations.Operations; +using Pomelo.EntityFrameworkCore.MySql.Infrastructure.Internal; +using Pomelo.EntityFrameworkCore.MySql.Migrations; +using ShardingCore.Core.RuntimeContexts; +using ShardingCore.Helpers; + +namespace Sample.MySql +{ + public class ShardingMySqlMigrationsSqlGenerator:MySqlMigrationsSqlGenerator + { + private readonly IShardingRuntimeContext _shardingRuntimeContext; + + public ShardingMySqlMigrationsSqlGenerator(MigrationsSqlGeneratorDependencies dependencies, IRelationalAnnotationProvider annotationProvider, IMySqlOptions options,IShardingRuntimeContext shardingRuntimeContext) : base(dependencies, annotationProvider, options) + { + _shardingRuntimeContext = shardingRuntimeContext; + } + protected override void Generate( + MigrationOperation operation, + IModel model, + MigrationCommandListBuilder builder) + { + var oldCmds = builder.GetCommandList().ToList(); + base.Generate(operation, model, builder); + var newCmds = builder.GetCommandList().ToList(); + var addCmds = newCmds.Where(x => !oldCmds.Contains(x)).ToList(); + + MigrationHelper.Generate(_shardingRuntimeContext,operation, builder, Dependencies.SqlGenerationHelper, addCmds); + } + } +} \ No newline at end of file diff --git a/samples/Sample.MySql/Shardings/SysUserModVirtualDataSourceRoute.cs b/samples/Sample.MySql/Shardings/SysUserModVirtualDataSourceRoute.cs index 565b6117..eb8eb619 100644 --- a/samples/Sample.MySql/Shardings/SysUserModVirtualDataSourceRoute.cs +++ b/samples/Sample.MySql/Shardings/SysUserModVirtualDataSourceRoute.cs @@ -14,7 +14,10 @@ public class SysUserModVirtualDataSourceRoute:AbstractShardingOperatorVirtualDat public override List GetAllDataSourceNames() { - return Enumerable.Range(0, 500).Select(o => $"ds{o}").ToList(); + return new List() + { + "ds0", "ds1", "ds2" + }; } public override bool AddDataSourceName(string dataSourceName) diff --git a/samples/Sample.MySql/Startup.cs b/samples/Sample.MySql/Startup.cs index 526d9ebe..253bacc4 100644 --- a/samples/Sample.MySql/Startup.cs +++ b/samples/Sample.MySql/Startup.cs @@ -1,17 +1,36 @@ using System.Diagnostics; using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Migrations; using Sample.MySql.DbContexts; using Sample.MySql.Shardings; using ShardingCore; using ShardingCore.Bootstrappers; using ShardingCore.Core; using ShardingCore.Core.RuntimeContexts; +using ShardingCore.EFCores; using ShardingCore.Extensions; using ShardingCore.TableExists; using ShardingCore.TableExists.Abstractions; namespace Sample.MySql { + // public class AutoStart : IHostedService + // { + // + // public AutoStart(IShardingBootstrapper shardingBootstrapper) + // { + // shardingBootstrapper.Start(); + // } + // public Task StartAsync(CancellationToken cancellationToken) + // { + // return Task.CompletedTask; + // } + // + // public Task StopAsync(CancellationToken cancellationToken) + // { + // return Task.CompletedTask; + // } + // } public class Startup { public static readonly ILoggerFactory efLogger = LoggerFactory.Create(builder => @@ -28,6 +47,7 @@ namespace Sample.MySql // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { + // services.AddHostedService(); services.AddControllers(); // services.AddShardingDbContext(o => o.UseMySql(hostBuilderContext.Configuration.GetSection("MySql")["ConnectionString"],new MySqlServerVersion("5.7.15")) // ,op => @@ -49,7 +69,7 @@ namespace Sample.MySql { o.AddShardingTableRoute(); o.AddShardingTableRoute(); - // o.AddShardingDataSourceRoute(); + o.AddShardingDataSourceRoute(); }).UseConfig(o => { o.UseShardingQuery((conStr,builder)=> @@ -68,6 +88,19 @@ namespace Sample.MySql .EnableSensitiveDataLogging(); }); o.AddDefaultDataSource("ds0", "server=127.0.0.1;port=3306;database=dbdbd0;userid=root;password=root;"); + o.AddExtraDataSource(sp=>new Dictionary() + { + {"ds1", "server=127.0.0.1;port=3306;database=dbdbd1;userid=root;password=root;"}, + {"ds2", "server=127.0.0.1;port=3306;database=dbdbd2;userid=root;password=root;"} + }); + o.UseShellDbContextConfigure(b => + { + b.ReplaceService(); + }); + o.UseExecutorDbContextConfigure(b => + { + b.ReplaceService(); + }); }).ReplaceService(ServiceLifetime.Singleton) .Build(sp); stopwatch.Stop(); @@ -120,6 +153,17 @@ namespace Sample.MySql app.UseDeveloperExceptionPage(); } app.ApplicationServices.UseAutoShardingCreate(); + + using (var scope = app.ApplicationServices.CreateScope()) + { + var defaultShardingDbContext = scope.ServiceProvider.GetService(); + if (defaultShardingDbContext.Database.GetPendingMigrations().Any()) + { + defaultShardingDbContext.Database.Migrate(); + } + } + + app.ApplicationServices.UseAutoTryCompensateTable(); app.UseRouting(); diff --git a/samples/Samples.AutoByDate.SqlServer/ShardingSqlServerMigrationsSqlGenerator.cs b/samples/Samples.AutoByDate.SqlServer/ShardingSqlServerMigrationsSqlGenerator.cs index 98719510..976995fa 100644 --- a/samples/Samples.AutoByDate.SqlServer/ShardingSqlServerMigrationsSqlGenerator.cs +++ b/samples/Samples.AutoByDate.SqlServer/ShardingSqlServerMigrationsSqlGenerator.cs @@ -59,7 +59,7 @@ namespace Samples.AutoByDate.SqlServer /// /// https://github.com/Coldairarrow/EFCore.Sharding/blob/master/src/EFCore.Sharding.SqlServer/ShardingSqlServerMigrationsSqlGenerator.cs /// - public class ShardingSqlServerMigrationsSqlGenerator : SqlServerMigrationsSqlGenerator where TShardingDbContext : DbContext, IShardingDbContext + public class ShardingSqlServerMigrationsSqlGenerator : SqlServerMigrationsSqlGenerator { private readonly IShardingRuntimeContext _shardingRuntimeContext; @@ -78,7 +78,7 @@ namespace Samples.AutoByDate.SqlServer var newCmds = builder.GetCommandList().ToList(); var addCmds = newCmds.Where(x => !oldCmds.Contains(x)).ToList(); - MigrationHelper.Generate(_shardingRuntimeContext,operation, builder, Dependencies.SqlGenerationHelper, addCmds); + MigrationHelper.Generate(_shardingRuntimeContext,operation, builder, Dependencies.SqlGenerationHelper, addCmds); } } } diff --git a/src/ShardingCore/Core/RuntimeContexts/IShardingRuntimeContext.cs b/src/ShardingCore/Core/RuntimeContexts/IShardingRuntimeContext.cs index e66ad5ad..aa8d3157 100644 --- a/src/ShardingCore/Core/RuntimeContexts/IShardingRuntimeContext.cs +++ b/src/ShardingCore/Core/RuntimeContexts/IShardingRuntimeContext.cs @@ -24,7 +24,7 @@ namespace ShardingCore.Core.RuntimeContexts public interface IShardingRuntimeContext { - IShardingProvider GetIhardingProvider(); + IShardingProvider GetShardingProvider(); IShardingComparer GetShardingComparer(); IShardingCompilerExecutor GetShardingCompilerExecutor(); IShardingReadWriteManager GetShardingReadWriteManager(); diff --git a/src/ShardingCore/Core/RuntimeContexts/ShardingRuntimeContext.cs b/src/ShardingCore/Core/RuntimeContexts/ShardingRuntimeContext.cs index 4fc7a514..51411f12 100644 --- a/src/ShardingCore/Core/RuntimeContexts/ShardingRuntimeContext.cs +++ b/src/ShardingCore/Core/RuntimeContexts/ShardingRuntimeContext.cs @@ -66,7 +66,7 @@ namespace ShardingCore.Core.RuntimeContexts } private IShardingProvider _shardingProvider; - public IShardingProvider GetIhardingProvider() + public IShardingProvider GetShardingProvider() { return _shardingProvider??=GetRequiredService(); } @@ -187,7 +187,7 @@ namespace ShardingCore.Core.RuntimeContexts try { - var shardingProvider = GetIhardingProvider(); + var shardingProvider = GetShardingProvider(); using (var scope = shardingProvider.CreateScope()) { using (var dbContext = _dbContextCreator.GetShellDbContext(scope.ServiceProvider)) @@ -222,6 +222,11 @@ namespace ShardingCore.Core.RuntimeContexts foreach (var entityType in entityTypes) { trackerManager.AddDbContextModel(entityType.ClrType, entityType.FindPrimaryKey() != null); + if (!entityMetadataManager.IsSharding(entityType.ClrType)) + { + var entityMetadata = new EntityMetadata(entityType.ClrType); + entityMetadataManager.AddEntityMetadata(entityMetadata); + } entityMetadataManager.TryInitModel(entityType); } } @@ -289,7 +294,7 @@ namespace ShardingCore.Core.RuntimeContexts private void InitFieldValue() { - GetIhardingProvider(); + GetShardingProvider(); GetShardingComparer(); GetShardingCompilerExecutor(); GetShardingReadWriteManager(); diff --git a/src/ShardingCore/Core/ShardingMigrations/Abstractions/IShardingMigrationAccessor.cs b/src/ShardingCore/Core/ShardingMigrations/Abstractions/IShardingMigrationAccessor.cs new file mode 100644 index 00000000..32f36fa9 --- /dev/null +++ b/src/ShardingCore/Core/ShardingMigrations/Abstractions/IShardingMigrationAccessor.cs @@ -0,0 +1,8 @@ +namespace ShardingCore.Core.ShardingMigrations.Abstractions +{ + + public interface IShardingMigrationAccessor + { + ShardingMigrationContext ShardingMigrationContext { get; set; } + } +} diff --git a/src/ShardingCore/Core/ShardingMigrations/Abstractions/IShardingMigrationManager.cs b/src/ShardingCore/Core/ShardingMigrations/Abstractions/IShardingMigrationManager.cs new file mode 100644 index 00000000..c5c05f34 --- /dev/null +++ b/src/ShardingCore/Core/ShardingMigrations/Abstractions/IShardingMigrationManager.cs @@ -0,0 +1,13 @@ +namespace ShardingCore.Core.ShardingMigrations.Abstractions +{ + + public interface IShardingMigrationManager + { + ShardingMigrationContext Current { get; } + /// + /// 创建路由scope + /// + /// + ShardingMigrationScope CreateScope(); + } +} diff --git a/src/ShardingCore/Core/ShardingMigrations/ShardingMigrationAccessor.cs b/src/ShardingCore/Core/ShardingMigrations/ShardingMigrationAccessor.cs new file mode 100644 index 00000000..ab341424 --- /dev/null +++ b/src/ShardingCore/Core/ShardingMigrations/ShardingMigrationAccessor.cs @@ -0,0 +1,17 @@ +using System.Threading; +using ShardingCore.Core.ShardingMigrations.Abstractions; + +namespace ShardingCore.Core.ShardingMigrations +{ + + public class ShardingMigrationAccessor:IShardingMigrationAccessor + { + private static AsyncLocal _shardingMigrationContext = new AsyncLocal(); + public ShardingMigrationContext ShardingMigrationContext + { + get => _shardingMigrationContext.Value; + set => _shardingMigrationContext.Value = value; + } + + } +} diff --git a/src/ShardingCore/Core/ShardingMigrations/ShardingMigrationContext.cs b/src/ShardingCore/Core/ShardingMigrations/ShardingMigrationContext.cs new file mode 100644 index 00000000..b188c1e6 --- /dev/null +++ b/src/ShardingCore/Core/ShardingMigrations/ShardingMigrationContext.cs @@ -0,0 +1,16 @@ +namespace ShardingCore.Core.ShardingMigrations +{ + + public class ShardingMigrationContext + { + /// + /// 当前的数据源名称 + /// + public string CurrentDataSourceName { get; set; } + + public static ShardingMigrationContext Create() + { + return new ShardingMigrationContext(); + } + } +} diff --git a/src/ShardingCore/Core/ShardingMigrations/ShardingMigrationManager.cs b/src/ShardingCore/Core/ShardingMigrations/ShardingMigrationManager.cs new file mode 100644 index 00000000..1236d87a --- /dev/null +++ b/src/ShardingCore/Core/ShardingMigrations/ShardingMigrationManager.cs @@ -0,0 +1,22 @@ +using ShardingCore.Core.ShardingMigrations.Abstractions; + +namespace ShardingCore.Core.ShardingMigrations +{ + public class ShardingMigrationManager:IShardingMigrationManager + { + private readonly IShardingMigrationAccessor _shardingMigrationAccessor; + + public ShardingMigrationManager(IShardingMigrationAccessor shardingMigrationAccessor) + { + _shardingMigrationAccessor = shardingMigrationAccessor; + } + + public ShardingMigrationContext Current => _shardingMigrationAccessor.ShardingMigrationContext; + public ShardingMigrationScope CreateScope() + { + var shardingMigrationScope = new ShardingMigrationScope(_shardingMigrationAccessor); + _shardingMigrationAccessor.ShardingMigrationContext = ShardingMigrationContext.Create(); + return shardingMigrationScope; + } + } +} diff --git a/src/ShardingCore/Core/ShardingMigrations/ShardingMigrationOptions.cs b/src/ShardingCore/Core/ShardingMigrations/ShardingMigrationOptions.cs new file mode 100644 index 00000000..6a8402ad --- /dev/null +++ b/src/ShardingCore/Core/ShardingMigrations/ShardingMigrationOptions.cs @@ -0,0 +1,8 @@ +using System; + +namespace ShardingCore.Core.ShardingMigrations +{ + public class ShardingMigrationOptions + { + } +} diff --git a/src/ShardingCore/Core/ShardingMigrations/ShardingMigrationScope.cs b/src/ShardingCore/Core/ShardingMigrations/ShardingMigrationScope.cs new file mode 100644 index 00000000..1bc8aadf --- /dev/null +++ b/src/ShardingCore/Core/ShardingMigrations/ShardingMigrationScope.cs @@ -0,0 +1,20 @@ +using System; +using ShardingCore.Core.ShardingMigrations.Abstractions; + +namespace ShardingCore.Core.ShardingMigrations +{ + + public class ShardingMigrationScope:IDisposable + { + private readonly IShardingMigrationAccessor _shardingMigrationAccessor; + + public ShardingMigrationScope(IShardingMigrationAccessor shardingMigrationAccessor) + { + _shardingMigrationAccessor = shardingMigrationAccessor; + } + public void Dispose() + { + _shardingMigrationAccessor.ShardingMigrationContext = null; + } + } +} \ No newline at end of file diff --git a/src/ShardingCore/DynamicDataSources/DefaultDataSourceInitializer.cs b/src/ShardingCore/DynamicDataSources/DefaultDataSourceInitializer.cs index d3132bbf..f2bc50d6 100644 --- a/src/ShardingCore/DynamicDataSources/DefaultDataSourceInitializer.cs +++ b/src/ShardingCore/DynamicDataSources/DefaultDataSourceInitializer.cs @@ -124,7 +124,7 @@ namespace ShardingCore.DynamicDataSources } else { - dbContext.RemoveDbContextAllRelationModelThatIsNoSharding(); + dbContext.RemoveDbContextAllRelationModelWithoutShardingDataSourceOnly(); } dbContext.Database.EnsureCreated(); diff --git a/src/ShardingCore/EFCores/ShardingMigrator.cs b/src/ShardingCore/EFCores/ShardingMigrator.cs new file mode 100644 index 00000000..3b47f67c --- /dev/null +++ b/src/ShardingCore/EFCores/ShardingMigrator.cs @@ -0,0 +1,65 @@ +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Diagnostics; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Migrations.Internal; +using Microsoft.EntityFrameworkCore.Storage; +using ShardingCore.Core.RuntimeContexts; +using ShardingCore.Core.ShardingMigrations.Abstractions; +using ShardingCore.Extensions; +using ShardingCore.Sharding.Abstractions; + +namespace ShardingCore.EFCores +{ + public class ShardingMigrator:Migrator + { + private readonly IShardingRuntimeContext _shardingRuntimeContext; + + public ShardingMigrator(IShardingRuntimeContext shardingRuntimeContext,IMigrationsAssembly migrationsAssembly, IHistoryRepository historyRepository, IDatabaseCreator databaseCreator, IMigrationsSqlGenerator migrationsSqlGenerator, IRawSqlCommandBuilder rawSqlCommandBuilder, IMigrationCommandExecutor migrationCommandExecutor, IRelationalConnection connection, ISqlGenerationHelper sqlGenerationHelper, ICurrentDbContext currentContext, IModelRuntimeInitializer modelRuntimeInitializer, IDiagnosticsLogger logger, IRelationalCommandDiagnosticsLogger commandLogger, IDatabaseProvider databaseProvider) : base(migrationsAssembly, historyRepository, databaseCreator, migrationsSqlGenerator, rawSqlCommandBuilder, migrationCommandExecutor, connection, sqlGenerationHelper, currentContext, modelRuntimeInitializer, logger, commandLogger, databaseProvider) + { + _shardingRuntimeContext = shardingRuntimeContext; + } + + public override void Migrate(string targetMigration = null) + { + this.MigrateAsync(targetMigration).WaitAndUnwrapException(); + // base.Migrate(targetMigration); + } + + public override async Task MigrateAsync(string targetMigration = null, CancellationToken cancellationToken = new CancellationToken()) + { + var virtualDataSource = _shardingRuntimeContext.GetVirtualDataSource(); + var shardingProvider = _shardingRuntimeContext.GetShardingProvider(); + var dbContextCreator = _shardingRuntimeContext.GetDbContextCreator(); + var routeTailFactory = _shardingRuntimeContext.GetRouteTailFactory(); + var shardingMigrationManager = _shardingRuntimeContext.GetRequiredService(); + var allDataSourceNames = virtualDataSource.GetAllDataSourceNames(); + using (var scope=shardingProvider.CreateScope()) + { + using (var shellDbContext = dbContextCreator.GetShellDbContext(scope.ServiceProvider)) + { + var shardingDbContext = (IShardingDbContext)shellDbContext; + foreach (var dataSourceName in allDataSourceNames) + { + using (shardingMigrationManager.CreateScope()) + { + shardingMigrationManager.Current.CurrentDataSourceName = dataSourceName; + + using (var dbContext = shardingDbContext.GetDbContext(dataSourceName, true, + routeTailFactory.Create(string.Empty, false))) + { + if ((await dbContext.Database.GetPendingMigrationsAsync()).Any()) + { + await dbContext.Database.MigrateAsync(); + } + } + } + } + } + } + } + } +} diff --git a/src/ShardingCore/Extensions/DbContextExtension.cs b/src/ShardingCore/Extensions/DbContextExtension.cs index 1457ce6a..22be81b6 100644 --- a/src/ShardingCore/Extensions/DbContextExtension.cs +++ b/src/ShardingCore/Extensions/DbContextExtension.cs @@ -103,10 +103,10 @@ namespace ShardingCore.Extensions //#endif // } /// - /// 移除所有的没有分片的表 + /// 移除所有除了仅分库的 /// /// - public static void RemoveDbContextAllRelationModelThatIsNoSharding(this DbContext dbContext) + public static void RemoveDbContextAllRelationModelWithoutShardingDataSourceOnly(this DbContext dbContext) { #if !EFCORE2&&!EFCORE3&&!EFCORE5&&!EFCORE6 throw new NotImplementedException(); diff --git a/src/ShardingCore/Helpers/MigrationHelper.cs b/src/ShardingCore/Helpers/MigrationHelper.cs index b19405be..f93e9674 100644 --- a/src/ShardingCore/Helpers/MigrationHelper.cs +++ b/src/ShardingCore/Helpers/MigrationHelper.cs @@ -12,6 +12,8 @@ using Microsoft.EntityFrameworkCore.Migrations.Operations; using Microsoft.EntityFrameworkCore.Storage; using ShardingCore.Core; using ShardingCore.Core.RuntimeContexts; +using ShardingCore.Core.ShardingMigrations.Abstractions; +using ShardingCore.Core.VirtualDatabase.VirtualDataSources; using ShardingCore.Extensions; using ShardingCore.Sharding.Abstractions; @@ -31,33 +33,61 @@ namespace ShardingCore.Helpers public class MigrationHelper { private MigrationHelper() { } - public static void Generate( + public static void Generate( IShardingRuntimeContext shardingRuntimeContext, MigrationOperation operation, MigrationCommandListBuilder builder, ISqlGenerationHelper sqlGenerationHelper, List addCmds - ) where TShardingDContext:DbContext,IShardingDbContext + ) { var migrationCommands = (List) builder.GetFieldValue("_commands"); - addCmds.ForEach(aAddCmd => + var shardingMigrationManager = shardingRuntimeContext.GetRequiredService(); + var virtualDataSource = shardingRuntimeContext.GetRequiredService(); + if (shardingMigrationManager.Current == null||shardingMigrationManager.Current.CurrentDataSourceName==virtualDataSource.DefaultDataSourceName) { - var shardingCmds = BuildShardingCmds(shardingRuntimeContext,operation, aAddCmd.CommandText, sqlGenerationHelper); - if (shardingCmds.IsNotEmpty()) + addCmds.ForEach(aAddCmd => { - migrationCommands.Remove(aAddCmd); - //针对builder的原始表进行移除 - shardingCmds.ForEach(aShardingCmd => + var shardingCmds = BuildShardingCmds(shardingRuntimeContext,operation, aAddCmd.CommandText, sqlGenerationHelper); + if (shardingCmds.IsNotEmpty()) { - builder.Append(aShardingCmd) - .EndCommand(); - }); - } - }); + migrationCommands.Remove(aAddCmd); + //针对builder的原始表进行移除 + shardingCmds.ForEach(aShardingCmd => + { + builder.Append(aShardingCmd) + .EndCommand(); + }); + } + }); + } + else + { + addCmds.ForEach(aAddCmd => + { + var (migrationResult,shardingCmds) = BuildDataSourceShardingCmds(shardingRuntimeContext,shardingMigrationManager.Current.CurrentDataSourceName,operation, aAddCmd.CommandText, sqlGenerationHelper); + //如果是分库的 + if (migrationResult==MigrationResultEnum.DataSourceTableCommand) + { + if (shardingCmds.IsNotEmpty()) + { + migrationCommands.Remove(aAddCmd); + //针对builder的原始表进行移除 + shardingCmds.ForEach(aShardingCmd => + { + builder.Append(aShardingCmd) + .EndCommand(); + }); + } + }else if (migrationResult==MigrationResultEnum.TableCommand)//如果不是分库并且有表的话那么就把命令删除掉 + { + migrationCommands.Remove(aAddCmd); + } + }); + } } - private static List BuildShardingCmds(IShardingRuntimeContext shardingRuntimeContext,MigrationOperation operation, string sourceCmd, ISqlGenerationHelper sqlGenerationHelper) - where TShardingDContext : DbContext, IShardingDbContext + private static List BuildShardingCmds(IShardingRuntimeContext shardingRuntimeContext,MigrationOperation operation, string sourceCmd, ISqlGenerationHelper sqlGenerationHelper) { //所有MigrationOperation定义 //https://github.com/dotnet/efcore/tree/b970bf29a46521f40862a01db9e276e6448d3cb0/src/EFCore.Relational/Migrations/Operations @@ -114,6 +144,92 @@ namespace ShardingCore.Helpers return string.Format("^({0})$|^({0}_.*?)$|^(.*?_{0}_.*?)$|^(.*?_{0})$", absTableName); } } + private static (MigrationResultEnum migrationResult,List) BuildDataSourceShardingCmds(IShardingRuntimeContext shardingRuntimeContext,string dataSourceName,MigrationOperation operation, string sourceCmd, ISqlGenerationHelper sqlGenerationHelper) + { + //所有MigrationOperation定义 + //https://github.com/dotnet/efcore/tree/b970bf29a46521f40862a01db9e276e6448d3cb0/src/EFCore.Relational/Migrations/Operations + //ColumnOperation仅替换Table + //其余其余都是将Name和Table使用分表名替换 + var dataSourceRouteManager = shardingRuntimeContext.GetDataSourceRouteManager(); + var entityMetadataManager = shardingRuntimeContext.GetEntityMetadataManager(); + var tableRouteManager = shardingRuntimeContext.GetTableRouteManager(); + var tableRoutes = tableRouteManager.GetRoutes(); + var existsShardingTables = tableRoutes.ToDictionary(o => o.EntityMetadata.LogicTableName, o => o.GetTails().Select(p=>$"{o.EntityMetadata.LogicTableName}{o.EntityMetadata.TableSeparator}{p}").ToList()); + //Dictionary> _existsShardingTables + // = Cache.ServiceProvider.GetService().ExistsShardingTables; + List resList = new List(); + string absTableName = string.Empty; + + string name = operation.GetPropertyValue("Name") as string; + string tableName = operation.GetPropertyValue("Table") as string; + string pattern = string.Format("^({0})$|^({0}_.*?)$|^(.*?_{0}_.*?)$|^(.*?_{0})$", absTableName); + Func>, bool> where = x => + existsShardingTables.Any(y =>x.Key==y.Key&& Regex.IsMatch(name, BuildPattern(y.Key))); + + if (!string.IsNullOrWhiteSpace(tableName)) + { + absTableName = tableName; + } + else if (!string.IsNullOrWhiteSpace(name)) + { + if (existsShardingTables.Any(x => where(x))) + { + absTableName = existsShardingTables.Where(x => where(x)).FirstOrDefault().Key; + } + else + { + absTableName = name; + } + } + + MigrationResultEnum migrationResult = MigrationResultEnum.OtherCommand; + var entityMetadata = entityMetadataManager.TryGetByLogicTableName(absTableName); + if (entityMetadata != null) + { + migrationResult = MigrationResultEnum.TableCommand; + + + bool isShardingDataSource =entityMetadata.IsShardingDataSource(); + if (isShardingDataSource) + { + var virtualDataSourceRoute = dataSourceRouteManager.GetRoute(entityMetadata.EntityType); + isShardingDataSource = virtualDataSourceRoute.GetAllDataSourceNames().Contains(dataSourceName); + } + + if (isShardingDataSource) + { + migrationResult= MigrationResultEnum.DataSourceTableCommand; + } + //分表 + if (!string.IsNullOrWhiteSpace(absTableName) && existsShardingTables.ContainsKey(absTableName)) + { + + var shardings = existsShardingTables[absTableName]; + shardings.ForEach(aShardingTable => + { + string newCmd = sourceCmd; + GetReplaceGroups(operation, absTableName, aShardingTable).ForEach(aReplace => + { + newCmd = newCmd.Replace( + sqlGenerationHelper.DelimitIdentifier(aReplace.sourceName), + sqlGenerationHelper.DelimitIdentifier(aReplace.targetName)); + }); + if (newCmd.Contains("EXEC sp_addextendedproperty 'MS_Description', @description, 'SCHEMA', @defaultSchema, 'TABLE'")) + { + newCmd=newCmd.Replace($"EXEC sp_addextendedproperty 'MS_Description', @description, 'SCHEMA', @defaultSchema, 'TABLE', N'{absTableName}'", $"EXEC sp_addextendedproperty 'MS_Description', @description, 'SCHEMA', @defaultSchema, 'TABLE', N'{aShardingTable}'"); + } + resList.Add(newCmd); + }); + } + } + + return (migrationResult,resList); + + string BuildPattern(string absTableName) + { + return string.Format("^({0})$|^({0}_.*?)$|^(.*?_{0}_.*?)$|^(.*?_{0})$", absTableName); + } + } private static List<(string sourceName, string targetName)> GetReplaceGroups( MigrationOperation operation, string sourceTableName, string targetTableName) { diff --git a/src/ShardingCore/Helpers/MigrationResultEnum.cs b/src/ShardingCore/Helpers/MigrationResultEnum.cs new file mode 100644 index 00000000..f3ec323c --- /dev/null +++ b/src/ShardingCore/Helpers/MigrationResultEnum.cs @@ -0,0 +1,9 @@ +namespace ShardingCore.Helpers +{ + public enum MigrationResultEnum + { + OtherCommand, + DataSourceTableCommand, + TableCommand + } +} \ No newline at end of file diff --git a/src/ShardingCore/ShardingCoreExtension.cs b/src/ShardingCore/ShardingCoreExtension.cs index 45ff6961..2c4d8639 100644 --- a/src/ShardingCore/ShardingCoreExtension.cs +++ b/src/ShardingCore/ShardingCoreExtension.cs @@ -29,6 +29,8 @@ using ShardingCore.Core.DbContextCreator; using ShardingCore.Core.QueryTrackers; using ShardingCore.Core.RuntimeContexts; using ShardingCore.Core.ShardingConfigurations.ConfigBuilders; +using ShardingCore.Core.ShardingMigrations; +using ShardingCore.Core.ShardingMigrations.Abstractions; using ShardingCore.Core.UnionAllMergeShardingProviders; using ShardingCore.Core.UnionAllMergeShardingProviders.Abstractions; using ShardingCore.Core.VirtualDatabase.VirtualDataSources.Abstractions; @@ -144,6 +146,10 @@ namespace ShardingCore services.TryAddSingleton(); services.TryAddSingleton(); + //migration manage + services.TryAddSingleton(); + services.TryAddSingleton(); + //route manage services.TryAddSingleton(); services.TryAddSingleton(); @@ -151,6 +157,7 @@ namespace ShardingCore //sharding page services.TryAddSingleton(); services.TryAddSingleton(); + services.TryAddSingleton(); services.TryAddSingleton(); services.TryAddSingleton();