From 96e785ac107c8726dce2c0608c4199eb2f7c24f3 Mon Sep 17 00:00:00 2001 From: xuejiaming <326308290@qq.com> Date: Fri, 23 Dec 2022 09:10:01 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0aop=E9=92=88=E5=AF=B9abpvnext?= =?UTF-8?q?=E7=9A=84=E5=A4=84=E7=90=86[#226]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MyShardingExtension.cs | 2 +- .../AbstractShardingAbpDbContext.cs | 460 +----------------- .../EFCores/EFCore7x/ShardingStateManager.cs | 12 +- .../IShardingDbContextExecutor.cs | 16 + .../ShardingDbContextExecutorEventArgs.cs | 55 +++ .../ShardingDbContextExecutor.cs | 38 +- 6 files changed, 131 insertions(+), 452 deletions(-) create mode 100644 src/ShardingCore/Sharding/Abstractions/ShardingDbContextExecutorEventArgs.cs diff --git a/samples/Sample.AutoCreateIfPresent/MyShardingExtension.cs b/samples/Sample.AutoCreateIfPresent/MyShardingExtension.cs index 07595869..47d54649 100644 --- a/samples/Sample.AutoCreateIfPresent/MyShardingExtension.cs +++ b/samples/Sample.AutoCreateIfPresent/MyShardingExtension.cs @@ -44,7 +44,7 @@ public static class MyShardingExtension new Dictionary>() { { - shardingDbContext.CreateGenericDbContext(entitiesArray[0]), + shardingDbContext.GetShardingExecutor().CreateGenericDbContext(entitiesArray[0]), entitiesArray } } diff --git a/samples/Samples.AbpSharding/AbstractShardingAbpDbContext.cs b/samples/Samples.AbpSharding/AbstractShardingAbpDbContext.cs index 27907862..89eb4735 100644 --- a/samples/Samples.AbpSharding/AbstractShardingAbpDbContext.cs +++ b/samples/Samples.AbpSharding/AbstractShardingAbpDbContext.cs @@ -34,48 +34,25 @@ namespace Samples.AbpSharding if (wrapOptionsExtension != null) { _shardingDbContextExecutor = new ShardingDbContextExecutor(this); + _shardingDbContextExecutor.EntityCreateDbContextBefore += (sender, args) => + { + CheckAndSetShardingKeyThatSupportAutoCreate(args.Entity); + }; + _shardingDbContextExecutor.CreateDbContextAfter += (sender, args) => + { + var shardingDbContextExecutor = (IShardingDbContextExecutor)sender; + var argsDbContext = args.DbContext; + var shellDbContext = shardingDbContextExecutor.GetShellDbContext(); + + if (argsDbContext is AbpDbContext abpDbContext&&shellDbContext is AbpDbContext abpShellDbContext && + abpDbContext.LazyServiceProvider == null) + { + abpDbContext.LazyServiceProvider = abpShellDbContext.LazyServiceProvider; + } + }; } } - /// - /// 是否是真正的执行者 - /// - private bool isExecutor => _shardingDbContextExecutor == null; - - //public void ShardingUpgrade() - //{ - // //IsExecutor = true; - //} - - public DbContext GetDbContext(string dataSourceName, CreateDbContextStrategyEnum strategy, IRouteTail routeTail) - { - var dbContext = _shardingDbContextExecutor.CreateDbContext(strategy, dataSourceName, routeTail); - if (dbContext is AbpDbContext abpDbContext) - { - abpDbContext.LazyServiceProvider = this.LazyServiceProvider; - } - - return dbContext; - } - - /// - /// 根据对象创建通用的dbcontext - /// - /// - /// - /// - public DbContext CreateGenericDbContext(TEntity entity) where TEntity : class - { - CheckAndSetShardingKeyThatSupportAutoCreate(entity); - var dbContext = _shardingDbContextExecutor.CreateGenericDbContext(entity); - if (dbContext is AbpDbContext abpDbContext && abpDbContext.LazyServiceProvider == null) - { - abpDbContext.LazyServiceProvider = this.LazyServiceProvider; - } - - return dbContext; - } - public IShardingDbContextExecutor GetShardingExecutor() { return _shardingDbContextExecutor; @@ -118,416 +95,19 @@ namespace Samples.AbpSharding } } - - public override EntityEntry Add(object entity) - { - if (isExecutor) - base.Add(entity); - return CreateGenericDbContext(entity).Add(entity); - } - - public override EntityEntry Add(TEntity entity) - { - if (isExecutor) - return base.Add(entity); - return CreateGenericDbContext(entity).Add(entity); - } - - - public override ValueTask> AddAsync(TEntity entity, CancellationToken cancellationToken = new CancellationToken()) - { - if (isExecutor) - return base.AddAsync(entity, cancellationToken); - return CreateGenericDbContext(entity).AddAsync(entity, cancellationToken); - } - - public override ValueTask AddAsync(object entity, CancellationToken cancellationToken = new CancellationToken()) - { - if (isExecutor) - return base.AddAsync(entity, cancellationToken); - return CreateGenericDbContext(entity).AddAsync(entity, cancellationToken); - } - - public override void AddRange(params object[] entities) - { - if (isExecutor) - { - base.AddRange(entities); - return; - } - var groups = entities.Select(o => - { - var dbContext = CreateGenericDbContext(o); - return new - { - DbContext = dbContext, - Entity = o - }; - }).GroupBy(g => g.DbContext); - - foreach (var group in groups) - { - group.Key.AddRange(group.Select(o => o.Entity)); - } - } - public override void AddRange(IEnumerable entities) - { - if (isExecutor) - { - base.AddRange(entities); - return; - } - var groups = entities.Select(o => - { - var dbContext = CreateGenericDbContext(o); - return new - { - DbContext = dbContext, - Entity = o - }; - }).GroupBy(g => g.DbContext); - - foreach (var group in groups) - { - group.Key.AddRange(group.Select(o => o.Entity)); - } - } - - public override async Task AddRangeAsync(params object[] entities) - { - if (isExecutor) - { - await base.AddRangeAsync(entities); - return; - } - var groups = entities.Select(o => - { - var dbContext = CreateGenericDbContext(o); - return new - { - DbContext = dbContext, - Entity = o - }; - }).GroupBy(g => g.DbContext); - - foreach (var group in groups) - { - await group.Key.AddRangeAsync(group.Select(o => o.Entity)); - } - } - - public override async Task AddRangeAsync(IEnumerable entities, CancellationToken cancellationToken = new CancellationToken()) - { - if (isExecutor) - { - await base.AddRangeAsync(entities, cancellationToken); - return; - } - var groups = entities.Select(o => - { - var dbContext = CreateGenericDbContext(o); - return new - { - DbContext = dbContext, - Entity = o - }; - }).GroupBy(g => g.DbContext); - - foreach (var group in groups) - { - await group.Key.AddRangeAsync(group.Select(o => o.Entity)); - } - } - - public override EntityEntry Attach(TEntity entity) - { - if (isExecutor) - return base.Attach(entity); - return CreateGenericDbContext(entity).Attach(entity); - } - - public override EntityEntry Attach(object entity) - { - if (isExecutor) - return base.Attach(entity); - return CreateGenericDbContext(entity).Attach(entity); - } - - public override void AttachRange(params object[] entities) - { - if (isExecutor) - { - base.AttachRange(entities); - return; - } - var groups = entities.Select(o => - { - var dbContext = CreateGenericDbContext(o); - return new - { - DbContext = dbContext, - Entity = o - }; - }).GroupBy(g => g.DbContext); - - foreach (var group in groups) - { - group.Key.AttachRange(group.Select(o => o.Entity)); - } - } - - public override void AttachRange(IEnumerable entities) - { - if (isExecutor) - { - base.AttachRange(entities); - return; - } - var groups = entities.Select(o => - { - var dbContext = CreateGenericDbContext(o); - return new - { - DbContext = dbContext, - Entity = o - }; - }).GroupBy(g => g.DbContext); - - foreach (var group in groups) - { - group.Key.AttachRange(group.Select(o => o.Entity)); - } - } - - - //public override DatabaseFacade Database => _dbContextCaches.Any() - // ? _dbContextCaches.First().Value.Database - // : GetDbContext(true, string.Empty).Database; - - public override EntityEntry Entry(TEntity entity) - { - if (isExecutor) - return base.Entry(entity); - return CreateGenericDbContext(entity).Entry(entity); - } - - public override EntityEntry Entry(object entity) - { - if (isExecutor) - return base.Entry(entity); - return CreateGenericDbContext(entity).Entry(entity); - } - - public override EntityEntry Update(TEntity entity) - { - if (isExecutor) - return base.Update(entity); - return CreateGenericDbContext(entity).Update(entity); - } - - public override EntityEntry Update(object entity) - { - if (isExecutor) - return base.Update(entity); - return CreateGenericDbContext(entity).Update(entity); - } - - public override void UpdateRange(params object[] entities) - { - if (isExecutor) - { - base.UpdateRange(entities); - return; - } - var groups = entities.Select(o => - { - var dbContext = CreateGenericDbContext(o); - return new - { - DbContext = dbContext, - Entity = o - }; - }).GroupBy(g => g.DbContext); - - foreach (var group in groups) - { - group.Key.UpdateRange(group.Select(o => o.Entity)); - } - } - - public override void UpdateRange(IEnumerable entities) - { - if (isExecutor) - { - base.UpdateRange(entities); - return; - } - var groups = entities.Select(o => - { - var dbContext = CreateGenericDbContext(o); - return new - { - DbContext = dbContext, - Entity = o - }; - }).GroupBy(g => g.DbContext); - - foreach (var group in groups) - { - group.Key.UpdateRange(group.Select(o => o.Entity)); - } - } - - public override EntityEntry Remove(TEntity entity) - { - if (isExecutor) - return base.Remove(entity); - return CreateGenericDbContext(entity).Remove(entity); - } - - public override EntityEntry Remove(object entity) - { - if (isExecutor) - return base.Remove(entity); - return CreateGenericDbContext(entity).Remove(entity); - } - - public override void RemoveRange(params object[] entities) - { - if (isExecutor) - { - base.RemoveRange(entities); - return; - } - var groups = entities.Select(o => - { - var dbContext = CreateGenericDbContext(o); - return new - { - DbContext = dbContext, - Entity = o - }; - }).GroupBy(g => g.DbContext); - - foreach (var group in groups) - { - group.Key.RemoveRange(group.Select(o => o.Entity)); - } - } - - public override void RemoveRange(IEnumerable entities) - { - if (isExecutor) - { - base.RemoveRange(entities); - return; - } - var groups = entities.Select(o => - { - var dbContext = CreateGenericDbContext(o); - return new - { - DbContext = dbContext, - Entity = o - }; - }).GroupBy(g => g.DbContext); - - foreach (var group in groups) - { - group.Key.RemoveRange(group.Select(o => o.Entity)); - } - } - - public override int SaveChanges() - { - - if (isExecutor) - return base.SaveChanges(); - return this.SaveChanges(true); - } - - public override int SaveChanges(bool acceptAllChangesOnSuccess) - { - if (isExecutor) - return base.SaveChanges(acceptAllChangesOnSuccess); - //ApplyShardingConcepts(); - int i = 0; - //如果是内部开的事务就内部自己消化 - if (Database.CurrentTransaction == null && _shardingDbContextExecutor.IsMultiDbContext) - { - using (var tran = Database.BeginTransaction()) - { - i = _shardingDbContextExecutor.SaveChanges(acceptAllChangesOnSuccess); - tran.Commit(); - } - } - else - { - i = _shardingDbContextExecutor.SaveChanges(acceptAllChangesOnSuccess); - } - - return i; - } - - - public override Task SaveChangesAsync(CancellationToken cancellationToken = new CancellationToken()) - { - if (isExecutor) - return base.SaveChangesAsync(cancellationToken); - return this.SaveChangesAsync(true, cancellationToken); - } - - public override async Task SaveChangesAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = new CancellationToken()) - { - if (isExecutor) - return await base.SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken); - //ApplyShardingConcepts(); - int i = 0; - //如果是内部开的事务就内部自己消化 - if (Database.CurrentTransaction == null && _shardingDbContextExecutor.IsMultiDbContext) - { - using (var tran = await Database.BeginTransactionAsync(cancellationToken)) - { - i = await _shardingDbContextExecutor.SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken); - - await tran.CommitAsync(cancellationToken); - } - } - else - { - i = await _shardingDbContextExecutor.SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken); - } - - - return i; - } - public override void Dispose() { - - if (isExecutor) - { - base.Dispose(); - } - else - { - _shardingDbContextExecutor.Dispose(); - base.Dispose(); - } + _shardingDbContextExecutor?.Dispose(); + base.Dispose(); } public override async ValueTask DisposeAsync() { - if (isExecutor) - { - await base.DisposeAsync(); - } - else + if (_shardingDbContextExecutor != null) { await _shardingDbContextExecutor.DisposeAsync(); - - await base.DisposeAsync(); } + await base.DisposeAsync(); } } } \ No newline at end of file diff --git a/src/ShardingCore/EFCores/EFCore7x/ShardingStateManager.cs b/src/ShardingCore/EFCores/EFCore7x/ShardingStateManager.cs index 474808e0..154d9a8f 100644 --- a/src/ShardingCore/EFCores/EFCore7x/ShardingStateManager.cs +++ b/src/ShardingCore/EFCores/EFCore7x/ShardingStateManager.cs @@ -15,13 +15,11 @@ namespace ShardingCore.EFCores { public class ShardingStateManager:StateManager { - private readonly DbContext _currentDbContext; private readonly IShardingDbContext _currentShardingDbContext; public ShardingStateManager(StateManagerDependencies dependencies) : base(dependencies) { - _currentDbContext=dependencies.CurrentContext.Context; - _currentShardingDbContext = (IShardingDbContext)_currentDbContext; + _currentShardingDbContext = (IShardingDbContext)Context; } public override InternalEntityEntry GetOrCreateEntry(object entity) @@ -69,9 +67,9 @@ namespace ShardingCore.EFCores //ApplyShardingConcepts(); int i = 0; //如果是内部开的事务就内部自己消化 - if (_currentDbContext.Database.AutoTransactionsEnabled&&_currentDbContext.Database.CurrentTransaction==null&&_currentShardingDbContext.GetShardingExecutor().IsMultiDbContext) + if (Context.Database.AutoTransactionsEnabled&&Context.Database.CurrentTransaction==null&&_currentShardingDbContext.GetShardingExecutor().IsMultiDbContext) { - using (var tran = _currentDbContext.Database.BeginTransaction()) + using (var tran = Context.Database.BeginTransaction()) { i = _currentShardingDbContext.GetShardingExecutor().SaveChanges(acceptAllChangesOnSuccess); tran.Commit(); @@ -90,9 +88,9 @@ namespace ShardingCore.EFCores //ApplyShardingConcepts(); int i = 0; //如果是内部开的事务就内部自己消化 - if (_currentDbContext.Database.AutoTransactionsEnabled && _currentDbContext.Database.CurrentTransaction==null && _currentShardingDbContext.GetShardingExecutor().IsMultiDbContext) + if (Context.Database.AutoTransactionsEnabled && Context.Database.CurrentTransaction==null && _currentShardingDbContext.GetShardingExecutor().IsMultiDbContext) { - using (var tran = await _currentDbContext.Database.BeginTransactionAsync(cancellationToken)) + using (var tran = await Context.Database.BeginTransactionAsync(cancellationToken)) { i = await _currentShardingDbContext.GetShardingExecutor().SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken); await tran.CommitAsync(cancellationToken); diff --git a/src/ShardingCore/Sharding/Abstractions/IShardingDbContextExecutor.cs b/src/ShardingCore/Sharding/Abstractions/IShardingDbContextExecutor.cs index af262436..67add0b9 100644 --- a/src/ShardingCore/Sharding/Abstractions/IShardingDbContextExecutor.cs +++ b/src/ShardingCore/Sharding/Abstractions/IShardingDbContextExecutor.cs @@ -23,6 +23,22 @@ namespace ShardingCore.Sharding.Abstractions #endif { + /// + /// 使用对象创建db context的前执行 + /// + event EventHandler EntityCreateDbContextBefore; + /// + /// 使用对象创建db context的后执行 + /// + event EventHandler EntityCreateDbContextAfter; + /// + /// 使用tail创建db context的前执行 + /// + event EventHandler CreateDbContextBefore; + /// + /// 使用tail创建db context的后执行 + /// + event EventHandler CreateDbContextAfter; /// /// has multi db context /// diff --git a/src/ShardingCore/Sharding/Abstractions/ShardingDbContextExecutorEventArgs.cs b/src/ShardingCore/Sharding/Abstractions/ShardingDbContextExecutorEventArgs.cs new file mode 100644 index 00000000..37e12b59 --- /dev/null +++ b/src/ShardingCore/Sharding/Abstractions/ShardingDbContextExecutorEventArgs.cs @@ -0,0 +1,55 @@ +using System; +using Microsoft.EntityFrameworkCore; +using ShardingCore.Core.VirtualRoutes.TableRoutes.RouteTails.Abstractions; + +namespace ShardingCore.Sharding.Abstractions +{ + public class EntityCreateDbContextBeforeEventArgs: EventArgs + { + public object Entity { get; } + + public EntityCreateDbContextBeforeEventArgs(object entity) + { + Entity = entity; + } + } + public class CreateDbContextBeforeEventArgs: EventArgs + { + public CreateDbContextStrategyEnum Strategy { get; } + public string DataSourceName { get; } + public IRouteTail RouteTail { get; } + + public CreateDbContextBeforeEventArgs(CreateDbContextStrategyEnum strategy, string dataSourceName, IRouteTail routeTail) + { + Strategy = strategy; + DataSourceName = dataSourceName; + RouteTail = routeTail; + } + } + public class CreateDbContextAfterEventArgs: EventArgs + { + public CreateDbContextStrategyEnum Strategy { get; } + public string DataSourceName { get; } + public IRouteTail RouteTail { get; } + public DbContext DbContext { get; } + + public CreateDbContextAfterEventArgs(CreateDbContextStrategyEnum strategy, string dataSourceName, IRouteTail routeTail,DbContext dbContext) + { + Strategy = strategy; + DataSourceName = dataSourceName; + RouteTail = routeTail; + DbContext = dbContext; + } + } + public class EntityCreateDbContextAfterEventArgs: EventArgs + { + public object Entity { get; } + public DbContext DbContext { get; } + + public EntityCreateDbContextAfterEventArgs(object entity,DbContext dbContext) + { + Entity = entity; + DbContext = dbContext; + } + } +} diff --git a/src/ShardingCore/Sharding/ShardingDbContextExecutors/ShardingDbContextExecutor.cs b/src/ShardingCore/Sharding/ShardingDbContextExecutors/ShardingDbContextExecutor.cs index d02f8703..5fb4e0a7 100644 --- a/src/ShardingCore/Sharding/ShardingDbContextExecutors/ShardingDbContextExecutor.cs +++ b/src/ShardingCore/Sharding/ShardingDbContextExecutors/ShardingDbContextExecutor.cs @@ -35,6 +35,13 @@ namespace ShardingCore.Sharding.ShardingDbContextExecutors /// public class ShardingDbContextExecutor : IShardingDbContextExecutor { + + + public event EventHandler EntityCreateDbContextBefore; + public event EventHandler EntityCreateDbContextAfter; + public event EventHandler CreateDbContextBefore; + public event EventHandler CreateDbContextAfter; + private readonly ILogger _logger; private readonly DbContext _shardingDbContext; @@ -106,19 +113,29 @@ namespace ShardingCore.Sharding.ShardingDbContextExecutors public DbContext CreateDbContext(CreateDbContextStrategyEnum strategy, string dataSourceName, IRouteTail routeTail) { + if (CreateDbContextBefore != null) + { + CreateDbContextBefore.Invoke(this,new CreateDbContextBeforeEventArgs(strategy,dataSourceName,routeTail)); + } + + DbContext dbContext; if (CreateDbContextStrategyEnum.ShareConnection == strategy) { var dataSourceDbContext = GetDataSourceDbContext(dataSourceName); - return dataSourceDbContext.CreateDbContext(routeTail); + dbContext= dataSourceDbContext.CreateDbContext(routeTail); } else { var parallelDbContextOptions = CreateParallelDbContextOptions(dataSourceName, strategy); - var dbContext = + dbContext = _dbContextCreator.CreateDbContext(_shardingDbContext, parallelDbContextOptions, routeTail); dbContext.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking; - return dbContext; } + if (CreateDbContextAfter != null) + { + CreateDbContextAfter.Invoke(this,new CreateDbContextAfterEventArgs(strategy,dataSourceName,routeTail,dbContext)); + } + return dbContext; } private DbContextOptions CreateParallelDbContextOptions(string dataSourceName, @@ -136,12 +153,25 @@ namespace ShardingCore.Sharding.ShardingDbContextExecutors public DbContext CreateGenericDbContext(TEntity entity) where TEntity : class { + + if (EntityCreateDbContextBefore != null) + { + EntityCreateDbContextBefore.Invoke(this,new EntityCreateDbContextBeforeEventArgs(entity)); + } + var realEntityType = _trackerManager.TranslateEntityType(entity.GetType()); var dataSourceName = GetDataSourceName(entity,realEntityType); var tail = GetTableTail(dataSourceName, entity,realEntityType); - return CreateDbContext(CreateDbContextStrategyEnum.ShareConnection, dataSourceName, + var dbContext = CreateDbContext(CreateDbContextStrategyEnum.ShareConnection, dataSourceName, _routeTailFactory.Create(tail)); + + if (EntityCreateDbContextAfter != null) + { + EntityCreateDbContextAfter.Invoke(this,new EntityCreateDbContextAfterEventArgs(entity,dbContext)); + } + + return dbContext; } public IVirtualDataSource GetVirtualDataSource()