diff --git a/samples/Sample.Migrations/Startup.cs b/samples/Sample.Migrations/Startup.cs index 2bc6af43..b433d501 100644 --- a/samples/Sample.Migrations/Startup.cs +++ b/samples/Sample.Migrations/Startup.cs @@ -14,6 +14,7 @@ using Microsoft.EntityFrameworkCore.Migrations; using Sample.Migrations.EFCores; using ShardingCore; using ShardingCore.Bootstrappers; +using ShardingCore.Core.RuntimeContexts; using ShardingCore.Core.VirtualDatabase.VirtualDataSources.Abstractions; namespace Sample.Migrations @@ -30,7 +31,6 @@ namespace Sample.Migrations // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { - services.AddControllers(); //services.AddDbContext((sp, builder) => diff --git a/samples/Sample.MySql/Controllers/WeatherForecastController.cs b/samples/Sample.MySql/Controllers/WeatherForecastController.cs index b8d4809d..68ad156a 100644 --- a/samples/Sample.MySql/Controllers/WeatherForecastController.cs +++ b/samples/Sample.MySql/Controllers/WeatherForecastController.cs @@ -46,8 +46,8 @@ namespace Sample.MySql.Controllers // Console.WriteLine("------------"); // using (var tran = _defaultTableDbContext.Database.BeginTransaction()) // { - - var resultX = await _defaultTableDbContext.Set() + var sysUserMods = _defaultTableDbContext.Set(); + var resultX = await _defaultTableDbContext.Set() .Where(o => o.Id == "2" || o.Id == "3").FirstOrDefaultAsync(); var resultY = await _defaultTableDbContext.Set().FirstOrDefaultAsync(o => o.Id == "2" || o.Id == "3"); var shardingFirstOrDefaultAsyncxxx = await _defaultTableDbContext.Set().Where(o=>o.Time==DateTime.Now).ToListAsync(); diff --git a/samples/Sample.MySql/Startup.cs b/samples/Sample.MySql/Startup.cs index 2f1ed16c..22e17dc2 100644 --- a/samples/Sample.MySql/Startup.cs +++ b/samples/Sample.MySql/Startup.cs @@ -91,7 +91,7 @@ namespace Sample.MySql }); o.AddDefaultDataSource("ds0", "server=127.0.0.1;port=3306;database=dbdbdx;userid=root;password=root;"); - }).AddShardingCore(); + }).ReplaceService().AddShardingCore(); services.AddSingleton(sp => { Stopwatch stopwatch = Stopwatch.StartNew(); @@ -196,21 +196,21 @@ namespace Sample.MySql // var shardingRuntimeContext = app.ApplicationServices.GetRequiredService(); // var entityMetadataManager = shardingRuntimeContext.GetEntityMetadataManager(); // var entityMetadata = entityMetadataManager.TryGet(); - // using (var scope = app.ApplicationServices.CreateScope()) - // { - // var defaultShardingDbContext = scope.ServiceProvider.GetService(); - // // if (defaultShardingDbContext.Database.GetPendingMigrations().Any()) - // { - // try - // { - // - // defaultShardingDbContext.Database.Migrate(); - // } - // catch (Exception e) - // { - // } - // } - // } + using (var scope = app.ApplicationServices.CreateScope()) + { + var defaultShardingDbContext = scope.ServiceProvider.GetService(); + // if (defaultShardingDbContext.Database.GetPendingMigrations().Any()) + { + try + { + + defaultShardingDbContext.Database.Migrate(); + } + catch (Exception e) + { + } + } + } // using (var scope = app.ApplicationServices.CreateScope()) // { // var defaultShardingDbContext = scope.ServiceProvider.GetService(); diff --git a/samples/Sample.SqlServer/Startup.cs b/samples/Sample.SqlServer/Startup.cs index ad70c7c4..97bf7f84 100644 --- a/samples/Sample.SqlServer/Startup.cs +++ b/samples/Sample.SqlServer/Startup.cs @@ -10,6 +10,8 @@ using ShardingCore; using System; using System.Collections.Generic; using System.Diagnostics; +using ShardingCore.Core.RuntimeContexts; +using ShardingCore.Extensions; using ShardingCore.Helpers; using ShardingCore.Sharding.ReadWriteConfigurations; @@ -32,7 +34,6 @@ namespace Sample.SqlServer { services.AddControllers(); //services.AddDbContext(o => o.UseSqlServer("Data Source=localhost;Initial Catalog=ShardingCoreDBxx3;Integrated Security=True")); - services.AddShardingDbContext() .UseRouteConfig(o => { diff --git a/src/ShardingCore/Bootstrappers/IShardingInitializer.cs b/src/ShardingCore/Bootstrappers/IShardingInitializer.cs index 5d9373e3..825de39b 100644 --- a/src/ShardingCore/Bootstrappers/IShardingInitializer.cs +++ b/src/ShardingCore/Bootstrappers/IShardingInitializer.cs @@ -1,9 +1,10 @@ namespace ShardingCore.Bootstrappers { - + /// + /// 分片初始化器主要用来初始化元数据信息和平行表 + /// internal interface IShardingInitializer { - /// /// 初始化 /// diff --git a/src/ShardingCore/Core/DbContextCreator/ShardingDbContextOptions.cs b/src/ShardingCore/Core/DbContextCreator/ShardingDbContextOptions.cs index da63b6ee..3a882190 100644 --- a/src/ShardingCore/Core/DbContextCreator/ShardingDbContextOptions.cs +++ b/src/ShardingCore/Core/DbContextCreator/ShardingDbContextOptions.cs @@ -5,12 +5,9 @@ using ShardingCore.Core.VirtualRoutes.TableRoutes.RouteTails.Abstractions; namespace ShardingCore.Core.DbContextCreator { - /* - * @Author: xjm - * @Description: - * @Date: Wednesday, 16 December 2020 16:15:43 - * @Email: 326308290@qq.com - */ + /// + /// 用来实现dbcontext的创建,将RouteTail和DbContextOptions封装到一起 + /// public class ShardingDbContextOptions { public ShardingDbContextOptions(DbContextOptions dbContextOptions, IRouteTail routeTail) @@ -19,7 +16,13 @@ namespace ShardingCore.Core.DbContextCreator DbContextOptions = dbContextOptions; } + /// + /// 用来告诉ShardingCore创建的DbContext是什么后缀 + /// public IRouteTail RouteTail{ get; } + /// + /// 用来创建DbContext + /// public DbContextOptions DbContextOptions { get; } } } \ No newline at end of file diff --git a/src/ShardingCore/Core/Internal/MultiEnumerator.cs b/src/ShardingCore/Core/Internal/MultiEnumerator.cs new file mode 100644 index 00000000..6d37247a --- /dev/null +++ b/src/ShardingCore/Core/Internal/MultiEnumerator.cs @@ -0,0 +1,58 @@ +using System.Collections; +using System.Collections.Generic; +using System.Linq; + +namespace ShardingCore.Core.Internal +{ + + public class MultiEnumerator:IEnumerator + { + private readonly List> _enumerators; + private int index; + private readonly int _enumeratorsCount; + + public MultiEnumerator(IEnumerable> enumerators) + { + _enumerators = enumerators.ToList(); + _enumeratorsCount = _enumerators.Count; + index = 0; + } + public bool MoveNext() + { + if (_enumeratorsCount == 0) + { + return false; + } + + if (index >= _enumeratorsCount) + { + return false; + } + + while (index < _enumeratorsCount) + { + var moveNext = _enumerators[index].MoveNext(); + if (moveNext) + { + return true; + } + index++; + } + return false; + } + + public void Reset() + { + throw new System.NotImplementedException(); + } + + public TEntity Current => _enumerators[index].Current; + + object IEnumerator.Current => Current; + + public void Dispose() + { + _enumerators.Clear(); + } + } +} \ No newline at end of file diff --git a/src/ShardingCore/Core/ShardingConfigurations/ShardingConfigOptions.cs b/src/ShardingCore/Core/ShardingConfigurations/ShardingConfigOptions.cs index 0c9a2857..ced9db20 100644 --- a/src/ShardingCore/Core/ShardingConfigurations/ShardingConfigOptions.cs +++ b/src/ShardingCore/Core/ShardingConfigurations/ShardingConfigOptions.cs @@ -7,6 +7,9 @@ using ShardingCore.Core.ServiceProviders; namespace ShardingCore.Core.ShardingConfigurations { + /// + /// 分片配置 + /// public class ShardingConfigOptions { /// diff --git a/src/ShardingCore/EFCores/ChangeTrackers/ShardingChangeTracker.cs b/src/ShardingCore/EFCores/ChangeTrackers/ShardingChangeTracker.cs new file mode 100644 index 00000000..d5a551e8 --- /dev/null +++ b/src/ShardingCore/EFCores/ChangeTrackers/ShardingChangeTracker.cs @@ -0,0 +1,148 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.ChangeTracking; +using Microsoft.EntityFrameworkCore.ChangeTracking.Internal; +using Microsoft.EntityFrameworkCore.Metadata; +using ShardingCore.Sharding.Abstractions; + +namespace ShardingCore.EFCores.ChangeTrackers +{ + public class ShardingChangeTracker : ChangeTracker + { + private readonly DbContext _dbContext; + + public ShardingChangeTracker(DbContext context, IStateManager stateManager, IChangeDetector changeDetector, + IModel model, IEntityEntryGraphIterator graphIterator) : base(context, stateManager, changeDetector, model, + graphIterator) + { + _dbContext = context; + } +#if !EFCORE2 && !EFCORE3 && !EFCORE5 && !EFCORE6 + 1 +#endif + + public override bool HasChanges() + { + if (_dbContext is ICurrentDbContextDiscover currentDbContextDiscover) + { + return currentDbContextDiscover.GetCurrentDbContexts().Any(o => + o.Value.GetCurrentContexts().Any(r => r.Value.ChangeTracker.HasChanges())); + } + + return base.HasChanges(); + } + + public override IEnumerable Entries() + { + if (_dbContext is ICurrentDbContextDiscover currentDbContextDiscover) + { + return currentDbContextDiscover.GetCurrentDbContexts().SelectMany(o => + o.Value.GetCurrentContexts().SelectMany(cd => cd.Value.ChangeTracker.Entries())); + } + + return base.Entries(); + } + + public override IEnumerable> Entries() + { + if (_dbContext is ICurrentDbContextDiscover currentDbContextDiscover) + { + return currentDbContextDiscover.GetCurrentDbContexts().SelectMany(o => + o.Value.GetCurrentContexts().SelectMany(cd => cd.Value.ChangeTracker.Entries())); + } + + return base.Entries(); + } + + public override void DetectChanges() + { + if (_dbContext is ICurrentDbContextDiscover) + { + Do(c => c.DetectChanges()); + return; + } + base.DetectChanges(); + } + + public override void AcceptAllChanges() + { + if (_dbContext is ICurrentDbContextDiscover) + { + Do(c => c.AcceptAllChanges()); + return; + } + base.AcceptAllChanges(); + } + + private void Do(Action action) + { + var dataSourceDbContexts = ((ICurrentDbContextDiscover)_dbContext).GetCurrentDbContexts(); + foreach (var dataSourceDbContext in dataSourceDbContexts) + { + var currentContexts = dataSourceDbContext.Value.GetCurrentContexts(); + foreach (var keyValuePair in currentContexts) + { + action(keyValuePair.Value.ChangeTracker); + } + } + } + + public override void TrackGraph(object rootEntity, Action callback) + { + if (_dbContext is ICurrentDbContextDiscover) + { + Do(c => c.TrackGraph(rootEntity,callback)); + return; + } + base.TrackGraph(rootEntity, callback); + } + +#if !EFCORE2 + public override void TrackGraph(object rootEntity, TState state, Func, bool> callback) where TState : default + { + if (_dbContext is ICurrentDbContextDiscover) + { + Do(c => c.TrackGraph(rootEntity,state,callback)); + return; + } + base.TrackGraph(rootEntity, state, callback); + } + + public override void CascadeChanges() + { + if (_dbContext is ICurrentDbContextDiscover) + { + Do(c => c.CascadeChanges()); + return; + } + base.CascadeChanges(); + } + +#endif +#if !EFCORE2 && !EFCORE3 + public override void Clear() + { + if (_dbContext is ICurrentDbContextDiscover) + { + Do(c => c.Clear()); + return; + } + base.Clear(); + } +#endif + +#if EFCORE2 + public override void TrackGraph(object rootEntity, TState state, Func callback) + { + if (_dbContext is ICurrentDbContextDiscover) + { + Do(c => c.TrackGraph(rootEntity,state,callback)); + return; + } + base.TrackGraph(rootEntity, state, callback); + } +#endif + } +} \ No newline at end of file diff --git a/src/ShardingCore/EFCores/ChangeTrackers/ShardingChangeTrackerFactory.cs b/src/ShardingCore/EFCores/ChangeTrackers/ShardingChangeTrackerFactory.cs new file mode 100644 index 00000000..370cab0b --- /dev/null +++ b/src/ShardingCore/EFCores/ChangeTrackers/ShardingChangeTrackerFactory.cs @@ -0,0 +1,33 @@ +using Microsoft.EntityFrameworkCore.ChangeTracking; +using Microsoft.EntityFrameworkCore.ChangeTracking.Internal; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Internal; +using Microsoft.EntityFrameworkCore.Metadata; + +namespace ShardingCore.EFCores.ChangeTrackers +{ + + public class ShardingChangeTrackerFactory:ChangeTrackerFactory + { + private readonly ICurrentDbContext _currentContext; + private readonly IStateManager _stateManager; + private readonly IChangeDetector _changeDetector; + private readonly IModel _model; + private readonly IEntityEntryGraphIterator _graphIterator; + + public ShardingChangeTrackerFactory(ICurrentDbContext currentContext, IStateManager stateManager, IChangeDetector changeDetector, IModel model, IEntityEntryGraphIterator graphIterator) : base(currentContext, stateManager, changeDetector, model, graphIterator) + { + _currentContext = currentContext; + _stateManager = stateManager; + _changeDetector = changeDetector; + _model = model; + _graphIterator = graphIterator; + } + public ChangeTracker Create() + { + return new ShardingChangeTracker(_currentContext.Context, _stateManager, _changeDetector, _model, + _graphIterator); + } + + } +} diff --git a/src/ShardingCore/EFCores/MigrateUnit.cs b/src/ShardingCore/EFCores/MigrateUnit.cs index e42f45fc..60b8855f 100644 --- a/src/ShardingCore/EFCores/MigrateUnit.cs +++ b/src/ShardingCore/EFCores/MigrateUnit.cs @@ -2,7 +2,9 @@ using Microsoft.EntityFrameworkCore; namespace ShardingCore.EFCores { - + /// + /// 迁移执行单元 + /// public class MigrateUnit { public MigrateUnit(DbContext shellDbContext, string dataSourceName) @@ -10,8 +12,13 @@ namespace ShardingCore.EFCores ShellDbContext = shellDbContext; DataSourceName = dataSourceName; } - + /// + /// 壳dbcontext + /// public DbContext ShellDbContext { get; } + /// + /// 数据源名称 + /// public string DataSourceName { get; } } } diff --git a/src/ShardingCore/EFCores/ShardingChangeTracker.cs b/src/ShardingCore/EFCores/ShardingChangeTracker.cs deleted file mode 100644 index 83d7a7b0..00000000 --- a/src/ShardingCore/EFCores/ShardingChangeTracker.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.ChangeTracking; -using Microsoft.EntityFrameworkCore.ChangeTracking.Internal; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Metadata; -using ShardingCore.Exceptions; -using ShardingCore.Sharding.Abstractions; - -namespace ShardingCore.EFCores -{ - public class ShardingChangeTracker: ChangeTracker - { - private readonly ICurrentDbContextDiscover _contextDiscover; - - public ShardingChangeTracker(DbContext context, IStateManager stateManager, IChangeDetector changeDetector, IModel model, IEntityEntryGraphIterator graphIterator) : base(context, stateManager, changeDetector, model, graphIterator) - { - _contextDiscover = context as ICurrentDbContextDiscover?? throw new ShardingCoreNotSupportException($"{context.GetType()} not impl {nameof(ICurrentDbContextDiscover)}"); - } - - public override bool HasChanges() - { - return _contextDiscover.GetCurrentDbContexts().Any(o => - o.Value.GetCurrentContexts().Any(r => r.Value.ChangeTracker.HasChanges())); - } - - public override IEnumerable Entries() - { - return _contextDiscover.GetCurrentDbContexts().SelectMany(o => o.Value.GetCurrentContexts().SelectMany(cd=>cd.Value.ChangeTracker.Entries())); - } - - public override IEnumerable> Entries() - { - return _contextDiscover.GetCurrentDbContexts().SelectMany(o => o.Value.GetCurrentContexts().SelectMany(cd=>cd.Value.ChangeTracker.Entries())); - } - } -} diff --git a/src/ShardingCore/EFCores/ShardingInternalDbSet.cs b/src/ShardingCore/EFCores/ShardingInternalDbSet.cs index 55351581..aa148579 100644 --- a/src/ShardingCore/EFCores/ShardingInternalDbSet.cs +++ b/src/ShardingCore/EFCores/ShardingInternalDbSet.cs @@ -31,6 +31,7 @@ namespace ShardingCore.EFCores { private readonly IShardingDbContext _context; private readonly IShardingRuntimeContext _shardingRuntimeContext; + private LocalView? _localView; #if EFCORE5 || EFCORE6 @@ -63,6 +64,19 @@ namespace ShardingCore.EFCores } } + public override LocalView Local + { + get + { + + if (((DbContext)_context).ChangeTracker.AutoDetectChangesEnabled) + { + ((DbContext)_context).ChangeTracker.DetectChanges(); + } + + return _localView ??= new ShardingLocalView(this); + } + } private ITableRouteManager _tableRouteManager; protected ITableRouteManager TableRouteManager diff --git a/src/ShardingCore/EFCores/ShardingLocalView.cs b/src/ShardingCore/EFCores/ShardingLocalView.cs new file mode 100644 index 00000000..fdccb1f4 --- /dev/null +++ b/src/ShardingCore/EFCores/ShardingLocalView.cs @@ -0,0 +1,33 @@ +using System.Collections.Generic; +using System.Linq; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.ChangeTracking; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Internal; +using ShardingCore.Core.Internal; +using ShardingCore.Sharding.Abstractions; + +namespace ShardingCore.EFCores +{ + + public class ShardingLocalView:LocalView where TEntity : class + { + private readonly DbContext _dbContext; + + public ShardingLocalView(DbSet set) : base(set) + { + _dbContext = set.GetService().Context; + } + + public override IEnumerator GetEnumerator() + { + if (_dbContext is ICurrentDbContextDiscover currentDbContextDiscover) + { + var dataSourceDbContexts = currentDbContextDiscover.GetCurrentDbContexts(); + var enumerators = dataSourceDbContexts.SelectMany(o => o.Value.GetCurrentContexts().Select(cd=>cd.Value.Set().Local.GetEnumerator())); + return new MultiEnumerator(enumerators); + } + return base.GetEnumerator(); + } + } +} diff --git a/src/ShardingCore/Jobs/Abstaractions/IJob.cs b/src/ShardingCore/Jobs/Abstaractions/IJob.cs index 1394fdb6..dc471be7 100644 --- a/src/ShardingCore/Jobs/Abstaractions/IJob.cs +++ b/src/ShardingCore/Jobs/Abstaractions/IJob.cs @@ -4,11 +4,30 @@ using Microsoft.Extensions.Logging; namespace ShardingCore.Jobs.Abstaractions { + /// + /// 任务接口对应的路由实现后可以加入到默认的内存队列中定时执行 + /// public interface IJob { + /// + /// 任务名称 + /// string JobName { get; } + /// + /// 执行的周期 + /// + /// string[] GetJobCronExpressions(); + /// + /// 如何执行任务 + /// + /// Task ExecuteAsync(); + /// + /// 任务是否需要添加到默认的任务里面 + /// 当然也可以自行处理 + /// + /// bool AppendJob(); } } diff --git a/src/ShardingCore/Sharding/AbstractShardingDbContext.cs b/src/ShardingCore/Sharding/AbstractShardingDbContext.cs index 440bd9f7..6e927391 100644 --- a/src/ShardingCore/Sharding/AbstractShardingDbContext.cs +++ b/src/ShardingCore/Sharding/AbstractShardingDbContext.cs @@ -25,7 +25,7 @@ namespace ShardingCore.Sharding /// /// 分表分库的dbcontext /// - public abstract class AbstractShardingDbContext : DbContext, IShardingDbContext, ISupportShardingReadWrite//,ICurrentDbContextDiscover + public abstract class AbstractShardingDbContext : DbContext, IShardingDbContext, ISupportShardingReadWrite,ICurrentDbContextDiscover { protected IShardingDbContextExecutor ShardingDbContextExecutor { get; } @@ -501,10 +501,10 @@ namespace ShardingCore.Sharding ShardingDbContextExecutor.Commit(); } - //public IDictionary GetCurrentDbContexts() - //{ - // return ShardingDbContextExecutor.GetCurrentDbContexts(); - //} + public IDictionary GetCurrentDbContexts() + { + return ShardingDbContextExecutor.GetCurrentDbContexts(); + } } } \ No newline at end of file diff --git a/src/ShardingCore/ShardingCoreExtension.cs b/src/ShardingCore/ShardingCoreExtension.cs index 54741ad3..101a28a7 100644 --- a/src/ShardingCore/ShardingCoreExtension.cs +++ b/src/ShardingCore/ShardingCoreExtension.cs @@ -27,6 +27,7 @@ using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore.ChangeTracking.Internal; using Microsoft.EntityFrameworkCore.Migrations; using ShardingCore.Bootstrappers; using ShardingCore.Core.DbContextCreator; @@ -42,6 +43,7 @@ using ShardingCore.Core.VirtualRoutes.Abstractions; using ShardingCore.Core.VirtualRoutes.DataSourceRoutes; using ShardingCore.Core.VirtualRoutes.TableRoutes; using ShardingCore.DynamicDataSources; +using ShardingCore.EFCores.ChangeTrackers; using ShardingCore.Exceptions; using ShardingCore.Extensions; using ShardingCore.Sharding.MergeContexts; @@ -143,7 +145,7 @@ namespace ShardingCore dbContextOptionsBuilder.UseDefaultSharding(shardingRuntimeContext); } - public static void UseDefaultSharding(this DbContextOptionsBuilder dbContextOptionsBuilder, + public static DbContextOptionsBuilder UseDefaultSharding(this DbContextOptionsBuilder dbContextOptionsBuilder, IShardingRuntimeContext shardingRuntimeContext) where TShardingDbContext : DbContext, IShardingDbContext { var shardingConfigOptions = shardingRuntimeContext.GetShardingConfigOptions(); @@ -156,6 +158,7 @@ namespace ShardingCore .UseSharding(shardingRuntimeContext); virtualDataSource.ConfigurationParams.UseShellDbContextOptionBuilder(contextOptionsBuilder); + return dbContextOptionsBuilder; } internal static IServiceCollection AddInternalShardingCore(this IServiceCollection services) @@ -240,6 +243,7 @@ namespace ShardingCore return optionsBuilder.UseShardingWrapMark().UseShardingOptions(shardingRuntimeContext) .ReplaceService() .ReplaceService() + .ReplaceService() .ReplaceService>() .ReplaceService