[#161]支持分库迁移
This commit is contained in:
parent
4cd1a8a073
commit
98f76b409b
|
@ -31,7 +31,7 @@ namespace Sample.Migrations.EFCores
|
||||||
var newCmds = builder.GetCommandList().ToList();
|
var newCmds = builder.GetCommandList().ToList();
|
||||||
var addCmds = newCmds.Where(x => !oldCmds.Contains(x)).ToList();
|
var addCmds = newCmds.Where(x => !oldCmds.Contains(x)).ToList();
|
||||||
|
|
||||||
MigrationHelper.Generate<TShardingDbContext>(_shardingRuntimeContext,operation, builder, Dependencies.SqlGenerationHelper, addCmds);
|
MigrationHelper.Generate(_shardingRuntimeContext,operation, builder, Dependencies.SqlGenerationHelper, addCmds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,7 @@ namespace Sample.MySql
|
||||||
{
|
{
|
||||||
Id = id.ToString(),
|
Id = id.ToString(),
|
||||||
Age = id,
|
Age = id,
|
||||||
Name = $"name_{id}",
|
Name = $"ds{(id%3)}",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
var userModMonths = new List<SysUserLogByMonth>();
|
var userModMonths = new List<SysUserLogByMonth>();
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,7 +14,10 @@ public class SysUserModVirtualDataSourceRoute:AbstractShardingOperatorVirtualDat
|
||||||
|
|
||||||
public override List<string> GetAllDataSourceNames()
|
public override List<string> GetAllDataSourceNames()
|
||||||
{
|
{
|
||||||
return Enumerable.Range(0, 500).Select(o => $"ds{o}").ToList();
|
return new List<string>()
|
||||||
|
{
|
||||||
|
"ds0", "ds1", "ds2"
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool AddDataSourceName(string dataSourceName)
|
public override bool AddDataSourceName(string dataSourceName)
|
||||||
|
|
|
@ -1,17 +1,36 @@
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
using Sample.MySql.DbContexts;
|
using Sample.MySql.DbContexts;
|
||||||
using Sample.MySql.Shardings;
|
using Sample.MySql.Shardings;
|
||||||
using ShardingCore;
|
using ShardingCore;
|
||||||
using ShardingCore.Bootstrappers;
|
using ShardingCore.Bootstrappers;
|
||||||
using ShardingCore.Core;
|
using ShardingCore.Core;
|
||||||
using ShardingCore.Core.RuntimeContexts;
|
using ShardingCore.Core.RuntimeContexts;
|
||||||
|
using ShardingCore.EFCores;
|
||||||
using ShardingCore.Extensions;
|
using ShardingCore.Extensions;
|
||||||
using ShardingCore.TableExists;
|
using ShardingCore.TableExists;
|
||||||
using ShardingCore.TableExists.Abstractions;
|
using ShardingCore.TableExists.Abstractions;
|
||||||
|
|
||||||
namespace Sample.MySql
|
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 class Startup
|
||||||
{
|
{
|
||||||
public static readonly ILoggerFactory efLogger = LoggerFactory.Create(builder =>
|
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.
|
// This method gets called by the runtime. Use this method to add services to the container.
|
||||||
public void ConfigureServices(IServiceCollection services)
|
public void ConfigureServices(IServiceCollection services)
|
||||||
{
|
{
|
||||||
|
// services.AddHostedService<AutoStart>();
|
||||||
services.AddControllers();
|
services.AddControllers();
|
||||||
// services.AddShardingDbContext<ShardingDefaultDbContext, DefaultDbContext>(o => o.UseMySql(hostBuilderContext.Configuration.GetSection("MySql")["ConnectionString"],new MySqlServerVersion("5.7.15"))
|
// services.AddShardingDbContext<ShardingDefaultDbContext, DefaultDbContext>(o => o.UseMySql(hostBuilderContext.Configuration.GetSection("MySql")["ConnectionString"],new MySqlServerVersion("5.7.15"))
|
||||||
// ,op =>
|
// ,op =>
|
||||||
|
@ -49,7 +69,7 @@ namespace Sample.MySql
|
||||||
{
|
{
|
||||||
o.AddShardingTableRoute<SysUserLogByMonthRoute>();
|
o.AddShardingTableRoute<SysUserLogByMonthRoute>();
|
||||||
o.AddShardingTableRoute<SysUserModVirtualTableRoute>();
|
o.AddShardingTableRoute<SysUserModVirtualTableRoute>();
|
||||||
// o.AddShardingDataSourceRoute<SysUserModVirtualDataSourceRoute>();
|
o.AddShardingDataSourceRoute<SysUserModVirtualDataSourceRoute>();
|
||||||
}).UseConfig(o =>
|
}).UseConfig(o =>
|
||||||
{
|
{
|
||||||
o.UseShardingQuery((conStr,builder)=>
|
o.UseShardingQuery((conStr,builder)=>
|
||||||
|
@ -68,6 +88,19 @@ namespace Sample.MySql
|
||||||
.EnableSensitiveDataLogging();
|
.EnableSensitiveDataLogging();
|
||||||
});
|
});
|
||||||
o.AddDefaultDataSource("ds0", "server=127.0.0.1;port=3306;database=dbdbd0;userid=root;password=root;");
|
o.AddDefaultDataSource("ds0", "server=127.0.0.1;port=3306;database=dbdbd0;userid=root;password=root;");
|
||||||
|
o.AddExtraDataSource(sp=>new Dictionary<string, string>()
|
||||||
|
{
|
||||||
|
{"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<IMigrator, ShardingMigrator>();
|
||||||
|
});
|
||||||
|
o.UseExecutorDbContextConfigure(b =>
|
||||||
|
{
|
||||||
|
b.ReplaceService<IMigrationsSqlGenerator, ShardingMySqlMigrationsSqlGenerator>();
|
||||||
|
});
|
||||||
}).ReplaceService<ITableEnsureManager,MySqlTableEnsureManager>(ServiceLifetime.Singleton)
|
}).ReplaceService<ITableEnsureManager,MySqlTableEnsureManager>(ServiceLifetime.Singleton)
|
||||||
.Build(sp);
|
.Build(sp);
|
||||||
stopwatch.Stop();
|
stopwatch.Stop();
|
||||||
|
@ -120,6 +153,17 @@ namespace Sample.MySql
|
||||||
app.UseDeveloperExceptionPage();
|
app.UseDeveloperExceptionPage();
|
||||||
}
|
}
|
||||||
app.ApplicationServices.UseAutoShardingCreate();
|
app.ApplicationServices.UseAutoShardingCreate();
|
||||||
|
|
||||||
|
using (var scope = app.ApplicationServices.CreateScope())
|
||||||
|
{
|
||||||
|
var defaultShardingDbContext = scope.ServiceProvider.GetService<DefaultShardingDbContext>();
|
||||||
|
if (defaultShardingDbContext.Database.GetPendingMigrations().Any())
|
||||||
|
{
|
||||||
|
defaultShardingDbContext.Database.Migrate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
app.ApplicationServices.UseAutoTryCompensateTable();
|
app.ApplicationServices.UseAutoTryCompensateTable();
|
||||||
app.UseRouting();
|
app.UseRouting();
|
||||||
|
|
||||||
|
|
|
@ -59,7 +59,7 @@ namespace Samples.AutoByDate.SqlServer
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// https://github.com/Coldairarrow/EFCore.Sharding/blob/master/src/EFCore.Sharding.SqlServer/ShardingSqlServerMigrationsSqlGenerator.cs
|
/// https://github.com/Coldairarrow/EFCore.Sharding/blob/master/src/EFCore.Sharding.SqlServer/ShardingSqlServerMigrationsSqlGenerator.cs
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class ShardingSqlServerMigrationsSqlGenerator<TShardingDbContext> : SqlServerMigrationsSqlGenerator where TShardingDbContext : DbContext, IShardingDbContext
|
public class ShardingSqlServerMigrationsSqlGenerator : SqlServerMigrationsSqlGenerator
|
||||||
{
|
{
|
||||||
private readonly IShardingRuntimeContext _shardingRuntimeContext;
|
private readonly IShardingRuntimeContext _shardingRuntimeContext;
|
||||||
|
|
||||||
|
@ -78,7 +78,7 @@ namespace Samples.AutoByDate.SqlServer
|
||||||
var newCmds = builder.GetCommandList().ToList();
|
var newCmds = builder.GetCommandList().ToList();
|
||||||
var addCmds = newCmds.Where(x => !oldCmds.Contains(x)).ToList();
|
var addCmds = newCmds.Where(x => !oldCmds.Contains(x)).ToList();
|
||||||
|
|
||||||
MigrationHelper.Generate<TShardingDbContext>(_shardingRuntimeContext,operation, builder, Dependencies.SqlGenerationHelper, addCmds);
|
MigrationHelper.Generate(_shardingRuntimeContext,operation, builder, Dependencies.SqlGenerationHelper, addCmds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ namespace ShardingCore.Core.RuntimeContexts
|
||||||
|
|
||||||
public interface IShardingRuntimeContext
|
public interface IShardingRuntimeContext
|
||||||
{
|
{
|
||||||
IShardingProvider GetIhardingProvider();
|
IShardingProvider GetShardingProvider();
|
||||||
IShardingComparer GetShardingComparer();
|
IShardingComparer GetShardingComparer();
|
||||||
IShardingCompilerExecutor GetShardingCompilerExecutor();
|
IShardingCompilerExecutor GetShardingCompilerExecutor();
|
||||||
IShardingReadWriteManager GetShardingReadWriteManager();
|
IShardingReadWriteManager GetShardingReadWriteManager();
|
||||||
|
|
|
@ -66,7 +66,7 @@ namespace ShardingCore.Core.RuntimeContexts
|
||||||
}
|
}
|
||||||
|
|
||||||
private IShardingProvider _shardingProvider;
|
private IShardingProvider _shardingProvider;
|
||||||
public IShardingProvider GetIhardingProvider()
|
public IShardingProvider GetShardingProvider()
|
||||||
{
|
{
|
||||||
return _shardingProvider??=GetRequiredService<IShardingProvider>();
|
return _shardingProvider??=GetRequiredService<IShardingProvider>();
|
||||||
}
|
}
|
||||||
|
@ -187,7 +187,7 @@ namespace ShardingCore.Core.RuntimeContexts
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var shardingProvider = GetIhardingProvider();
|
var shardingProvider = GetShardingProvider();
|
||||||
using (var scope = shardingProvider.CreateScope())
|
using (var scope = shardingProvider.CreateScope())
|
||||||
{
|
{
|
||||||
using (var dbContext = _dbContextCreator.GetShellDbContext(scope.ServiceProvider))
|
using (var dbContext = _dbContextCreator.GetShellDbContext(scope.ServiceProvider))
|
||||||
|
@ -222,6 +222,11 @@ namespace ShardingCore.Core.RuntimeContexts
|
||||||
foreach (var entityType in entityTypes)
|
foreach (var entityType in entityTypes)
|
||||||
{
|
{
|
||||||
trackerManager.AddDbContextModel(entityType.ClrType, entityType.FindPrimaryKey() != null);
|
trackerManager.AddDbContextModel(entityType.ClrType, entityType.FindPrimaryKey() != null);
|
||||||
|
if (!entityMetadataManager.IsSharding(entityType.ClrType))
|
||||||
|
{
|
||||||
|
var entityMetadata = new EntityMetadata(entityType.ClrType);
|
||||||
|
entityMetadataManager.AddEntityMetadata(entityMetadata);
|
||||||
|
}
|
||||||
entityMetadataManager.TryInitModel(entityType);
|
entityMetadataManager.TryInitModel(entityType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -289,7 +294,7 @@ namespace ShardingCore.Core.RuntimeContexts
|
||||||
|
|
||||||
private void InitFieldValue()
|
private void InitFieldValue()
|
||||||
{
|
{
|
||||||
GetIhardingProvider();
|
GetShardingProvider();
|
||||||
GetShardingComparer();
|
GetShardingComparer();
|
||||||
GetShardingCompilerExecutor();
|
GetShardingCompilerExecutor();
|
||||||
GetShardingReadWriteManager();
|
GetShardingReadWriteManager();
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
namespace ShardingCore.Core.ShardingMigrations.Abstractions
|
||||||
|
{
|
||||||
|
|
||||||
|
public interface IShardingMigrationAccessor
|
||||||
|
{
|
||||||
|
ShardingMigrationContext ShardingMigrationContext { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
namespace ShardingCore.Core.ShardingMigrations.Abstractions
|
||||||
|
{
|
||||||
|
|
||||||
|
public interface IShardingMigrationManager
|
||||||
|
{
|
||||||
|
ShardingMigrationContext Current { get; }
|
||||||
|
/// <summary>
|
||||||
|
/// 创建路由scope
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
ShardingMigrationScope CreateScope();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
using System.Threading;
|
||||||
|
using ShardingCore.Core.ShardingMigrations.Abstractions;
|
||||||
|
|
||||||
|
namespace ShardingCore.Core.ShardingMigrations
|
||||||
|
{
|
||||||
|
|
||||||
|
public class ShardingMigrationAccessor:IShardingMigrationAccessor
|
||||||
|
{
|
||||||
|
private static AsyncLocal<ShardingMigrationContext> _shardingMigrationContext = new AsyncLocal<ShardingMigrationContext>();
|
||||||
|
public ShardingMigrationContext ShardingMigrationContext
|
||||||
|
{
|
||||||
|
get => _shardingMigrationContext.Value;
|
||||||
|
set => _shardingMigrationContext.Value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
namespace ShardingCore.Core.ShardingMigrations
|
||||||
|
{
|
||||||
|
|
||||||
|
public class ShardingMigrationContext
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 当前的数据源名称
|
||||||
|
/// </summary>
|
||||||
|
public string CurrentDataSourceName { get; set; }
|
||||||
|
|
||||||
|
public static ShardingMigrationContext Create()
|
||||||
|
{
|
||||||
|
return new ShardingMigrationContext();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace ShardingCore.Core.ShardingMigrations
|
||||||
|
{
|
||||||
|
public class ShardingMigrationOptions
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -124,7 +124,7 @@ namespace ShardingCore.DynamicDataSources
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
dbContext.RemoveDbContextAllRelationModelThatIsNoSharding();
|
dbContext.RemoveDbContextAllRelationModelWithoutShardingDataSourceOnly();
|
||||||
}
|
}
|
||||||
|
|
||||||
dbContext.Database.EnsureCreated();
|
dbContext.Database.EnsureCreated();
|
||||||
|
|
|
@ -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<DbLoggerCategory.Migrations> 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<IShardingMigrationManager>();
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -103,10 +103,10 @@ namespace ShardingCore.Extensions
|
||||||
//#endif
|
//#endif
|
||||||
// }
|
// }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 移除所有的没有分片的表
|
/// 移除所有除了仅分库的
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="dbContext"></param>
|
/// <param name="dbContext"></param>
|
||||||
public static void RemoveDbContextAllRelationModelThatIsNoSharding(this DbContext dbContext)
|
public static void RemoveDbContextAllRelationModelWithoutShardingDataSourceOnly(this DbContext dbContext)
|
||||||
{
|
{
|
||||||
#if !EFCORE2&&!EFCORE3&&!EFCORE5&&!EFCORE6
|
#if !EFCORE2&&!EFCORE3&&!EFCORE5&&!EFCORE6
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
|
|
|
@ -12,6 +12,8 @@ using Microsoft.EntityFrameworkCore.Migrations.Operations;
|
||||||
using Microsoft.EntityFrameworkCore.Storage;
|
using Microsoft.EntityFrameworkCore.Storage;
|
||||||
using ShardingCore.Core;
|
using ShardingCore.Core;
|
||||||
using ShardingCore.Core.RuntimeContexts;
|
using ShardingCore.Core.RuntimeContexts;
|
||||||
|
using ShardingCore.Core.ShardingMigrations.Abstractions;
|
||||||
|
using ShardingCore.Core.VirtualDatabase.VirtualDataSources;
|
||||||
using ShardingCore.Extensions;
|
using ShardingCore.Extensions;
|
||||||
using ShardingCore.Sharding.Abstractions;
|
using ShardingCore.Sharding.Abstractions;
|
||||||
|
|
||||||
|
@ -31,33 +33,61 @@ namespace ShardingCore.Helpers
|
||||||
public class MigrationHelper
|
public class MigrationHelper
|
||||||
{
|
{
|
||||||
private MigrationHelper() { }
|
private MigrationHelper() { }
|
||||||
public static void Generate<TShardingDContext>(
|
public static void Generate(
|
||||||
IShardingRuntimeContext shardingRuntimeContext,
|
IShardingRuntimeContext shardingRuntimeContext,
|
||||||
MigrationOperation operation,
|
MigrationOperation operation,
|
||||||
MigrationCommandListBuilder builder,
|
MigrationCommandListBuilder builder,
|
||||||
ISqlGenerationHelper sqlGenerationHelper,
|
ISqlGenerationHelper sqlGenerationHelper,
|
||||||
List<MigrationCommand> addCmds
|
List<MigrationCommand> addCmds
|
||||||
) where TShardingDContext:DbContext,IShardingDbContext
|
)
|
||||||
{
|
{
|
||||||
var migrationCommands = (List<MigrationCommand>) builder.GetFieldValue("_commands");
|
var migrationCommands = (List<MigrationCommand>) builder.GetFieldValue("_commands");
|
||||||
addCmds.ForEach(aAddCmd =>
|
var shardingMigrationManager = shardingRuntimeContext.GetRequiredService<IShardingMigrationManager>();
|
||||||
|
var virtualDataSource = shardingRuntimeContext.GetRequiredService<IVirtualDataSource>();
|
||||||
|
if (shardingMigrationManager.Current == null||shardingMigrationManager.Current.CurrentDataSourceName==virtualDataSource.DefaultDataSourceName)
|
||||||
{
|
{
|
||||||
var shardingCmds = BuildShardingCmds<TShardingDContext>(shardingRuntimeContext,operation, aAddCmd.CommandText, sqlGenerationHelper);
|
addCmds.ForEach(aAddCmd =>
|
||||||
if (shardingCmds.IsNotEmpty())
|
|
||||||
{
|
{
|
||||||
migrationCommands.Remove(aAddCmd);
|
var shardingCmds = BuildShardingCmds(shardingRuntimeContext,operation, aAddCmd.CommandText, sqlGenerationHelper);
|
||||||
//针对builder的原始表进行移除
|
if (shardingCmds.IsNotEmpty())
|
||||||
shardingCmds.ForEach(aShardingCmd =>
|
|
||||||
{
|
{
|
||||||
builder.Append(aShardingCmd)
|
migrationCommands.Remove(aAddCmd);
|
||||||
.EndCommand();
|
//针对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<string> BuildShardingCmds<TShardingDContext>(IShardingRuntimeContext shardingRuntimeContext,MigrationOperation operation, string sourceCmd, ISqlGenerationHelper sqlGenerationHelper)
|
private static List<string> BuildShardingCmds(IShardingRuntimeContext shardingRuntimeContext,MigrationOperation operation, string sourceCmd, ISqlGenerationHelper sqlGenerationHelper)
|
||||||
where TShardingDContext : DbContext, IShardingDbContext
|
|
||||||
{
|
{
|
||||||
//所有MigrationOperation定义
|
//所有MigrationOperation定义
|
||||||
//https://github.com/dotnet/efcore/tree/b970bf29a46521f40862a01db9e276e6448d3cb0/src/EFCore.Relational/Migrations/Operations
|
//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);
|
return string.Format("^({0})$|^({0}_.*?)$|^(.*?_{0}_.*?)$|^(.*?_{0})$", absTableName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
private static (MigrationResultEnum migrationResult,List<string>) 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<string, List<string>> _existsShardingTables
|
||||||
|
// = Cache.ServiceProvider.GetService<ShardingContainer>().ExistsShardingTables;
|
||||||
|
List<string> resList = new List<string>();
|
||||||
|
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<KeyValuePair<string, List<string>>, 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(
|
private static List<(string sourceName, string targetName)> GetReplaceGroups(
|
||||||
MigrationOperation operation, string sourceTableName, string targetTableName)
|
MigrationOperation operation, string sourceTableName, string targetTableName)
|
||||||
{
|
{
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
namespace ShardingCore.Helpers
|
||||||
|
{
|
||||||
|
public enum MigrationResultEnum
|
||||||
|
{
|
||||||
|
OtherCommand,
|
||||||
|
DataSourceTableCommand,
|
||||||
|
TableCommand
|
||||||
|
}
|
||||||
|
}
|
|
@ -29,6 +29,8 @@ using ShardingCore.Core.DbContextCreator;
|
||||||
using ShardingCore.Core.QueryTrackers;
|
using ShardingCore.Core.QueryTrackers;
|
||||||
using ShardingCore.Core.RuntimeContexts;
|
using ShardingCore.Core.RuntimeContexts;
|
||||||
using ShardingCore.Core.ShardingConfigurations.ConfigBuilders;
|
using ShardingCore.Core.ShardingConfigurations.ConfigBuilders;
|
||||||
|
using ShardingCore.Core.ShardingMigrations;
|
||||||
|
using ShardingCore.Core.ShardingMigrations.Abstractions;
|
||||||
using ShardingCore.Core.UnionAllMergeShardingProviders;
|
using ShardingCore.Core.UnionAllMergeShardingProviders;
|
||||||
using ShardingCore.Core.UnionAllMergeShardingProviders.Abstractions;
|
using ShardingCore.Core.UnionAllMergeShardingProviders.Abstractions;
|
||||||
using ShardingCore.Core.VirtualDatabase.VirtualDataSources.Abstractions;
|
using ShardingCore.Core.VirtualDatabase.VirtualDataSources.Abstractions;
|
||||||
|
@ -144,6 +146,10 @@ namespace ShardingCore
|
||||||
services.TryAddSingleton<IQueryableRewriteEngine, QueryableRewriteEngine>();
|
services.TryAddSingleton<IQueryableRewriteEngine, QueryableRewriteEngine>();
|
||||||
services.TryAddSingleton<IQueryableOptimizeEngine, QueryableOptimizeEngine>();
|
services.TryAddSingleton<IQueryableOptimizeEngine, QueryableOptimizeEngine>();
|
||||||
|
|
||||||
|
//migration manage
|
||||||
|
services.TryAddSingleton<IShardingMigrationAccessor, ShardingMigrationAccessor>();
|
||||||
|
services.TryAddSingleton<IShardingMigrationManager, ShardingMigrationManager>();
|
||||||
|
|
||||||
//route manage
|
//route manage
|
||||||
services.TryAddSingleton<IShardingRouteManager, ShardingRouteManager>();
|
services.TryAddSingleton<IShardingRouteManager, ShardingRouteManager>();
|
||||||
services.TryAddSingleton<IShardingRouteAccessor, ShardingRouteAccessor>();
|
services.TryAddSingleton<IShardingRouteAccessor, ShardingRouteAccessor>();
|
||||||
|
@ -151,6 +157,7 @@ namespace ShardingCore
|
||||||
//sharding page
|
//sharding page
|
||||||
services.TryAddSingleton<IShardingPageManager, ShardingPageManager>();
|
services.TryAddSingleton<IShardingPageManager, ShardingPageManager>();
|
||||||
services.TryAddSingleton<IShardingPageAccessor, ShardingPageAccessor>();
|
services.TryAddSingleton<IShardingPageAccessor, ShardingPageAccessor>();
|
||||||
|
|
||||||
services.TryAddSingleton<IShardingBootstrapper, ShardingBootstrapper>();
|
services.TryAddSingleton<IShardingBootstrapper, ShardingBootstrapper>();
|
||||||
services.TryAddSingleton<IUnionAllMergeManager, UnionAllMergeManager>();
|
services.TryAddSingleton<IUnionAllMergeManager, UnionAllMergeManager>();
|
||||||
services.TryAddSingleton<IUnionAllMergeAccessor, UnionAllMergeAccessor>();
|
services.TryAddSingleton<IUnionAllMergeAccessor, UnionAllMergeAccessor>();
|
||||||
|
|
Loading…
Reference in New Issue