diff --git a/ShardingCore.sln b/ShardingCore.sln index ba5993d6..24850d97 100644 --- a/ShardingCore.sln +++ b/ShardingCore.sln @@ -11,6 +11,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src3x", "src3x", "{62AAE0FE EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ShardingCore.3x", "src3x\ShardingCore.3x\ShardingCore.3x.csproj", "{E0FDBFA9-AE5F-42FB-8A60-4E5D9E7D5414}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src2x", "src2x", "{679E6084-0C45-4807-BFEE-D2FDA44B2188}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ShardingCore.2x", "src2x\ShardingCore.2x\ShardingCore.2x.csproj", "{FB92A4BE-A43E-4755-8132-EC38E9650B80}" +EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{CC2C88C0-65F2-445D-BE78-973B840FE281}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ShardingCore.Test50", "test\ShardingCore.Test50\ShardingCore.Test50.csproj", "{7EE133B6-5A02-41B7-9D89-41D9EA14184E}" @@ -31,7 +35,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Samples.AbpSharding", "samp EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ShardingCore.Test50_3x", "test\ShardingCore.Test50_3x\ShardingCore.Test50_3x.csproj", "{C0A59BB0-F0B8-4AC6-B192-0249E784FC88}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sample.BulkConsole", "samples\Sample.BulkConsole\Sample.BulkConsole.csproj", "{2443CC8B-FB7D-47A7-9663-F3848BB30A36}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ShardingCore.Test50_2x", "test\ShardingCore.Test50_2x\ShardingCore.Test50_2x.csproj", "{6709DD6A-6A44-4A49-BA4D-A50A40102C8B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sample.BulkConsole", "samples\Sample.BulkConsole\Sample.BulkConsole.csproj", "{2443CC8B-FB7D-47A7-9663-F3848BB30A36}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -47,6 +53,10 @@ Global {E0FDBFA9-AE5F-42FB-8A60-4E5D9E7D5414}.Debug|Any CPU.Build.0 = Debug|Any CPU {E0FDBFA9-AE5F-42FB-8A60-4E5D9E7D5414}.Release|Any CPU.ActiveCfg = Release|Any CPU {E0FDBFA9-AE5F-42FB-8A60-4E5D9E7D5414}.Release|Any CPU.Build.0 = Release|Any CPU + {FB92A4BE-A43E-4755-8132-EC38E9650B80}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FB92A4BE-A43E-4755-8132-EC38E9650B80}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FB92A4BE-A43E-4755-8132-EC38E9650B80}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FB92A4BE-A43E-4755-8132-EC38E9650B80}.Release|Any CPU.Build.0 = Release|Any CPU {7EE133B6-5A02-41B7-9D89-41D9EA14184E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {7EE133B6-5A02-41B7-9D89-41D9EA14184E}.Debug|Any CPU.Build.0 = Debug|Any CPU {7EE133B6-5A02-41B7-9D89-41D9EA14184E}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -79,6 +89,10 @@ Global {C0A59BB0-F0B8-4AC6-B192-0249E784FC88}.Debug|Any CPU.Build.0 = Debug|Any CPU {C0A59BB0-F0B8-4AC6-B192-0249E784FC88}.Release|Any CPU.ActiveCfg = Release|Any CPU {C0A59BB0-F0B8-4AC6-B192-0249E784FC88}.Release|Any CPU.Build.0 = Release|Any CPU + {6709DD6A-6A44-4A49-BA4D-A50A40102C8B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6709DD6A-6A44-4A49-BA4D-A50A40102C8B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6709DD6A-6A44-4A49-BA4D-A50A40102C8B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6709DD6A-6A44-4A49-BA4D-A50A40102C8B}.Release|Any CPU.Build.0 = Release|Any CPU {2443CC8B-FB7D-47A7-9663-F3848BB30A36}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {2443CC8B-FB7D-47A7-9663-F3848BB30A36}.Debug|Any CPU.Build.0 = Debug|Any CPU {2443CC8B-FB7D-47A7-9663-F3848BB30A36}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -90,6 +104,7 @@ Global GlobalSection(NestedProjects) = preSolution {3CAF09A6-6ABD-41D9-BA57-9A822B8095F7} = {490FAE47-4476-4508-B216-505FC850447F} {E0FDBFA9-AE5F-42FB-8A60-4E5D9E7D5414} = {62AAE0FE-4099-4A48-AA3C-F76F14C62655} + {FB92A4BE-A43E-4755-8132-EC38E9650B80} = {679E6084-0C45-4807-BFEE-D2FDA44B2188} {7EE133B6-5A02-41B7-9D89-41D9EA14184E} = {CC2C88C0-65F2-445D-BE78-973B840FE281} {D48E5EC2-CF83-4B17-8BBA-BDE52ADFAB1F} = {EDF8869A-C1E1-491B-BC9F-4A33F4DE1C73} {C8FAB96F-F13E-4094-883C-2D38D39EE4A3} = {CC2C88C0-65F2-445D-BE78-973B840FE281} @@ -98,6 +113,7 @@ Global {447D5357-F095-45DE-9DA5-2D9997237366} = {EDF8869A-C1E1-491B-BC9F-4A33F4DE1C73} {1136B8C9-3539-42FA-97FD-CAA6F146FCF0} = {EDF8869A-C1E1-491B-BC9F-4A33F4DE1C73} {C0A59BB0-F0B8-4AC6-B192-0249E784FC88} = {CC2C88C0-65F2-445D-BE78-973B840FE281} + {6709DD6A-6A44-4A49-BA4D-A50A40102C8B} = {CC2C88C0-65F2-445D-BE78-973B840FE281} {2443CC8B-FB7D-47A7-9663-F3848BB30A36} = {EDF8869A-C1E1-491B-BC9F-4A33F4DE1C73} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution diff --git a/nuget-publish.bat b/nuget-publish.bat index 8004482b..7bbcd9d2 100644 --- a/nuget-publish.bat +++ b/nuget-publish.bat @@ -1,5 +1,6 @@ :start ::定义版本 +set EFCORE2=2.2.0.20 set EFCORE3=3.2.0.20 set EFCORE5=5.2.0.20 diff --git a/samples/Sample.BulkConsole/Program.cs b/samples/Sample.BulkConsole/Program.cs index f541218d..147ac3a1 100644 --- a/samples/Sample.BulkConsole/Program.cs +++ b/samples/Sample.BulkConsole/Program.cs @@ -74,7 +74,6 @@ namespace Sample.BulkConsole Console.WriteLine("ok"); } - var b = DateTime.Now.Date.AddDays(-3); var queryable = myShardingDbContext.Set().Where(o => o.CreateTime >= b).OrderBy(o => o.CreateTime); var startNew1 = Stopwatch.StartNew(); diff --git a/samples/Sample.SqlServer/Controllers/ValuesController.cs b/samples/Sample.SqlServer/Controllers/ValuesController.cs index e5136034..e1751e07 100644 --- a/samples/Sample.SqlServer/Controllers/ValuesController.cs +++ b/samples/Sample.SqlServer/Controllers/ValuesController.cs @@ -74,7 +74,6 @@ namespace Sample.SqlServer.Controllers var sysUserMod98 = result.FirstOrDefault(o => o.Id == "98"); _defaultTableDbContext.Attach(sysUserMod98); sysUserMod98.Name = "name_update" + new Random().Next(1, 99) + "_98"; - _defaultTableDbContext.Attach(sysUserMod98); await _defaultTableDbContext.SaveChangesAsync(); var stu = new STU() { Id = "198" }; var sresultx111x = _defaultTableDbContext.Set().FirstOrDefault(o => o.Id == stu.Id); diff --git a/src/ShardingCore/Core/PhysicTables/DefaultPhysicTable.cs b/src/ShardingCore/Core/PhysicTables/DefaultPhysicTable.cs index b440c6e1..55d6d38f 100644 --- a/src/ShardingCore/Core/PhysicTables/DefaultPhysicTable.cs +++ b/src/ShardingCore/Core/PhysicTables/DefaultPhysicTable.cs @@ -42,10 +42,26 @@ namespace ShardingCore.Core.PhysicTables return Equals((DefaultPhysicTable) obj); } +#if !EFCORE2 public override int GetHashCode() { return HashCode.Combine(OriginalName, Tail, VirtualTable); } +#endif + +#if EFCORE2 + + public override int GetHashCode() + { + unchecked + { + var hashCode = (OriginalName != null ? OriginalName.GetHashCode() : 0); + hashCode = (hashCode * 397) ^ (Tail != null ? Tail.GetHashCode() : 0); + hashCode = (hashCode * 397) ^ (VirtualTable != null ? VirtualTable.GetHashCode() : 0); + return hashCode; + } + } +#endif } } \ No newline at end of file diff --git a/src/ShardingCore/Core/QueryRouteManagers/ShardingRouteAccessor.cs b/src/ShardingCore/Core/QueryRouteManagers/ShardingRouteAccessor.cs index 31f3772a..424bd951 100644 --- a/src/ShardingCore/Core/QueryRouteManagers/ShardingRouteAccessor.cs +++ b/src/ShardingCore/Core/QueryRouteManagers/ShardingRouteAccessor.cs @@ -17,9 +17,8 @@ namespace ShardingCore.Core.QueryRouteManagers { private static AsyncLocal _shardingRouteContext = new AsyncLocal(); - /// - /// sharding route context use in using code block - /// + + /// public ShardingRouteContext ShardingRouteContext { get => _shardingRouteContext.Value; diff --git a/src/ShardingCore/DIExtension.cs b/src/ShardingCore/DIExtension.cs index bb84fcef..f2666738 100644 --- a/src/ShardingCore/DIExtension.cs +++ b/src/ShardingCore/DIExtension.cs @@ -55,8 +55,13 @@ namespace ShardingCore Action shardingOptionAction = option => { optionsAction?.Invoke(option); +#if !EFCORE2 option.UseSharding(); +#endif +#if EFCORE2 + option.UseSharding(); +#endif }; services.AddDbContext(shardingOptionAction, contextLifetime, optionsLifetime); services.AddInternalShardingCore(); @@ -90,7 +95,13 @@ namespace ShardingCore Action shardingOptionAction = (sp, option) => { optionsAction?.Invoke(sp,option); +#if !EFCORE2 option.UseSharding(); + +#endif +#if EFCORE2 + option.UseSharding(); +#endif }; services.AddDbContext(shardingOptionAction, contextLifetime, optionsLifetime); services.AddInternalShardingCore(); @@ -168,6 +179,7 @@ namespace ShardingCore services.AddSingleton(); return services; } +#if !EFCORE2 internal static DbContextOptionsBuilder UseSharding(this DbContextOptionsBuilder optionsBuilder) { return optionsBuilder.ReplaceService() @@ -175,6 +187,16 @@ namespace ShardingCore .ReplaceService(); } +#endif +#if EFCORE2 + internal static DbContextOptionsBuilder UseSharding(this DbContextOptionsBuilder optionsBuilder) where TShardingDbContext : DbContext, IShardingDbContext + { + return optionsBuilder.ReplaceService() + .ReplaceService() + .ReplaceService>(); + } + +#endif internal static DbContextOptionsBuilder UseInnerDbContextSharding(this DbContextOptionsBuilder optionsBuilder) where TShardingDbContext:DbContext,IShardingDbContext { diff --git a/src/ShardingCore/DbContexts/EFCore2DbContextLocation.cs b/src/ShardingCore/DbContexts/EFCore2DbContextLocation.cs new file mode 100644 index 00000000..48a537af --- /dev/null +++ b/src/ShardingCore/DbContexts/EFCore2DbContextLocation.cs @@ -0,0 +1,20 @@ +#if EFCORE2 +using System; +using System.Collections.Generic; +using System.Text; + +namespace ShardingCore.DbContexts +{ + /* + * @Author: xjm + * @Description: + * @Date: 2021/9/5 21:29:47 + * @Ver: 1.0 + * @Email: 326308290@qq.com + */ + class EFCore2DbContextLocation + { + } +} + +#endif \ No newline at end of file diff --git a/src/ShardingCore/EFCores/ShardingDbSetSource.cs b/src/ShardingCore/EFCores/ShardingDbSetSource.cs index 831797d0..ff04c0df 100644 --- a/src/ShardingCore/EFCores/ShardingDbSetSource.cs +++ b/src/ShardingCore/EFCores/ShardingDbSetSource.cs @@ -12,6 +12,7 @@ namespace ShardingCore.EFCores * @Date: Saturday, 14 August 2021 10:17:43 * @Email: 326308290@qq.com */ +#if !EFCORE2 public class ShardingDbSetSource:IDbSetSource { #if EFCORE5 @@ -80,5 +81,53 @@ namespace ShardingCore.EFCores => c => new ShardingInternalDbSet(c); #endif } +#endif +#if EFCORE2 + + /// + /// This API supports the Entity Framework Core infrastructure and is not intended to be used + /// directly from your code. This API may change or be removed in future releases. + /// + public class ShardingDbSetSource : IDbSetSource, IDbQuerySource + { + private static readonly MethodInfo _genericCreateSet + = typeof(ShardingDbSetSource).GetTypeInfo().GetDeclaredMethod(nameof(CreateSetFactory)); + + private static readonly MethodInfo _genericCreateQuery + = typeof(ShardingDbSetSource).GetTypeInfo().GetDeclaredMethod(nameof(CreateQueryFactory)); + + private readonly ConcurrentDictionary> _cache + = new ConcurrentDictionary>(); + + /// + /// This API supports the Entity Framework Core infrastructure and is not intended to be used + /// directly from your code. This API may change or be removed in future releases. + /// + public virtual object Create(DbContext context, Type type) + => CreateCore(context, type, _genericCreateSet); + + /// + /// This API supports the Entity Framework Core infrastructure and is not intended to be used + /// directly from your code. This API may change or be removed in future releases. + /// + public virtual object CreateQuery(DbContext context, Type type) + => CreateCore(context, type, _genericCreateQuery); + + private object CreateCore(DbContext context, Type type, MethodInfo createMethod) + => _cache.GetOrAdd( + type, + t => (Func)createMethod + .MakeGenericMethod(t) + .Invoke(null, null))(context); + + private static Func CreateSetFactory() + where TEntity : class + => c => new ShardingInternalDbSet(c); + + private static Func> CreateQueryFactory() + where TQuery : class + => c => new ShardingInternalDbQuery(c); + } +#endif } \ No newline at end of file diff --git a/src/ShardingCore/EFCores/ShardingInternalDbQuery.cs b/src/ShardingCore/EFCores/ShardingInternalDbQuery.cs new file mode 100644 index 00000000..c6481315 --- /dev/null +++ b/src/ShardingCore/EFCores/ShardingInternalDbQuery.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Internal; + +namespace ShardingCore.EFCores +{ + /* + * @Author: xjm + * @Description: + * @Date: 2021/8/20 17:05:36 + * @Ver: 1.0 + * @Email: 326308290@qq.com + */ +#if EFCORE2 + + public class ShardingInternalDbQuery : InternalDbQuery where TQuery : class + { + public ShardingInternalDbQuery(DbContext context) : base(context) + { + } + } +#endif +} diff --git a/src/ShardingCore/EFCores/ShardingInternalDbSet.cs b/src/ShardingCore/EFCores/ShardingInternalDbSet.cs index 750549f0..6f191d41 100644 --- a/src/ShardingCore/EFCores/ShardingInternalDbSet.cs +++ b/src/ShardingCore/EFCores/ShardingInternalDbSet.cs @@ -55,6 +55,7 @@ namespace ShardingCore.EFCores /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// +#if !EFCORE2 public override async ValueTask> AddAsync( TEntity entity, CancellationToken cancellationToken = default) @@ -63,6 +64,15 @@ namespace ShardingCore.EFCores return await genericDbContext.AddAsync(entity, cancellationToken); } +#endif +#if EFCORE2 + public override async Task> AddAsync(TEntity entity, CancellationToken cancellationToken = new CancellationToken()) + { + var genericDbContext = ((IShardingDbContext)_context).CreateGenericDbContext(entity); + return await genericDbContext.AddAsync(entity, cancellationToken); + } + +#endif /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to diff --git a/src/ShardingCore/EFCores/ShardingQueryCompiler.cs b/src/ShardingCore/EFCores/ShardingQueryCompiler.cs index be9d62d1..47cf2256 100644 --- a/src/ShardingCore/EFCores/ShardingQueryCompiler.cs +++ b/src/ShardingCore/EFCores/ShardingQueryCompiler.cs @@ -15,6 +15,9 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.EntityFrameworkCore.Internal; +#if EFCORE2 +using Microsoft.EntityFrameworkCore.Internal; +#endif namespace ShardingCore.EFCores { @@ -41,6 +44,7 @@ namespace ShardingCore.EFCores return _shardingQueryExecutor.Execute(_currentContext, query); } +#if !EFCORE2 public TResult ExecuteAsync(Expression query, CancellationToken cancellationToken) { @@ -62,6 +66,35 @@ namespace ShardingCore.EFCores throw new NotImplementedException(); } +#endif +#if EFCORE2 + + + public IAsyncEnumerable ExecuteAsync(Expression query) + { + return _shardingQueryExecutor.ExecuteAsync>(_currentContext, query); + } + + public Task ExecuteAsync(Expression query, CancellationToken cancellationToken) + { + return _shardingQueryExecutor.ExecuteAsync>(_currentContext, query, cancellationToken); + } + + public Func CreateCompiledQuery(Expression query) + { + throw new NotImplementedException(); + } + + public Func> CreateCompiledAsyncEnumerableQuery(Expression query) + { + throw new NotImplementedException(); + } + + public Func> CreateCompiledAsyncTaskQuery(Expression query) + { + throw new NotImplementedException(); + } +#endif } } \ No newline at end of file diff --git a/src/ShardingCore/EFCores/ShardingRelationalConnection.cs b/src/ShardingCore/EFCores/ShardingRelationalConnection.cs index 4d9ab79f..5758a4e1 100644 --- a/src/ShardingCore/EFCores/ShardingRelationalConnection.cs +++ b/src/ShardingCore/EFCores/ShardingRelationalConnection.cs @@ -28,22 +28,36 @@ namespace ShardingCore.EFCores private readonly IRelationalConnection _relationalConnection; +#if !EFCORE2 public ShardingRelationalConnection(IRelationalConnection _relationalConnection, DbTransaction transaction) { this._relationalConnection = _relationalConnection; ((IShardingTransaction)Context).UseShardingTransaction(transaction); } +#endif +#if EFCORE2 + private readonly Type _dbContextType; + public ShardingRelationalConnection(IRelationalConnection _relationalConnection,DbTransaction transaction,Type dbContextType) + { + this._relationalConnection = _relationalConnection; + _dbContextType = dbContextType; + ((IShardingTransaction)Context).UseShardingTransaction(transaction); + } +#endif + public void ResetState() { _relationalConnection.ResetState(); } +#if !EFCORE2 public Task ResetStateAsync(CancellationToken cancellationToken = new CancellationToken()) { return _relationalConnection.ResetStateAsync(cancellationToken); } +#endif public IDbContextTransaction BeginTransaction() { @@ -122,7 +136,31 @@ namespace ShardingCore.EFCores public DbConnection DbConnection => _relationalConnection.DbConnection; public DbContext Context => +#if !EFCORE2 _relationalConnection.Context; +#endif +#if EFCORE2 + GetDbContext(); + + private DbContext GetDbContext() + { + var namedConnectionStringResolver = ((RelationalConnectionDependencies)_relationalConnection.GetPropertyValue("Dependencies")).ConnectionStringResolver; + var serviceProvider = (IServiceProvider)namedConnectionStringResolver.GetPropertyValue("ApplicationServiceProvider"); + var dbContext = (DbContext)serviceProvider.GetService(_dbContextType); + return dbContext; + } + + + public void RegisterBufferable(IBufferable bufferable) + { + _relationalConnection.RegisterBufferable(bufferable); + } + + public Task RegisterBufferableAsync(IBufferable bufferable, CancellationToken cancellationToken) + { + return _relationalConnection.RegisterBufferableAsync(bufferable, cancellationToken); + } +#endif public Guid ConnectionId => _relationalConnection.ConnectionId; public int? CommandTimeout @@ -163,6 +201,7 @@ namespace ShardingCore.EFCores public string ConnectionString => _relationalConnection.ConnectionString; +#if !EFCORE2 public async Task UseTransactionAsync(DbTransaction transaction, CancellationToken cancellationToken = new CancellationToken()) { @@ -181,5 +220,6 @@ namespace ShardingCore.EFCores { return _relationalConnection.DisposeAsync(); } +#endif } } diff --git a/src/ShardingCore/EFCores/ShardingRelationalTransactionFactory.cs b/src/ShardingCore/EFCores/ShardingRelationalTransactionFactory.cs index 87a02357..d70b9c4c 100644 --- a/src/ShardingCore/EFCores/ShardingRelationalTransactionFactory.cs +++ b/src/ShardingCore/EFCores/ShardingRelationalTransactionFactory.cs @@ -17,6 +17,7 @@ namespace ShardingCore.EFCores * @Ver: 1.0 * @Email: 326308290@qq.com */ +#if !EFCORE2 public class ShardingRelationalTransactionFactory: RelationalTransactionFactory { private readonly RelationalTransactionFactoryDependencies _dependencies; @@ -30,4 +31,23 @@ namespace ShardingCore.EFCores return new RelationalTransaction(new ShardingRelationalConnection(connection, transaction), transaction, transactionId, logger, transactionOwned); } } +#endif +#if EFCORE2 + + public class ShardingRelationalTransactionFactory : RelationalTransactionFactory where TShardingDbContext:DbContext,IShardingDbContext + { + private readonly RelationalTransactionFactoryDependencies _dependencies; + public ShardingRelationalTransactionFactory(RelationalTransactionFactoryDependencies dependencies) : base(dependencies) + { + _dependencies = dependencies; + } + public override RelationalTransaction Create(IRelationalConnection connection, DbTransaction transaction + , IDiagnosticsLogger logger, + bool transactionOwned) + { + return new RelationalTransaction(new ShardingRelationalConnection(connection, transaction,typeof(TShardingDbContext)), transaction, logger, + transactionOwned); + } + } +#endif } diff --git a/src/ShardingCore/Extensions/DbContextExtension.cs b/src/ShardingCore/Extensions/DbContextExtension.cs index f2aad489..90c933cd 100644 --- a/src/ShardingCore/Extensions/DbContextExtension.cs +++ b/src/ShardingCore/Extensions/DbContextExtension.cs @@ -108,6 +108,18 @@ var contextModelRelationalModel = contextModel.RelationalModel as RelationalMode IMemoryCache memoryCache = modelSourceDependencies.MemoryCache; object key1 = modelSourceDependencies.ModelCacheKeyFactory.Create(dbContext); memoryCache.Remove(key1); +#endif +#if EFCORE2 + + var modelSource = serviceScope.ServiceProvider.GetService(); + var modelSourceImpl = modelSource as RelationalModelSource; + + var modelSourceDependencies = + modelSourceImpl.GetPropertyValue("Dependencies") as ModelSourceDependencies; + var models = + typeof(ModelSource).GetTypeFieldValue(modelSourceImpl, "_models") as ConcurrentDictionary>; + object key1 = modelSourceDependencies.ModelCacheKeyFactory.Create(dbContext); + models.TryRemove(key1,out var del); #endif } @@ -133,6 +145,9 @@ var contextModelRelationalModel = contextModel.RelationalModel as RelationalMode var syncObject = modelSourceImpl.GetFieldValue("_syncObject"); return syncObject; #endif +#if EFCORE2 + return sLock; +#endif } diff --git a/src/ShardingCore/Extensions/ShardingExtension.cs b/src/ShardingCore/Extensions/ShardingExtension.cs index 3e62c74f..6bcc9270 100644 --- a/src/ShardingCore/Extensions/ShardingExtension.cs +++ b/src/ShardingCore/Extensions/ShardingExtension.cs @@ -57,7 +57,13 @@ namespace ShardingCore.Extensions public static string ShardingPrint(this Expression expression) { + +#if !EFCORE2 return expression.Print(); +#endif +#if EFCORE2 + return expression.ToString(); +#endif } /// diff --git a/src/ShardingCore/Sharding/AbstractShardingDbContext.cs b/src/ShardingCore/Sharding/AbstractShardingDbContext.cs index eba6253b..c5005785 100644 --- a/src/ShardingCore/Sharding/AbstractShardingDbContext.cs +++ b/src/ShardingCore/Sharding/AbstractShardingDbContext.cs @@ -215,6 +215,7 @@ namespace ShardingCore.Sharding return CreateGenericDbContext(entity).Add(entity); } +#if !EFCORE2 public override ValueTask> AddAsync(TEntity entity, CancellationToken cancellationToken = new CancellationToken()) { @@ -225,6 +226,18 @@ namespace ShardingCore.Sharding { return CreateGenericDbContext(entity).AddAsync(entity, cancellationToken); } +#endif +#if EFCORE2 + public override Task> AddAsync(TEntity entity, CancellationToken cancellationToken = new CancellationToken()) + { + return CreateGenericDbContext(entity).AddAsync(entity, cancellationToken); + } + + public override Task AddAsync(object entity, CancellationToken cancellationToken = new CancellationToken()) + { + return CreateGenericDbContext(entity).AddAsync(entity, cancellationToken); + } +#endif public override void AddRange(params object[] entities) { @@ -507,6 +520,7 @@ namespace ShardingCore.Sharding return i; } +#if !EFCORE2 public override async Task SaveChangesAsync(CancellationToken cancellationToken = new CancellationToken()) @@ -537,6 +551,37 @@ namespace ShardingCore.Sharding return i; } +#endif +#if EFCORE2 + public override async Task SaveChangesAsync(CancellationToken cancellationToken = new CancellationToken()) + { + + var isBeginTransaction = IsBeginTransaction; + int i = 0; + //如果是内部开的事务就内部自己消化 + if (!isBeginTransaction) + { + using (var tran = await Database.BeginTransactionAsync(cancellationToken)) + { + foreach (var dbContextCache in _dbContextCaches) + { + i += await dbContextCache.Value.SaveChangesAsync(cancellationToken); + } + tran.Commit(); + } + } + else + { + foreach (var dbContextCache in _dbContextCaches) + { + i += await dbContextCache.Value.SaveChangesAsync(cancellationToken); + } + } + + return i; + } +#endif +#if !EFCORE2 public override async Task SaveChangesAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = new CancellationToken()) { @@ -569,6 +614,37 @@ namespace ShardingCore.Sharding return i; } +#endif +#if EFCORE2 + public override async Task SaveChangesAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = new CancellationToken()) + { + + var isBeginTransaction = IsBeginTransaction; + int i = 0; + //如果是内部开的事务就内部自己消化 + if (!isBeginTransaction) + { + using (var tran = await Database.BeginTransactionAsync(cancellationToken)) + { + + foreach (var dbContextCache in _dbContextCaches) + { + i += await dbContextCache.Value.SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken); + } + + tran.Commit(); + } + } + else + { + foreach (var dbContextCache in _dbContextCaches) + { + i += await dbContextCache.Value.SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken); + } + } + return i; + } +#endif public override void Dispose() { @@ -587,6 +663,7 @@ namespace ShardingCore.Sharding base.Dispose(); } +#if !EFCORE2 public override async ValueTask DisposeAsync() { foreach (var dbContextCache in _dbContextCaches) @@ -603,5 +680,6 @@ namespace ShardingCore.Sharding await base.DisposeAsync(); } +#endif } } \ No newline at end of file diff --git a/src/ShardingCore/Sharding/Abstractions/IShardingQueryExecutor.cs b/src/ShardingCore/Sharding/Abstractions/IShardingQueryExecutor.cs index 47d0e080..b9a4ce5c 100644 --- a/src/ShardingCore/Sharding/Abstractions/IShardingQueryExecutor.cs +++ b/src/ShardingCore/Sharding/Abstractions/IShardingQueryExecutor.cs @@ -2,6 +2,9 @@ using System.Linq.Expressions; using System.Threading; using Microsoft.EntityFrameworkCore.Infrastructure; using ShardingCore.Sharding.Enumerators; +#if EFCORE2 +using Microsoft.EntityFrameworkCore.Internal; +#endif namespace ShardingCore.Sharding.Abstractions { diff --git a/src/ShardingCore/Sharding/Enumerators/StreamMergeAsync/InMemoryReverseStreamMergeAsyncEnumerator.cs b/src/ShardingCore/Sharding/Enumerators/StreamMergeAsync/InMemoryReverseStreamMergeAsyncEnumerator.cs index 1b6d50e3..196f3f5f 100644 --- a/src/ShardingCore/Sharding/Enumerators/StreamMergeAsync/InMemoryReverseStreamMergeAsyncEnumerator.cs +++ b/src/ShardingCore/Sharding/Enumerators/StreamMergeAsync/InMemoryReverseStreamMergeAsyncEnumerator.cs @@ -24,6 +24,7 @@ namespace ShardingCore.Sharding.Enumerators.StreamMergeAsync { _inMemoryStreamMergeAsyncEnumerator = inMemoryStreamMergeAsyncEnumerator; } +#if !EFCORE2 public async ValueTask DisposeAsync() { await _inMemoryStreamMergeAsyncEnumerator.DisposeAsync(); @@ -46,6 +47,25 @@ namespace ShardingCore.Sharding.Enumerators.StreamMergeAsync return _reverseEnumerator.MoveNext(); } +#endif +#if EFCORE2 + public async Task MoveNext(CancellationToken cancellationToken) + { + if (_first) + { + LinkedList _reverseCollection = new LinkedList(); + while (await _inMemoryStreamMergeAsyncEnumerator.MoveNext(cancellationToken)) + { + _reverseCollection.AddFirst(_inMemoryStreamMergeAsyncEnumerator.GetCurrent()); + } + + _reverseEnumerator = _reverseCollection.GetEnumerator(); + _first = false; + } + + return _reverseEnumerator.MoveNext(); + } +#endif public bool MoveNext() { diff --git a/src/ShardingCore/Sharding/Enumerators/StreamMergeAsync/MultiAggregateOrderStreamMergeAsyncEnumerator.cs b/src/ShardingCore/Sharding/Enumerators/StreamMergeAsync/MultiAggregateOrderStreamMergeAsyncEnumerator.cs index a1263969..dba826ee 100644 --- a/src/ShardingCore/Sharding/Enumerators/StreamMergeAsync/MultiAggregateOrderStreamMergeAsyncEnumerator.cs +++ b/src/ShardingCore/Sharding/Enumerators/StreamMergeAsync/MultiAggregateOrderStreamMergeAsyncEnumerator.cs @@ -56,11 +56,21 @@ namespace ShardingCore.Sharding.Enumerators return _mergeContext.SelectContext.SelectProperties.Where(o => !o.IsAggregateMethod) .Select(o => first.GetValueByExpression(o.PropertyName)).ToList(); } +#if !EFCORE2 public async ValueTask MoveNextAsync() +#endif +#if EFCORE2 + public async Task MoveNext(CancellationToken cancellationToken=new CancellationToken()) +#endif { if (_queue.IsEmpty()) return false; +#if !EFCORE2 var hasNext = await SetCurrentValueAsync(); +#endif +#if EFCORE2 + var hasNext = await SetCurrentValueAsync(cancellationToken); +#endif if (hasNext) { CurrentGroupValues = _queue.IsEmpty() ? new List(0) : GetCurrentGroupValues(_queue.Peek()); @@ -79,7 +89,12 @@ namespace ShardingCore.Sharding.Enumerators return true; } +#if !EFCORE2 private async ValueTask SetCurrentValueAsync() +#endif +#if EFCORE2 + private async Task SetCurrentValueAsync(CancellationToken cancellationToken=new CancellationToken()) +#endif { CurrentValue = default; var currentValues = new List(); @@ -89,7 +104,12 @@ namespace ShardingCore.Sharding.Enumerators currentValues.Add(current); var first = _queue.Poll(); +#if !EFCORE2 if (await first.MoveNextAsync()) +#endif +#if EFCORE2 + if (await first.MoveNext(cancellationToken)) +#endif { _queue.Offer(first); } @@ -203,6 +223,7 @@ namespace ShardingCore.Sharding.Enumerators return CurrentValue; } +#if !EFCORE2 public async ValueTask DisposeAsync() { @@ -211,6 +232,7 @@ namespace ShardingCore.Sharding.Enumerators await enumerator.DisposeAsync(); } } +#endif public void Reset() diff --git a/src/ShardingCore/Sharding/Enumerators/StreamMergeAsync/MultiOrderStreamMergeAsyncEnumerator.cs b/src/ShardingCore/Sharding/Enumerators/StreamMergeAsync/MultiOrderStreamMergeAsyncEnumerator.cs index f7bf0c61..c7bdeb9b 100644 --- a/src/ShardingCore/Sharding/Enumerators/StreamMergeAsync/MultiOrderStreamMergeAsyncEnumerator.cs +++ b/src/ShardingCore/Sharding/Enumerators/StreamMergeAsync/MultiOrderStreamMergeAsyncEnumerator.cs @@ -45,7 +45,12 @@ namespace ShardingCore.Sharding.Enumerators.StreamMergeAsync _currentEnumerator = _queue.IsEmpty() ? _enumerators.FirstOrDefault() : _queue.Peek(); } +#if !EFCORE2 public async ValueTask MoveNextAsync() +#endif +#if EFCORE2 + public async Task MoveNext(CancellationToken cancellationToken = new CancellationToken()) +#endif { if (_queue.IsEmpty()) return false; @@ -56,8 +61,14 @@ namespace ShardingCore.Sharding.Enumerators.StreamMergeAsync } var first = _queue.Poll(); +#if !EFCORE2 if (await first.MoveNextAsync()) +#endif +#if EFCORE2 + + if (await first.MoveNext(cancellationToken)) +#endif { _queue.Offer(first); } @@ -117,6 +128,7 @@ namespace ShardingCore.Sharding.Enumerators.StreamMergeAsync return _currentEnumerator.GetCurrent(); } +#if !EFCORE2 public async ValueTask DisposeAsync() { @@ -125,6 +137,7 @@ namespace ShardingCore.Sharding.Enumerators.StreamMergeAsync await enumerator.DisposeAsync(); } } +#endif diff --git a/src/ShardingCore/Sharding/Enumerators/StreamMergeAsync/OrderStreamMergeAsyncEnumerator.cs b/src/ShardingCore/Sharding/Enumerators/StreamMergeAsync/OrderStreamMergeAsyncEnumerator.cs index 4b5b96fa..3b8633a4 100644 --- a/src/ShardingCore/Sharding/Enumerators/StreamMergeAsync/OrderStreamMergeAsyncEnumerator.cs +++ b/src/ShardingCore/Sharding/Enumerators/StreamMergeAsync/OrderStreamMergeAsyncEnumerator.cs @@ -38,9 +38,19 @@ namespace ShardingCore.Sharding.Enumerators _orderValues = HasElement() ? GetCurrentOrderValues() : new List(0); } +#if !EFCORE2 public async ValueTask MoveNextAsync() +#endif +#if EFCORE2 + public async Task MoveNext(CancellationToken cancellationToken = new CancellationToken()) +#endif { +#if !EFCORE2 var has = await _enumerator.MoveNextAsync(); +#endif +#if EFCORE2 + var has = await _enumerator.MoveNext(cancellationToken); +#endif SetOrderValues(); return has; } @@ -119,10 +129,12 @@ namespace ShardingCore.Sharding.Enumerators { return _orderValues ?? new List(0); } +#if !EFCORE2 public ValueTask DisposeAsync() { return _enumerator.DisposeAsync(); } +#endif } } \ No newline at end of file diff --git a/src/ShardingCore/Sharding/Enumerators/StreamMergeAsync/PaginationStreamMergeAsyncEnumerator.cs b/src/ShardingCore/Sharding/Enumerators/StreamMergeAsync/PaginationStreamMergeAsyncEnumerator.cs index 43baa54f..80b6401a 100644 --- a/src/ShardingCore/Sharding/Enumerators/StreamMergeAsync/PaginationStreamMergeAsyncEnumerator.cs +++ b/src/ShardingCore/Sharding/Enumerators/StreamMergeAsync/PaginationStreamMergeAsyncEnumerator.cs @@ -31,19 +31,34 @@ namespace ShardingCore.Sharding.Enumerators.StreamMergeAsync else _enumerator = new MultiOrderStreamMergeAsyncEnumerator(_mergeContext, sources); } +#if !EFCORE2 public async ValueTask MoveNextAsync() +#endif +#if EFCORE2 + public async Task MoveNext(CancellationToken cancellationToken = new CancellationToken()) +#endif { //如果合并数据的时候不需要跳过也没有take多少那么就是直接next while (_skip.GetValueOrDefault() > this.realSkip) { +#if !EFCORE2 var has = await _enumerator.MoveNextAsync(); +#endif +#if EFCORE2 + var has = await _enumerator.MoveNext(cancellationToken); +#endif realSkip++; if (!has) return false; } +#if !EFCORE2 var next = await _enumerator.MoveNextAsync(); +#endif +#if EFCORE2 + var next = await _enumerator.MoveNext(cancellationToken); +#endif if (next) { @@ -111,9 +126,12 @@ namespace ShardingCore.Sharding.Enumerators.StreamMergeAsync { _enumerator.Dispose(); } +#if !EFCORE2 + public ValueTask DisposeAsync() { return _enumerator.DisposeAsync(); } +#endif } } \ No newline at end of file diff --git a/src/ShardingCore/Sharding/Enumerators/StreamMergeAsync/StreamMergeAsyncEnumerator.cs b/src/ShardingCore/Sharding/Enumerators/StreamMergeAsync/StreamMergeAsyncEnumerator.cs index be8e781f..163b520d 100644 --- a/src/ShardingCore/Sharding/Enumerators/StreamMergeAsync/StreamMergeAsyncEnumerator.cs +++ b/src/ShardingCore/Sharding/Enumerators/StreamMergeAsync/StreamMergeAsyncEnumerator.cs @@ -43,6 +43,7 @@ namespace ShardingCore.Sharding.Enumerators } return false; } +#if !EFCORE2 public async ValueTask DisposeAsync() { if (_asyncSource != null) @@ -95,6 +96,7 @@ namespace ShardingCore.Sharding.Enumerators return _syncSource.MoveNext(); } +#endif @@ -104,5 +106,68 @@ namespace ShardingCore.Sharding.Enumerators } object IEnumerator.Current => Current; +#if EFCORE2 + public void Dispose() + { + _asyncSource.Dispose(); + } + + public async Task MoveNext(CancellationToken cancellationToken=new CancellationToken()) + { + if (skip) + { + skip = false; + return null != SourceCurrent(); + } + return await _asyncSource.MoveNext(cancellationToken); + } + public T Current => GetCurrent(); + public T ReallyCurrent => GetReallyCurrent(); + public bool HasElement() + { + return null != SourceCurrent(); + } + + private T SourceCurrent() + { + try + { + if (tryGetCurrentError) + return default; + return _asyncSource.Current; + }catch(Exception e) + { + tryGetCurrentError = true; + return default; + } + } + + private bool tryGetCurrentError = false; + + public T GetCurrent() + { + if (skip) + return default; + if (_asyncSource != null) return SourceCurrent(); + if (_syncSource != null) return _syncSource.Current; + return default; + } + public T GetReallyCurrent() + { + if (_asyncSource != null) return SourceCurrent(); + if (_syncSource != null) return _syncSource.Current; + return default; + } + public bool MoveNext() + { + if (skip) + { + skip = false; + return null != _syncSource.Current; + } + return _syncSource.MoveNext(); + } + +#endif } } \ No newline at end of file diff --git a/src/ShardingCore/Sharding/PaginationConfigurations/MultiQueryPagination/IMultiQueryPredicate.cs b/src/ShardingCore/Sharding/PaginationConfigurations/MultiQueryPagination/IMultiQueryPredicate.cs deleted file mode 100644 index a986dffc..00000000 --- a/src/ShardingCore/Sharding/PaginationConfigurations/MultiQueryPagination/IMultiQueryPredicate.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace ShardingCore.Sharding.PaginationConfigurations.MultiQueryPagination -{ - /* - * @Author: xjm - * @Description: - * @Date: 2021/9/15 17:07:30 - * @Ver: 1.0 - * @Email: 326308290@qq.com - */ - public interface IMultiQueryPredicate - { - public bool ContinueMultiQuery(long total, int currentSkip, int tables); - } -} diff --git a/src/ShardingCore/Sharding/PaginationConfigurations/PaginationBuilder.cs b/src/ShardingCore/Sharding/PaginationConfigurations/PaginationBuilder.cs index 63541d5d..74771828 100644 --- a/src/ShardingCore/Sharding/PaginationConfigurations/PaginationBuilder.cs +++ b/src/ShardingCore/Sharding/PaginationConfigurations/PaginationBuilder.cs @@ -53,14 +53,5 @@ namespace ShardingCore.Sharding.PaginationConfigurations // _metadata.TakeInMemoryCountIfLe = count; // return this; //} - - /// - /// 启用多次查询排序 - /// - /// - public PaginationBuilder ConfigMultiQueryShardingPage() - { - return this; - } } } diff --git a/src/ShardingCore/Sharding/ShardingQueryExecutors/DefaultShardingQueryExecutor.cs b/src/ShardingCore/Sharding/ShardingQueryExecutors/DefaultShardingQueryExecutor.cs index 7332a081..117079b9 100644 --- a/src/ShardingCore/Sharding/ShardingQueryExecutors/DefaultShardingQueryExecutor.cs +++ b/src/ShardingCore/Sharding/ShardingQueryExecutors/DefaultShardingQueryExecutor.cs @@ -12,6 +12,9 @@ using ShardingCore.Sharding.Abstractions; using ShardingCore.Sharding.StreamMergeEngines; using ShardingCore.Sharding.StreamMergeEngines.Abstractions; using ShardingCore.Sharding.StreamMergeEngines.AggregateMergeEngines; +#if EFCORE2 +using Microsoft.EntityFrameworkCore.Internal; +#endif namespace ShardingCore.Sharding.ShardingQueryExecutors { diff --git a/src/ShardingCore/Sharding/StreamMergeEngines/Abstractions/AbstractEnsureExpressionMergeEngines/AbstractEnsureMethodCallConstantInMemoryAsyncMergeEngine.cs b/src/ShardingCore/Sharding/StreamMergeEngines/Abstractions/AbstractEnsureExpressionMergeEngines/AbstractEnsureMethodCallConstantInMemoryAsyncMergeEngine.cs index bb3e2bfd..49c9dc8d 100644 --- a/src/ShardingCore/Sharding/StreamMergeEngines/Abstractions/AbstractEnsureExpressionMergeEngines/AbstractEnsureMethodCallConstantInMemoryAsyncMergeEngine.cs +++ b/src/ShardingCore/Sharding/StreamMergeEngines/Abstractions/AbstractEnsureExpressionMergeEngines/AbstractEnsureMethodCallConstantInMemoryAsyncMergeEngine.cs @@ -3,7 +3,6 @@ using System.Linq; using System.Linq.Expressions; using Microsoft.EntityFrameworkCore.Infrastructure; using ShardingCore.Exceptions; -using ShardingCore.Extensions; using ShardingCore.Sharding.Abstractions; namespace ShardingCore.Sharding.StreamMergeEngines.Abstractions.AbstractEnsureExpressionMergeEngines @@ -27,7 +26,12 @@ namespace ShardingCore.Sharding.StreamMergeEngines.Abstractions.AbstractEnsureEx if (!(secondExpression is ConstantExpression constantExpression)) { - throw new ShardingCoreException($"not found constant {methodCallExpression.ShardingPrint()}"); +#if !EFCORE2 + throw new ShardingCoreException($"not found constant {methodCallExpression.Print()}"); +#endif +#if EFCORE2 + throw new ShardingCoreException($"not found constant {methodCallExpression}"); +#endif } _constantItem = (TEntity)constantExpression.Value; } @@ -35,7 +39,12 @@ namespace ShardingCore.Sharding.StreamMergeEngines.Abstractions.AbstractEnsureEx { if (!(secondExpression is ConstantExpression)) { - throw new InvalidOperationException(_methodCallExpression.ShardingPrint()); +#if !EFCORE2 + throw new InvalidOperationException(_methodCallExpression.Print()); +#endif +#if EFCORE2 + throw new InvalidOperationException(_methodCallExpression.ToString()); +#endif } return queryable; diff --git a/src/ShardingCore/Sharding/StreamMergeEngines/Abstractions/AbstractEnsureExpressionMergeEngines/AbstractEnsureMethodCallSelectorInMemoryAsyncMergeEngine.cs b/src/ShardingCore/Sharding/StreamMergeEngines/Abstractions/AbstractEnsureExpressionMergeEngines/AbstractEnsureMethodCallSelectorInMemoryAsyncMergeEngine.cs index 4943d2d1..bebb75db 100644 --- a/src/ShardingCore/Sharding/StreamMergeEngines/Abstractions/AbstractEnsureExpressionMergeEngines/AbstractEnsureMethodCallSelectorInMemoryAsyncMergeEngine.cs +++ b/src/ShardingCore/Sharding/StreamMergeEngines/Abstractions/AbstractEnsureExpressionMergeEngines/AbstractEnsureMethodCallSelectorInMemoryAsyncMergeEngine.cs @@ -3,7 +3,6 @@ using System.Linq; using System.Linq.Expressions; using Microsoft.EntityFrameworkCore.Infrastructure; using ShardingCore.Exceptions; -using ShardingCore.Extensions; using ShardingCore.Sharding.Abstractions; namespace ShardingCore.Sharding.StreamMergeEngines.Abstractions.AbstractEnsureExpressionMergeEngines @@ -32,7 +31,12 @@ namespace ShardingCore.Sharding.StreamMergeEngines.Abstractions.AbstractEnsureEx return queryable.Select(selector); } - throw new ShardingCoreException($"expression is not selector:{secondExpression.ShardingPrint()}"); +#if !EFCORE2 + throw new ShardingCoreException($"expression is not selector:{secondExpression.Print()}"); +#endif +#if EFCORE2 + throw new ShardingCoreException($"expression is not selector:{secondExpression}"); +#endif } return queryable; } diff --git a/src/ShardingCore/Sharding/StreamMergeEngines/Abstractions/AbstractEnsureExpressionMergeEngines/AbstractEnsureMethodCallWhereInMemoryAsyncMergeEngine.cs b/src/ShardingCore/Sharding/StreamMergeEngines/Abstractions/AbstractEnsureExpressionMergeEngines/AbstractEnsureMethodCallWhereInMemoryAsyncMergeEngine.cs index 335f728d..6e79cda4 100644 --- a/src/ShardingCore/Sharding/StreamMergeEngines/Abstractions/AbstractEnsureExpressionMergeEngines/AbstractEnsureMethodCallWhereInMemoryAsyncMergeEngine.cs +++ b/src/ShardingCore/Sharding/StreamMergeEngines/Abstractions/AbstractEnsureExpressionMergeEngines/AbstractEnsureMethodCallWhereInMemoryAsyncMergeEngine.cs @@ -2,7 +2,6 @@ using System.Linq; using System.Linq.Expressions; using Microsoft.EntityFrameworkCore.Infrastructure; -using ShardingCore.Extensions; using ShardingCore.Sharding.Abstractions; namespace ShardingCore.Sharding.StreamMergeEngines.Abstractions.AbstractEnsureExpressionMergeEngines @@ -30,7 +29,12 @@ namespace ShardingCore.Sharding.StreamMergeEngines.Abstractions.AbstractEnsureEx return queryable.Where(predicate); } - throw new InvalidOperationException(_methodCallExpression.ShardingPrint()); +#if !EFCORE2 + throw new InvalidOperationException(_methodCallExpression.Print()); +#endif +#if EFCORE2 + throw new InvalidOperationException(_methodCallExpression.ToString()); +#endif } } diff --git a/src/ShardingCore/Sharding/StreamMergeEngines/Abstractions/AbstractGenericExpressionMergeEngines/AbstractGenericMethodCallSelectorInMemoryAsyncMergeEngine.cs b/src/ShardingCore/Sharding/StreamMergeEngines/Abstractions/AbstractGenericExpressionMergeEngines/AbstractGenericMethodCallSelectorInMemoryAsyncMergeEngine.cs index c14f4468..2685e904 100644 --- a/src/ShardingCore/Sharding/StreamMergeEngines/Abstractions/AbstractGenericExpressionMergeEngines/AbstractGenericMethodCallSelectorInMemoryAsyncMergeEngine.cs +++ b/src/ShardingCore/Sharding/StreamMergeEngines/Abstractions/AbstractGenericExpressionMergeEngines/AbstractGenericMethodCallSelectorInMemoryAsyncMergeEngine.cs @@ -3,7 +3,6 @@ using System.Linq; using System.Linq.Expressions; using Microsoft.EntityFrameworkCore.Infrastructure; using ShardingCore.Exceptions; -using ShardingCore.Extensions; using ShardingCore.Sharding.Abstractions; namespace ShardingCore.Sharding.StreamMergeEngines.Abstractions.AbstractGenericExpressionMergeEngines @@ -31,7 +30,13 @@ namespace ShardingCore.Sharding.StreamMergeEngines.Abstractions.AbstractGenericE return queryable.Select(selector); } - throw new ShardingCoreException($"expression is not selector:{secondExpression.ShardingPrint()}"); + +#if !EFCORE2 + throw new ShardingCoreException($"expression is not selector:{secondExpression.Print()}"); +#endif +#if EFCORE2 + throw new ShardingCoreException($"expression is not selector:{secondExpression}"); +#endif } return queryable; } diff --git a/src/ShardingCore/Sharding/StreamMergeEngines/Abstractions/AbstractGenericExpressionMergeEngines/AbstractGenericMethodCallWhereInMemoryAsyncMergeEngine.cs b/src/ShardingCore/Sharding/StreamMergeEngines/Abstractions/AbstractGenericExpressionMergeEngines/AbstractGenericMethodCallWhereInMemoryAsyncMergeEngine.cs index 78f2db0b..5c88b204 100644 --- a/src/ShardingCore/Sharding/StreamMergeEngines/Abstractions/AbstractGenericExpressionMergeEngines/AbstractGenericMethodCallWhereInMemoryAsyncMergeEngine.cs +++ b/src/ShardingCore/Sharding/StreamMergeEngines/Abstractions/AbstractGenericExpressionMergeEngines/AbstractGenericMethodCallWhereInMemoryAsyncMergeEngine.cs @@ -2,7 +2,6 @@ using System.Linq; using System.Linq.Expressions; using Microsoft.EntityFrameworkCore.Infrastructure; -using ShardingCore.Extensions; using ShardingCore.Sharding.Abstractions; namespace ShardingCore.Sharding.StreamMergeEngines.Abstractions.AbstractGenericExpressionMergeEngines @@ -32,7 +31,12 @@ namespace ShardingCore.Sharding.StreamMergeEngines.Abstractions.AbstractGenericE return queryable.Where(predicate); } } - throw new InvalidOperationException(_methodCallExpression.ShardingPrint()); +#if !EFCORE2 + throw new InvalidOperationException(_methodCallExpression.Print()); +#endif +#if EFCORE2 + throw new InvalidOperationException(_methodCallExpression.ToString()); +#endif } } diff --git a/src/ShardingCore/Sharding/StreamMergeEngines/AsyncEnumerableStreamMergeEngine.cs b/src/ShardingCore/Sharding/StreamMergeEngines/AsyncEnumerableStreamMergeEngine.cs index f1092745..d8f7b300 100644 --- a/src/ShardingCore/Sharding/StreamMergeEngines/AsyncEnumerableStreamMergeEngine.cs +++ b/src/ShardingCore/Sharding/StreamMergeEngines/AsyncEnumerableStreamMergeEngine.cs @@ -3,6 +3,10 @@ using System.Collections; using System.Collections.Generic; using System.Threading; +#if EFCORE2 +using Microsoft.EntityFrameworkCore.Extensions.Internal; +#endif + namespace ShardingCore.Sharding.StreamMergeEngines { /* @@ -21,11 +25,21 @@ namespace ShardingCore.Sharding.StreamMergeEngines } +#if !EFCORE2 public IAsyncEnumerator GetAsyncEnumerator(CancellationToken cancellationToken = new CancellationToken()) { return new EnumeratorShardingQueryExecutor(_mergeContext).ExecuteAsync(cancellationToken) .GetAsyncEnumerator(cancellationToken); } +#endif + +#if EFCORE2 + IAsyncEnumerator IAsyncEnumerable.GetEnumerator() + { + return ((IAsyncEnumerable)new EnumeratorShardingQueryExecutor(_mergeContext).ExecuteAsync()) + .GetEnumerator(); + } +#endif public IEnumerator GetEnumerator() diff --git a/src/ShardingCore/Sharding/StreamMergeEngines/EnumeratorStreamMergeEngines/Abstractions/AbstractEnumeratorAsyncStreamMergeEngine.cs b/src/ShardingCore/Sharding/StreamMergeEngines/EnumeratorStreamMergeEngines/Abstractions/AbstractEnumeratorAsyncStreamMergeEngine.cs index 370a86f9..ab0879b4 100644 --- a/src/ShardingCore/Sharding/StreamMergeEngines/EnumeratorStreamMergeEngines/Abstractions/AbstractEnumeratorAsyncStreamMergeEngine.cs +++ b/src/ShardingCore/Sharding/StreamMergeEngines/EnumeratorStreamMergeEngines/Abstractions/AbstractEnumeratorAsyncStreamMergeEngine.cs @@ -10,6 +10,9 @@ using ShardingCore.Exceptions; using ShardingCore.Extensions; using ShardingCore.Sharding.Enumerators; using ShardingCore.Sharding.Enumerators.StreamMergeAsync; +#if EFCORE2 +using Microsoft.EntityFrameworkCore.Extensions.Internal; +#endif namespace ShardingCore.Sharding.StreamMergeEngines.EnumeratorStreamMergeEngines.Abstractions { @@ -57,9 +60,16 @@ namespace ShardingCore.Sharding.StreamMergeEngines.EnumeratorStreamMergeEngines. } public async Task> DoGetAsyncEnumerator(IQueryable newQueryable) { +#if !EFCORE2 var enumator = newQueryable.AsAsyncEnumerable().GetAsyncEnumerator(); await enumator.MoveNextAsync(); return enumator; +#endif +#if EFCORE2 + var enumator = newQueryable.AsAsyncEnumerable().GetEnumerator(); + await enumator.MoveNext(); + return enumator; +#endif } public IEnumerator DoGetEnumerator(IQueryable newQueryable) { diff --git a/src/ShardingCore/Sharding/StreamMergeEngines/EnumeratorStreamMergeEngines/Abstractions/AbstractEnumeratorStreamMergeEngine.cs b/src/ShardingCore/Sharding/StreamMergeEngines/EnumeratorStreamMergeEngines/Abstractions/AbstractEnumeratorStreamMergeEngine.cs index 738928d4..41d907f3 100644 --- a/src/ShardingCore/Sharding/StreamMergeEngines/EnumeratorStreamMergeEngines/Abstractions/AbstractEnumeratorStreamMergeEngine.cs +++ b/src/ShardingCore/Sharding/StreamMergeEngines/EnumeratorStreamMergeEngines/Abstractions/AbstractEnumeratorStreamMergeEngine.cs @@ -32,11 +32,21 @@ namespace ShardingCore.Sharding.StreamMergeEngines.EnumeratorStreamMergeEngines. public abstract IStreamMergeAsyncEnumerator GetShardingAsyncEnumerator(bool async, CancellationToken cancellationToken = new CancellationToken()); +#if !EFCORE2 public IAsyncEnumerator GetAsyncEnumerator( CancellationToken cancellationToken = new CancellationToken()) { return GetShardingAsyncEnumerator(true,cancellationToken); } +#endif + +#if EFCORE2 + IAsyncEnumerator IAsyncEnumerable.GetEnumerator() + { + return GetShardingAsyncEnumerator(true); + } + +#endif public IEnumerator GetEnumerator() { diff --git a/src/ShardingCore/ShardingBootstrapper.cs b/src/ShardingCore/ShardingBootstrapper.cs index 9b4e6aab..0145669e 100644 --- a/src/ShardingCore/ShardingBootstrapper.cs +++ b/src/ShardingCore/ShardingBootstrapper.cs @@ -70,7 +70,12 @@ namespace ShardingCore var virtualTable = CreateVirtualTable(entity.ClrType, virtualRoute); //获取ShardingEntity的实际表名 +#if !EFCORE2 var tableName = context.Model.FindEntityType(virtualTable.EntityType).GetTableName(); +#endif +#if EFCORE2 + var tableName = context.Model.FindEntityType(virtualTable.EntityType).Relational().TableName; +#endif virtualTable.SetOriginalTableName(tableName); _virtualTableManager.AddVirtualTable(shardingConfigOption.ShardingDbContextType,virtualTable); CreateDataTable(shardingConfigOption.ShardingDbContextType,virtualTable, shardingConfigOption); diff --git a/src/ShardingCore/ShardingCore.csproj b/src/ShardingCore/ShardingCore.csproj index ee8ab93e..1e153601 100644 --- a/src/ShardingCore/ShardingCore.csproj +++ b/src/ShardingCore/ShardingCore.csproj @@ -1,4 +1,6 @@ + + netstandard2.1 $(EFCORE5) diff --git a/src2x/ShardingCore.2x/ShardingCore.2x.csproj b/src2x/ShardingCore.2x/ShardingCore.2x.csproj new file mode 100644 index 00000000..e9e4ea4f --- /dev/null +++ b/src2x/ShardingCore.2x/ShardingCore.2x.csproj @@ -0,0 +1,30 @@ + + + + + netstandard2.0 + $(EFCORE2) + true + TRACE;DEBUG;EFCORE2; + 8.0 + ShardingCore + ShardingCore + + + + true + bin\Release\ShardingCore.2x.xml + + + + + + + + + + + + + + diff --git a/test/ShardingCore.Test50_2x/Class1.cs b/test/ShardingCore.Test50_2x/Class1.cs new file mode 100644 index 00000000..521d3d4a --- /dev/null +++ b/test/ShardingCore.Test50_2x/Class1.cs @@ -0,0 +1,8 @@ +using System; + +namespace ShardingCore.Test50_2x +{ + public class Class1 + { + } +} diff --git a/test/ShardingCore.Test50_2x/Configs/DbConfig.json b/test/ShardingCore.Test50_2x/Configs/DbConfig.json new file mode 100644 index 00000000..f305cd6d --- /dev/null +++ b/test/ShardingCore.Test50_2x/Configs/DbConfig.json @@ -0,0 +1,5 @@ +{ + "SqlServer": { + "ConnectionString": "Data Source=localhost;Initial Catalog=ShardingCoreDB;Integrated Security=True;" + } +} \ No newline at end of file diff --git a/test/ShardingCore.Test50_2x/DefaultDbContext.cs b/test/ShardingCore.Test50_2x/DefaultDbContext.cs new file mode 100644 index 00000000..be7961f9 --- /dev/null +++ b/test/ShardingCore.Test50_2x/DefaultDbContext.cs @@ -0,0 +1,31 @@ +using Microsoft.EntityFrameworkCore; +using ShardingCore.Core.VirtualRoutes.RouteTails.Abstractions; +using ShardingCore.Sharding.Abstractions; +using ShardingCore.Test50_2x.Domain.Maps; + +namespace ShardingCore.Test50_2x +{ + /* + * @Author: xjm + * @Description: + * @Date: 2021/3/31 15:28:11 + * @Ver: 1.0 + * @Email: 326308290@qq.com + */ + public class DefaultDbContext : DbContext, IShardingTableDbContext + { + public DefaultDbContext(DbContextOptions options) : base(options) + { + + } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + base.OnModelCreating(modelBuilder); + modelBuilder.ApplyConfiguration(new SysUserModMap()); + modelBuilder.ApplyConfiguration(new SysUserSalaryMap()); + } + + public IRouteTail RouteTail { get; set; } + } +} diff --git a/test/ShardingCore.Test50_2x/Domain/Entities/SysUserMod.cs b/test/ShardingCore.Test50_2x/Domain/Entities/SysUserMod.cs new file mode 100644 index 00000000..cdb1eb32 --- /dev/null +++ b/test/ShardingCore.Test50_2x/Domain/Entities/SysUserMod.cs @@ -0,0 +1,29 @@ +using ShardingCore.Core; + +namespace ShardingCore.Test50_2x.Domain.Entities +{ +/* +* @Author: xjm +* @Description: +* @Date: Thursday, 14 January 2021 15:36:43 +* @Email: 326308290@qq.com +*/ + public class SysUserMod:IShardingTable + { + /// + /// 用户Id用于分表 + /// + [ShardingTableKey(TailPrefix = "_")] + public string Id { get; set; } + /// + /// 用户名称 + /// + public string Name { get; set; } + /// + /// 用户姓名 + /// + public int Age { get; set; } + public int AgeGroup { get; set; } + + } +} \ No newline at end of file diff --git a/test/ShardingCore.Test50_2x/Domain/Entities/SysUserSalary.cs b/test/ShardingCore.Test50_2x/Domain/Entities/SysUserSalary.cs new file mode 100644 index 00000000..e0dc6d9a --- /dev/null +++ b/test/ShardingCore.Test50_2x/Domain/Entities/SysUserSalary.cs @@ -0,0 +1,42 @@ +using ShardingCore.Core; + +namespace ShardingCore.Test50_2x.Domain.Entities +{ +/* +* @Author: xjm +* @Description: +* @Date: Monday, 01 February 2021 15:43:22 +* @Email: 326308290@qq.com +*/ + public class SysUserSalary:IShardingTable + { + public string Id { get; set; } + public string UserId { get; set; } + /// + /// 每月的金额 + /// + [ShardingTableKey] + public int DateOfMonth { get; set; } + /// + /// 工资 + /// + public int Salary { get; set; } + /// + /// 工资 + /// + public long SalaryLong { get; set; } + + /// + /// 工资 + /// + public decimal SalaryDecimal { get; set; } + /// + /// 工资 + /// + public double SalaryDouble { get; set; } + /// + /// 工资 + /// + public float SalaryFloat { get; set; } + } +} \ No newline at end of file diff --git a/test/ShardingCore.Test50_2x/Domain/Maps/SysUserModMap.cs b/test/ShardingCore.Test50_2x/Domain/Maps/SysUserModMap.cs new file mode 100644 index 00000000..07d78aa1 --- /dev/null +++ b/test/ShardingCore.Test50_2x/Domain/Maps/SysUserModMap.cs @@ -0,0 +1,23 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using ShardingCore.Test50_2x.Domain.Entities; + +namespace ShardingCore.Test50_2x.Domain.Maps +{ +/* +* @Author: xjm +* @Description: +* @Date: Thursday, 14 January 2021 15:37:33 +* @Email: 326308290@qq.com +*/ + public class SysUserModMap:IEntityTypeConfiguration + { + public void Configure(EntityTypeBuilder builder) + { + builder.HasKey(o => o.Id); + builder.Property(o => o.Id).IsRequired().HasMaxLength(128); + builder.Property(o => o.Name).HasMaxLength(128); + builder.ToTable(nameof(SysUserMod)); + } + } +} \ No newline at end of file diff --git a/test/ShardingCore.Test50_2x/Domain/Maps/SysUserSalaryMap.cs b/test/ShardingCore.Test50_2x/Domain/Maps/SysUserSalaryMap.cs new file mode 100644 index 00000000..a2feed71 --- /dev/null +++ b/test/ShardingCore.Test50_2x/Domain/Maps/SysUserSalaryMap.cs @@ -0,0 +1,23 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using ShardingCore.Test50_2x.Domain.Entities; + +namespace ShardingCore.Test50_2x.Domain.Maps +{ +/* +* @Author: xjm +* @Description: +* @Date: Monday, 01 February 2021 15:42:35 +* @Email: 326308290@qq.com +*/ + public class SysUserSalaryMap:IEntityTypeConfiguration + { + public void Configure(EntityTypeBuilder builder) + { + builder.HasKey(o => o.Id); + builder.Property(o => o.Id).IsRequired().HasMaxLength(128); + builder.Property(o => o.UserId).IsRequired().HasMaxLength(128); + builder.ToTable(nameof(SysUserSalary)); + } + } +} \ No newline at end of file diff --git a/test/ShardingCore.Test50_2x/ShardingCore.Test50_2x.csproj b/test/ShardingCore.Test50_2x/ShardingCore.Test50_2x.csproj new file mode 100644 index 00000000..8fbc62be --- /dev/null +++ b/test/ShardingCore.Test50_2x/ShardingCore.Test50_2x.csproj @@ -0,0 +1,32 @@ + + + + net5.0 + 9.0 + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + true + PreserveNewest + PreserveNewest + + + + + + + + + diff --git a/test/ShardingCore.Test50_2x/ShardingDefaultDbContext.cs b/test/ShardingCore.Test50_2x/ShardingDefaultDbContext.cs new file mode 100644 index 00000000..f3fd8225 --- /dev/null +++ b/test/ShardingCore.Test50_2x/ShardingDefaultDbContext.cs @@ -0,0 +1,30 @@ +using System; +using Microsoft.EntityFrameworkCore; +using ShardingCore.Sharding; +using ShardingCore.Test50_2x.Domain.Maps; + +namespace ShardingCore.Test50_2x +{ + /* + * @Author: xjm + * @Description: + * @Date: 2021/8/15 10:21:03 + * @Ver: 1.0 + * @Email: 326308290@qq.com + */ + public class ShardingDefaultDbContext:AbstractShardingDbContext + { + public ShardingDefaultDbContext(DbContextOptions options) : base(options) + { + } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + base.OnModelCreating(modelBuilder); + modelBuilder.ApplyConfiguration(new SysUserModMap()); + modelBuilder.ApplyConfiguration(new SysUserSalaryMap()); + } + + public override Type ShardingDbContextType => this.GetType(); + } +} diff --git a/test/ShardingCore.Test50_2x/ShardingTest.cs b/test/ShardingCore.Test50_2x/ShardingTest.cs new file mode 100644 index 00000000..01bbbce7 --- /dev/null +++ b/test/ShardingCore.Test50_2x/ShardingTest.cs @@ -0,0 +1,417 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; +using ShardingCore.Core.QueryRouteManagers.Abstractions; +using ShardingCore.Test50_2x.Domain.Entities; +using Xunit; + +namespace ShardingCore.Test50_2x +{ + /* + * @Author: xjm + * @Description: + * @Date: Friday, 15 January 2021 17:22:10 + * @Email: 326308290@qq.com + */ + public class ShardingTest + { + private readonly ShardingDefaultDbContext _virtualDbContext; + private readonly IShardingRouteManager _shardingRouteManager; + + public ShardingTest(ShardingDefaultDbContext virtualDbContext,IShardingRouteManager shardingRouteManager) + { + _virtualDbContext = virtualDbContext; + _shardingRouteManager = shardingRouteManager; + } + + //[Fact] + //public async Task Route_TEST() + //{ + // var queryable1 = _virtualDbContext.Set().Where(o=>o.Id=="339"); + // var routeResults1 = _routingRuleEngineFactory.Route(queryable1); + // Assert.Equal(1,routeResults1.Count()); + // Assert.Equal(1,routeResults1.FirstOrDefault().ReplaceTables.Count()); + // Assert.Equal("0",routeResults1.FirstOrDefault().ReplaceTables.FirstOrDefault().Tail); + // Assert.Equal(nameof(SysUserMod),routeResults1.FirstOrDefault().ReplaceTables.FirstOrDefault().OriginalName); + // var ids = new[] {"339", "124","142"}; + // var queryable2= _virtualDbContext.Set().Where(o=>ids.Contains(o.Id)); + // var routeResult2s = _routingRuleEngineFactory.Route(queryable2); + // Assert.Equal(2,routeResult2s.Count()); + // Assert.Equal(1,routeResult2s.FirstOrDefault().ReplaceTables.Count()); + // Assert.Equal(2,routeResult2s.SelectMany(o=>o.ReplaceTables).Count()); + // Assert.Equal(true,routeResult2s.SelectMany(o=>o.ReplaceTables).All(o=>new[]{"0","1"}.Contains(o.Tail))); + //} + + [Fact] + public async Task ToList_All_Route_Test() + { + using (_shardingRouteManager.CreateScope()) + { + _shardingRouteManager.Current.Must.TryAdd(typeof(SysUserMod), new HashSet() { "00" }); + + var mod00s = await _virtualDbContext.Set().ToListAsync(); + Assert.Equal(333, mod00s.Count); + } + var mods = await _virtualDbContext.Set().ToListAsync(); + Assert.Equal(1000, mods.Count); + + var modOrders1 = await _virtualDbContext.Set().OrderBy(o => o.Age).ToListAsync(); + int ascAge = 1; + foreach (var sysUserMod in modOrders1) + { + Assert.Equal(ascAge, sysUserMod.Age); + ascAge++; + } + + + var modOrders2 = await _virtualDbContext.Set().OrderByDescending(o => o.Age).ToListAsync(); + int descAge = 1000; + foreach (var sysUserMod in modOrders2) + { + Assert.Equal(descAge, sysUserMod.Age); + descAge--; + } + } + + [Fact] + public async Task ToList_All_Test() + { + + var mods = await _virtualDbContext.Set().ToListAsync(); + Assert.Equal(1000, mods.Count); + + var modOrders1 = await _virtualDbContext.Set().OrderBy(o => o.Age).ToListAsync(); + int ascAge = 1; + foreach (var sysUserMod in modOrders1) + { + Assert.Equal(ascAge, sysUserMod.Age); + ascAge++; + } + + var modOrders2 = await _virtualDbContext.Set().OrderByDescending(o => o.Age).ToListAsync(); + int descAge = 1000; + foreach (var sysUserMod in modOrders2) + { + Assert.Equal(descAge, sysUserMod.Age); + descAge--; + } + + var pageResult = await _virtualDbContext.Set().Skip(10).Take(10).OrderByDescending(o => o.Age).ToListAsync(); + Assert.Equal(10, pageResult.Count); + int pageDescAge = 990; + foreach (var sysUserMod in pageResult) + { + Assert.Equal(pageDescAge, sysUserMod.Age); + pageDescAge--; + } + } + + [Fact] + public async Task ToList_Join_Test() + { + var list = await (from u in _virtualDbContext.Set() + join salary in _virtualDbContext.Set() + on u.Id equals salary.UserId + select new + { + u.Id, + u.Age, + Salary = salary.Salary, + DateOfMonth = salary.DateOfMonth, + Name = u.Name + }).ToListAsync(); + var list2 = list.OrderBy(o=>o.Age).Select(o=>o.Age).Distinct().ToList(); + Assert.Equal(24000, list.Count()); + Assert.Equal(24, list.Count(o => o.Name == "name_200")); + + + var queryable = (from u in _virtualDbContext.Set().Where(o => o.Id == "300") + join salary in _virtualDbContext.Set() + on u.Id equals salary.UserId + select new + { + Salary = salary.Salary, + DateOfMonth = salary.DateOfMonth, + Name = u.Name + }); + var list1 = await queryable.ToListAsync(); + Assert.Equal(24, list1.Count()); + Assert.DoesNotContain(list1, o => o.Name != "name_300"); + } + + [Fact] + public async Task ToList_OrderBy_Asc_Desc_Test() + { + var modascs = await _virtualDbContext.Set().OrderBy(o => o.Age).ToListAsync(); + Assert.Equal(1000, modascs.Count); + var i = 1; + foreach (var age in modascs) + { + Assert.Equal(i, age.Age); + i++; + } + + var moddescs = await _virtualDbContext.Set().OrderByDescending(o => o.Age).ToListAsync(); + Assert.Equal(1000, moddescs.Count); + var j = 1000; + foreach (var age in moddescs) + { + Assert.Equal(j, age.Age); + j--; + } + } + + [Fact] + public async Task ToList_Id_In_Test() + { + var ids = new[] {"1", "2", "3", "4"}; + var sysUserMods = await _virtualDbContext.Set().Where(o => ids.Contains(o.Id)).ToListAsync(); + foreach (var id in ids) + { + Assert.Contains(sysUserMods, o => o.Id == id); + } + + Assert.DoesNotContain(sysUserMods, o => o.Age > 4); + } + + [Fact] + public async Task ToList_Id_Eq_Test() + { + var mods = await _virtualDbContext.Set().Where(o => o.Id == "3").ToListAsync(); + Assert.Single(mods); + Assert.Equal("3", mods[0].Id); + } + + [Fact] + public async Task ToList_Id_Not_Eq_Test() + { + var mods = await _virtualDbContext.Set().Where(o => o.Id != "3").ToListAsync(); + Assert.Equal(999, mods.Count); + Assert.DoesNotContain(mods, o => o.Id == "3"); + } + + [Fact] + public async Task ToList_Id_Not_Eq_Skip_Test() + { + var mods = await _virtualDbContext.Set().Where(o => o.Id != "3").OrderBy(o => o.Age).Skip(2).ToListAsync(); + Assert.Equal(997, mods.Count); + Assert.DoesNotContain(mods, o => o.Id == "3"); + Assert.Equal(4, mods[0].Age); + Assert.Equal(5, mods[1].Age); + + var modsDesc = await _virtualDbContext.Set().Where(o => o.Id != "3").OrderByDescending(o => o.Age).Skip(13).ToListAsync(); + Assert.Equal(986, modsDesc.Count); + Assert.DoesNotContain(mods, o => o.Id == "3"); + Assert.Equal(987, modsDesc[0].Age); + Assert.Equal(986, modsDesc[1].Age); + } + + [Fact] + public async Task ToList_Name_Eq_Test() + { + var mods = await _virtualDbContext.Set().Where(o => o.Name == "name_3").ToListAsync(); + Assert.Single(mods); + Assert.Equal("3", mods[0].Id); + } + + [Fact] + public async Task ToList_Id_Eq_Not_In_Db_Test() + { + var mods = await _virtualDbContext.Set().Where(o => o.Id == "1001").ToListAsync(); + Assert.Empty(mods); + } + + [Fact] + public async Task ToList_Name_Eq_Not_In_Db_Test() + { + var mods = await _virtualDbContext.Set().Where(o => o.Name == "name_1001").ToListAsync(); + Assert.Empty(mods); + } + + [Fact] + public async Task FirstOrDefault_Order_By_Id_Test() + { + var sysUserModAge = await _virtualDbContext.Set().OrderBy(o => o.Age).FirstOrDefaultAsync(); + Assert.True(sysUserModAge != null && sysUserModAge.Id == "1"); + var sysUserModAgeDesc = await _virtualDbContext.Set().OrderByDescending(o => o.Age).FirstOrDefaultAsync(); + Assert.True(sysUserModAgeDesc != null && sysUserModAgeDesc.Id == "1000"); + var sysUserMod = await _virtualDbContext.Set().OrderBy(o => o.Id).FirstOrDefaultAsync(); + Assert.True(sysUserMod != null && sysUserMod.Id == "1"); + + var sysUserModDesc = await _virtualDbContext.Set().OrderByDescending(o => o.Id).FirstOrDefaultAsync(); + Assert.True(sysUserModDesc != null && sysUserModDesc.Id == "999"); + } + + [Fact] + public async Task FirstOrDefault2() + { + var sysUserMod = await _virtualDbContext.Set().Where(o => o.Id == "1").FirstOrDefaultAsync(); + Assert.NotNull(sysUserMod); + Assert.True(sysUserMod.Id == "1"); + var user198 = await _virtualDbContext.Set().FirstOrDefaultAsync(o => o.Id == "198"); + Assert.True(user198.Id == "198"); + var userId198 = await _virtualDbContext.Set().Where(o => o.Id == "198").Select(o => o.Id).FirstOrDefaultAsync(); + Assert.Equal(userId198, "198"); + } + + [Fact] + public async Task FirstOrDefault3() + { + var sysUserMod = await _virtualDbContext.Set().Where(o => o.Name == "name_2").FirstOrDefaultAsync(); + Assert.NotNull(sysUserMod); + Assert.Equal("2", sysUserMod.Id); + } + + [Fact] + public async Task FirstOrDefault4() + { + var sysUserMod = await _virtualDbContext.Set().Where(o => o.Id != "1").FirstOrDefaultAsync(); + Assert.NotNull(sysUserMod); + Assert.True(sysUserMod.Id != "1"); + } + + [Fact] + public async Task FirstOrDefault5() + { + var sysUserMod = await _virtualDbContext.Set().Where(o => o.Name == "name_1001").FirstOrDefaultAsync(); + Assert.Null(sysUserMod); + } + + [Fact] + public async Task Count_Test() + { + var a = await _virtualDbContext.Set().Where(o => o.Name == "name_1000").CountAsync(); + Assert.Equal(1, a); + var b = await _virtualDbContext.Set().Where(o => o.Name != "name_1000").CountAsync(); + Assert.Equal(999, b); + } + + [Fact] + public async Task Sum_Test() + { + var a = await _virtualDbContext.Set().SumAsync(o => o.Age); + var expected = 0; + for (int i = 1; i <= 1000; i++) + { + expected += i; + } + + Assert.Equal(expected, a); + var b = await _virtualDbContext.Set().Where(o => o.Name != "name_1000").SumAsync(o => o.Age); + Assert.Equal(expected - 1000, b); + } + + [Fact] + public async Task Max_Test() + { + var a = await _virtualDbContext.Set().MaxAsync(o => o.Age); + Assert.Equal(1000, a); + var b = await _virtualDbContext.Set().Where(o => o.Name != "name_1000").MaxAsync(o => o.Age); + Assert.Equal(999, b); + var c = await _virtualDbContext.Set().Where(o => o.Age < 500).MaxAsync(o => o.Age); + Assert.Equal(499, c); + var e = await _virtualDbContext.Set().Where(o => o.Age <= 500).MaxAsync(o => o.Age); + Assert.Equal(500, e); + } + + [Fact] + public async Task Max_Join_Test() + { + var queryable = (from u in _virtualDbContext.Set().Where(o => o.Id == "300") + join salary in _virtualDbContext.Set() + on u.Id equals salary.UserId + select new + { + Salary = salary.Salary, + DateOfMonth = salary.DateOfMonth, + Name = u.Name + }); + var maxSalary = await queryable.MaxAsync(o => o.Salary); + Assert.Equal(1390000, maxSalary); + } + + [Fact] + public async Task Min_Test() + { + var a = await _virtualDbContext.Set().MinAsync(o => o.Age); + Assert.Equal(1, a); + var b = await _virtualDbContext.Set().Where(o => o.Name != "name_1").MinAsync(o => o.Age); + Assert.Equal(2, b); + var c = await _virtualDbContext.Set().Where(o => o.Age > 500).MinAsync(o => o.Age); + Assert.Equal(501, c); + var e = await _virtualDbContext.Set().Where(o => o.Age >= 500).MinAsync(o => o.Age); + Assert.Equal(500, e); + } + + [Fact] + public async Task Any_Test() + { + var a = await _virtualDbContext.Set().AnyAsync(o => o.Age == 100); + Assert.True(a); + var b = await _virtualDbContext.Set().Where(o => o.Name != "name_1").AnyAsync(o => o.Age == 1); + Assert.False(b); + var c = await _virtualDbContext.Set().Where(o => o.Age > 500).AnyAsync(o => o.Age <= 500); + Assert.False(c); + var e = await _virtualDbContext.Set().Where(o => o.Age >= 500).AnyAsync(o => o.Age <= 500); + Assert.True(e); + } + + [Fact] + public async Task Group_Test() + { + var ids = new[] {"200", "300"}; + var dateOfMonths = new[] {202111, 202110}; + var group = await (from u in _virtualDbContext.Set() + .Where(o => ids.Contains(o.UserId) && dateOfMonths.Contains(o.DateOfMonth)) + group u by new + { + UId = u.UserId + } + into g + select new + { + GroupUserId = g.Key.UId, + Count = g.Count(), + TotalSalary = g.Sum(o => o.Salary), + AvgSalary = g.Average(o => o.Salary), + AvgSalaryDecimal = g.Average(o => o.SalaryDecimal), + MinSalary = g.Min(o => o.Salary), + MaxSalary = g.Max(o => o.Salary) + }).ToListAsync(); + Assert.Equal(2, group.Count); + Assert.Equal(2, group[0].Count); + Assert.Equal(2260000, group[0].TotalSalary); + Assert.Equal(1130000, group[0].AvgSalary); + Assert.Equal(11300, group[0].AvgSalaryDecimal); + Assert.Equal(1120000, group[0].MinSalary); + Assert.Equal(1140000, group[0].MaxSalary); + } + // [Fact] + // public async Task Group_API_Test() + // { + // var ids = new[] {"200", "300"}; + // var dateOfMonths = new[] {202111, 202110}; + // var group = await _virtualDbContext.Set() + // .Where(o => ids.Contains(o.UserId) && dateOfMonths.Contains(o.DateOfMonth)) + // .ShardingGroupByAsync(g => new {UId = g.UserId}, g => new + // { + // + // GroupUserId = g.Key.UId, + // Count = g.Count(), + // TotalSalary = g.Sum(o => o.Salary), + // AvgSalary = g.Average(o => o.Salary), + // AvgSalaryDecimal = g.Average(o => o.SalaryDecimal), + // MinSalary = g.Min(o => o.Salary), + // MaxSalary = g.Max(o => o.Salary) + // }); + // Assert.Equal(2, group.Count); + // Assert.Equal(2, group[0].Count); + // Assert.Equal(2260000, group[0].TotalSalary); + // Assert.Equal(1130000, group[0].AvgSalary); + // Assert.Equal(11300, group[0].AvgSalaryDecimal); + // Assert.Equal(1120000, group[0].MinSalary); + // Assert.Equal(1140000, group[0].MaxSalary); + // } + } +} \ No newline at end of file diff --git a/test/ShardingCore.Test50_2x/Shardings/SysUserModVirtualTableRoute.cs b/test/ShardingCore.Test50_2x/Shardings/SysUserModVirtualTableRoute.cs new file mode 100644 index 00000000..cb821e36 --- /dev/null +++ b/test/ShardingCore.Test50_2x/Shardings/SysUserModVirtualTableRoute.cs @@ -0,0 +1,20 @@ +using ShardingCore.Test50_2x.Domain.Entities; +using ShardingCore.VirtualRoutes.Mods; + +namespace ShardingCore.Test50_2x.Shardings +{ +/* +* @Author: xjm +* @Description: +* @Date: Thursday, 14 January 2021 15:39:27 +* @Email: 326308290@qq.com +*/ + public class SysUserModVirtualTableRoute : AbstractSimpleShardingModKeyStringVirtualTableRoute + { + protected override bool EnableHintRoute => true; + public SysUserModVirtualTableRoute() : base(2,3) + { + } + + } +} \ No newline at end of file diff --git a/test/ShardingCore.Test50_2x/Shardings/SysUserSalaryVirtualTableRoute.cs b/test/ShardingCore.Test50_2x/Shardings/SysUserSalaryVirtualTableRoute.cs new file mode 100644 index 00000000..87e5fbc0 --- /dev/null +++ b/test/ShardingCore.Test50_2x/Shardings/SysUserSalaryVirtualTableRoute.cs @@ -0,0 +1,75 @@ +using System; +using System.Collections.Generic; +using System.Linq.Expressions; +using ShardingCore.Core.VirtualRoutes; +using ShardingCore.Core.VirtualRoutes.TableRoutes; +using ShardingCore.Core.VirtualRoutes.TableRoutes.Abstractions; +using ShardingCore.Test50_2x.Domain.Entities; + +namespace ShardingCore.Test50_2x.Shardings +{ +/* +* @Author: xjm +* @Description: +* @Date: Monday, 01 February 2021 15:54:55 +* @Email: 326308290@qq.com +*/ + public class SysUserSalaryVirtualTableRoute:AbstractShardingOperatorVirtualTableRoute + { + protected override int ConvertToShardingKey(object shardingKey) + { + return Convert.ToInt32(shardingKey); + } + + public override string ShardingKeyToTail(object shardingKey) + { + var time = ConvertToShardingKey(shardingKey); + return TimeFormatToTail(time); + } + + + public override List GetAllTails() + { + var beginTime = new DateTime(2020, 1, 1); + var endTime = new DateTime(2021, 12, 1); + var list = new List(24); + var tempTime = beginTime; + while (tempTime <= endTime) + { + list.Add($"{tempTime:yyyyMM}"); + tempTime = tempTime.AddMonths(1); + } + + return list; + } + + protected string TimeFormatToTail(int time) + { + var dateOfMonth=DateTime.ParseExact($"{time}","yyyyMM",System.Globalization.CultureInfo.InvariantCulture,System.Globalization.DateTimeStyles.AdjustToUniversal); + return $"{dateOfMonth:yyyyMM}"; + } + + protected override Expression> GetRouteToFilter(int shardingKey, ShardingOperatorEnum shardingOperator) + { + var t = TimeFormatToTail(shardingKey); + switch (shardingOperator) + { + case ShardingOperatorEnum.GreaterThan: + case ShardingOperatorEnum.GreaterThanOrEqual: + return tail => String.Compare(tail, t, StringComparison.Ordinal) >= 0; + case ShardingOperatorEnum.LessThan: + return tail => String.Compare(tail, t, StringComparison.Ordinal) < 0; + case ShardingOperatorEnum.LessThanOrEqual: + return tail => String.Compare(tail, t, StringComparison.Ordinal) <= 0; + case ShardingOperatorEnum.Equal: return tail => tail == t; + default: + { +#if DEBUG + Console.WriteLine($"shardingOperator is not equal scan all table tail"); +#endif + return tail => true; + } + } + } + } +} \ No newline at end of file diff --git a/test/ShardingCore.Test50_2x/Startup.cs b/test/ShardingCore.Test50_2x/Startup.cs new file mode 100644 index 00000000..bbef08fc --- /dev/null +++ b/test/ShardingCore.Test50_2x/Startup.cs @@ -0,0 +1,123 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Storage; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using ShardingCore.EFCores; +using ShardingCore.Test50_2x.Domain.Entities; +using ShardingCore.Test50_2x.Shardings; + +namespace ShardingCore.Test50_2x +{ + /* + * @Author: xjm + * @Description: + * @Date: Friday, 15 January 2021 15:37:46 + * @Email: 326308290@qq.com + */ + public class Startup + { + public static readonly ILoggerFactory efLogger = LoggerFactory.Create(builder => + { + builder.AddFilter((category, level) => category == DbLoggerCategory.Database.Command.Name && level == LogLevel.Information).AddConsole(); + }); + // // 自定义 host 构建 + public void ConfigureHost(IHostBuilder hostBuilder) + { + hostBuilder + .ConfigureAppConfiguration(builder => + { + builder.AddJsonFile("Configs/DbConfig.json"); + //builder.AddJsonFile("Configs/MacDbConfig.json"); + }); + } + + // 支持的形式: + // ConfigureServices(IServiceCollection services) + // ConfigureServices(IServiceCollection services, HostBuilderContext hostBuilderContext) + // ConfigureServices(HostBuilderContext hostBuilderContext, IServiceCollection services) + public void ConfigureServices(IServiceCollection services, HostBuilderContext hostBuilderContext) + { + services.AddDbContext(); + services.AddShardingDbContext(o => o.UseSqlServer(hostBuilderContext.Configuration.GetSection("SqlServer")["ConnectionString"]) + , op => + { + op.EnsureCreatedWithOutShardingTable = true; + op.CreateShardingTableOnStart = true; + op.UseShardingOptionsBuilder((connection, builder) => builder.UseSqlServer(connection).UseLoggerFactory(efLogger), + (conStr,builder)=> builder.UseSqlServer(conStr).UseLoggerFactory(efLogger)); + op.AddShardingTableRoute(); + op.AddShardingTableRoute(); + }); + } + + // 可以添加要用到的方法参数,会自动从注册的服务中获取服务实例,类似于 asp.net core 里 Configure 方法 + public void Configure(IServiceProvider serviceProvider) + { + var shardingBootstrapper = serviceProvider.GetService(); + shardingBootstrapper.Start(); + // 有一些测试数据要初始化可以放在这里 + InitData(serviceProvider).GetAwaiter().GetResult(); + } + + /// + /// 添加种子数据 + /// + /// + /// + private async Task InitData(IServiceProvider serviceProvider) + { + using (var scope = serviceProvider.CreateScope()) + { + var virtualDbContext = scope.ServiceProvider.GetService(); + if (!await virtualDbContext.Set().AnyAsync()) + { + var ids = Enumerable.Range(1, 1000); + var userMods = new List(); + var userSalaries = new List(); + var beginTime = new DateTime(2020, 1, 1); + var endTime = new DateTime(2021, 12, 1); + foreach (var id in ids) + { + userMods.Add(new SysUserMod() + { + Id = id.ToString(), + Age = id, + Name = $"name_{id}", + AgeGroup = Math.Abs(id % 10) + }); + var tempTime = beginTime; + var i = 0; + while (tempTime <= endTime) + { + var dateOfMonth = $@"{tempTime:yyyyMM}"; + userSalaries.Add(new SysUserSalary() + { + Id = $@"{id}{dateOfMonth}", + UserId = id.ToString(), + DateOfMonth = int.Parse(dateOfMonth), + Salary = 700000 + id * 100 * i, + SalaryLong = 700000 + id * 100 * i, + SalaryDecimal = (700000 + id * 100 * i) / 100m, + SalaryDouble = (700000 + id * 100 * i) / 100d, + SalaryFloat = (700000 + id * 100 * i) / 100f + }); + tempTime = tempTime.AddMonths(1); + i++; + } + } + + await virtualDbContext.AddRangeAsync(userMods); + await virtualDbContext.AddRangeAsync(userSalaries); + + await virtualDbContext.SaveChangesAsync(); + } + } + } + } +} \ No newline at end of file