diff --git a/ShardingCore.sln b/ShardingCore.sln
index ca7bc3e8..97005a1f 100644
--- a/ShardingCore.sln
+++ b/ShardingCore.sln
@@ -57,6 +57,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sample.ShardingConsole", "s
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sample.OracleIssue", "samples\Sample.OracleIssue\Sample.OracleIssue.csproj", "{BF4FEA2A-3F09-47D8-9BF7-4261D8D1671D}"
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src2_6", "src2_6", "{5C015EB7-678C-421E-BB84-30EDCCCE0AB6}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ShardingCore.2_6", "src2_6\ShardingCore.2_6\ShardingCore.2_6.csproj", "{B8B27249-E775-4A8F-BF64-B64C6B34DAA3}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ShardingCore.Test6x", "test\ShardingCore.Test6x\ShardingCore.Test6x.csproj", "{8ED3A191-5A29-4599-B383-9FD225CC0BA2}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -155,6 +161,14 @@ Global
{BF4FEA2A-3F09-47D8-9BF7-4261D8D1671D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BF4FEA2A-3F09-47D8-9BF7-4261D8D1671D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BF4FEA2A-3F09-47D8-9BF7-4261D8D1671D}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B8B27249-E775-4A8F-BF64-B64C6B34DAA3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B8B27249-E775-4A8F-BF64-B64C6B34DAA3}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B8B27249-E775-4A8F-BF64-B64C6B34DAA3}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B8B27249-E775-4A8F-BF64-B64C6B34DAA3}.Release|Any CPU.Build.0 = Release|Any CPU
+ {8ED3A191-5A29-4599-B383-9FD225CC0BA2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {8ED3A191-5A29-4599-B383-9FD225CC0BA2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {8ED3A191-5A29-4599-B383-9FD225CC0BA2}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {8ED3A191-5A29-4599-B383-9FD225CC0BA2}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -183,6 +197,8 @@ Global
{3E895438-E609-4860-8391-6897ED55DA06} = {CC2C88C0-65F2-445D-BE78-973B840FE281}
{BAB101D4-2BFF-44CE-90E3-8B72DDB266B8} = {EDF8869A-C1E1-491B-BC9F-4A33F4DE1C73}
{BF4FEA2A-3F09-47D8-9BF7-4261D8D1671D} = {EDF8869A-C1E1-491B-BC9F-4A33F4DE1C73}
+ {B8B27249-E775-4A8F-BF64-B64C6B34DAA3} = {5C015EB7-678C-421E-BB84-30EDCCCE0AB6}
+ {8ED3A191-5A29-4599-B383-9FD225CC0BA2} = {CC2C88C0-65F2-445D-BE78-973B840FE281}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {8C07A667-E8B4-43C7-8053-721584BAD291}
diff --git a/benchmarks/ShardingCoreBenchmark/ShardingCoreBenchmark.csproj b/benchmarks/ShardingCoreBenchmark/ShardingCoreBenchmark.csproj
index c74474c3..5e8de405 100644
--- a/benchmarks/ShardingCoreBenchmark/ShardingCoreBenchmark.csproj
+++ b/benchmarks/ShardingCoreBenchmark/ShardingCoreBenchmark.csproj
@@ -17,7 +17,7 @@
-
+
diff --git a/benchmarks/ShardingCoreBenchmark5x/ShardingCoreBenchmark5x.csproj b/benchmarks/ShardingCoreBenchmark5x/ShardingCoreBenchmark5x.csproj
index 197d1354..3cdc6e75 100644
--- a/benchmarks/ShardingCoreBenchmark5x/ShardingCoreBenchmark5x.csproj
+++ b/benchmarks/ShardingCoreBenchmark5x/ShardingCoreBenchmark5x.csproj
@@ -11,8 +11,8 @@
-
-
+
+
diff --git a/nuget-publish.bat b/nuget-publish.bat
index 152fef52..4c3631d0 100644
--- a/nuget-publish.bat
+++ b/nuget-publish.bat
@@ -1,6 +1,7 @@
:start
::定义版本
-set SHARDINGCORE=6.8.0.5
+set SHARDINGCORE7=7.0.0.1
+set SHARDINGCORE2_6=6.8.0.5
::删除所有bin与obj下的文件
@echo off
diff --git a/samples/Sample.AutoCreateIfPresent/Sample.AutoCreateIfPresent.csproj b/samples/Sample.AutoCreateIfPresent/Sample.AutoCreateIfPresent.csproj
index f8cd0e56..128682ae 100644
--- a/samples/Sample.AutoCreateIfPresent/Sample.AutoCreateIfPresent.csproj
+++ b/samples/Sample.AutoCreateIfPresent/Sample.AutoCreateIfPresent.csproj
@@ -13,7 +13,7 @@
-
+
diff --git a/samples/Sample.BulkConsole/Sample.BulkConsole.csproj b/samples/Sample.BulkConsole/Sample.BulkConsole.csproj
index e0e13412..c4f054d1 100644
--- a/samples/Sample.BulkConsole/Sample.BulkConsole.csproj
+++ b/samples/Sample.BulkConsole/Sample.BulkConsole.csproj
@@ -10,7 +10,7 @@
-
+
diff --git a/samples/Sample.Migrations/RemoveForeignKeyMigrationsModelDiffer.cs b/samples/Sample.Migrations/RemoveForeignKeyMigrationsModelDiffer.cs
index 4e8898d2..ef277dc4 100644
--- a/samples/Sample.Migrations/RemoveForeignKeyMigrationsModelDiffer.cs
+++ b/samples/Sample.Migrations/RemoveForeignKeyMigrationsModelDiffer.cs
@@ -22,9 +22,6 @@ namespace Sample.Migrations
[SuppressMessage("Usage", "EF1001:Internal EF Core API usage.", Justification = "<挂起>")]
public class RemoveForeignKeyMigrationsModelDiffer:MigrationsModelDiffer
{
- public RemoveForeignKeyMigrationsModelDiffer(IRelationalTypeMappingSource typeMappingSource, IMigrationsAnnotationProvider migrationsAnnotations, IChangeDetector changeDetector, IUpdateAdapterFactory updateAdapterFactory, CommandBatchPreparerDependencies commandBatchPreparerDependencies) : base(typeMappingSource, migrationsAnnotations, changeDetector, updateAdapterFactory, commandBatchPreparerDependencies)
- {
- }
public override IReadOnlyList GetDifferences(IRelationalModel? source, IRelationalModel? target)
{
@@ -36,5 +33,9 @@ namespace Sample.Migrations
}
return sourceOperations;
}
+
+ public RemoveForeignKeyMigrationsModelDiffer(IRelationalTypeMappingSource typeMappingSource, IMigrationsAnnotationProvider migrationsAnnotations, IChangeDetector changeDetector, IUpdateAdapterFactory updateAdapterFactory, CommandBatchPreparerDependencies commandBatchPreparerDependencies) : base(typeMappingSource, migrationsAnnotations, changeDetector, updateAdapterFactory, commandBatchPreparerDependencies)
+ {
+ }
}
}
\ No newline at end of file
diff --git a/samples/Sample.Migrations/Sample.Migrations.csproj b/samples/Sample.Migrations/Sample.Migrations.csproj
index a5bba585..bcaeb1ae 100644
--- a/samples/Sample.Migrations/Sample.Migrations.csproj
+++ b/samples/Sample.Migrations/Sample.Migrations.csproj
@@ -13,7 +13,7 @@
-
+
diff --git a/samples/Sample.MultiConfig/Sample.MultiConfig.csproj b/samples/Sample.MultiConfig/Sample.MultiConfig.csproj
index 949ce3e5..f384fd36 100644
--- a/samples/Sample.MultiConfig/Sample.MultiConfig.csproj
+++ b/samples/Sample.MultiConfig/Sample.MultiConfig.csproj
@@ -12,7 +12,7 @@
-
+
diff --git a/samples/Sample.MySql/Sample.MySql.csproj b/samples/Sample.MySql/Sample.MySql.csproj
index 7d8e1180..8c24e2c5 100644
--- a/samples/Sample.MySql/Sample.MySql.csproj
+++ b/samples/Sample.MySql/Sample.MySql.csproj
@@ -16,7 +16,7 @@
-
+
diff --git a/samples/Sample.NoShardingMultiLevel/Sample.NoShardingMultiLevel.csproj b/samples/Sample.NoShardingMultiLevel/Sample.NoShardingMultiLevel.csproj
index c95271a4..4fdafaa8 100644
--- a/samples/Sample.NoShardingMultiLevel/Sample.NoShardingMultiLevel.csproj
+++ b/samples/Sample.NoShardingMultiLevel/Sample.NoShardingMultiLevel.csproj
@@ -11,7 +11,7 @@
-
+
diff --git a/samples/Sample.OracleIssue/Sample.OracleIssue.csproj b/samples/Sample.OracleIssue/Sample.OracleIssue.csproj
index d3b78241..52b19498 100644
--- a/samples/Sample.OracleIssue/Sample.OracleIssue.csproj
+++ b/samples/Sample.OracleIssue/Sample.OracleIssue.csproj
@@ -15,7 +15,7 @@
-
+
diff --git a/samples/Sample.ShardingConsole/Sample.ShardingConsole.csproj b/samples/Sample.ShardingConsole/Sample.ShardingConsole.csproj
index 9c8c6ace..be9b0f53 100644
--- a/samples/Sample.ShardingConsole/Sample.ShardingConsole.csproj
+++ b/samples/Sample.ShardingConsole/Sample.ShardingConsole.csproj
@@ -8,7 +8,7 @@
-
+
diff --git a/samples/Sample.SqlServer/Sample.SqlServer.csproj b/samples/Sample.SqlServer/Sample.SqlServer.csproj
index 6bd6e59f..47eec57f 100644
--- a/samples/Sample.SqlServer/Sample.SqlServer.csproj
+++ b/samples/Sample.SqlServer/Sample.SqlServer.csproj
@@ -16,7 +16,7 @@
-
+
diff --git a/samples/Sample.SqlServer/UnionAllMerge/ShardingCoreSqlServerExtension.cs b/samples/Sample.SqlServer/UnionAllMerge/ShardingCoreSqlServerExtension.cs
index cd5c9da0..9e28aa55 100644
--- a/samples/Sample.SqlServer/UnionAllMerge/ShardingCoreSqlServerExtension.cs
+++ b/samples/Sample.SqlServer/UnionAllMerge/ShardingCoreSqlServerExtension.cs
@@ -4,7 +4,7 @@ using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Query;
using Microsoft.EntityFrameworkCore.Query.Internal;
using ShardingCore.Core.ShardingConfigurations;
-using ShardingCore.EFCores.OptionsExtensions;
+using ShardingCore.EFCores;
using ShardingCore.Sharding.Abstractions;
namespace Sample.SqlServer.UnionAllMerge
diff --git a/samples/Sample.SqlServer3x/Sample.SqlServer3x.csproj b/samples/Sample.SqlServer3x/Sample.SqlServer3x.csproj
index afba6721..19dde831 100644
--- a/samples/Sample.SqlServer3x/Sample.SqlServer3x.csproj
+++ b/samples/Sample.SqlServer3x/Sample.SqlServer3x.csproj
@@ -8,8 +8,8 @@
-
-
+
+
diff --git a/samples/Sample.SqlServerShardingAll/Sample.SqlServerShardingAll.csproj b/samples/Sample.SqlServerShardingAll/Sample.SqlServerShardingAll.csproj
index f6c09ec1..9517e637 100644
--- a/samples/Sample.SqlServerShardingAll/Sample.SqlServerShardingAll.csproj
+++ b/samples/Sample.SqlServerShardingAll/Sample.SqlServerShardingAll.csproj
@@ -9,7 +9,7 @@
-
+
diff --git a/samples/Sample.SqlServerShardingDataSource/Sample.SqlServerShardingDataSource.csproj b/samples/Sample.SqlServerShardingDataSource/Sample.SqlServerShardingDataSource.csproj
index 5aef5a2e..19fa28ac 100644
--- a/samples/Sample.SqlServerShardingDataSource/Sample.SqlServerShardingDataSource.csproj
+++ b/samples/Sample.SqlServerShardingDataSource/Sample.SqlServerShardingDataSource.csproj
@@ -11,7 +11,7 @@
-
+
diff --git a/samples/Sample.SqlServerShardingTable/Sample.SqlServerShardingTable.csproj b/samples/Sample.SqlServerShardingTable/Sample.SqlServerShardingTable.csproj
index f6c09ec1..9517e637 100644
--- a/samples/Sample.SqlServerShardingTable/Sample.SqlServerShardingTable.csproj
+++ b/samples/Sample.SqlServerShardingTable/Sample.SqlServerShardingTable.csproj
@@ -9,7 +9,7 @@
-
+
diff --git a/samples/Samples.AbpSharding/AbstractShardingAbpDbContext.cs b/samples/Samples.AbpSharding/AbstractShardingAbpDbContext.cs
index 2a86153e..27907862 100644
--- a/samples/Samples.AbpSharding/AbstractShardingAbpDbContext.cs
+++ b/samples/Samples.AbpSharding/AbstractShardingAbpDbContext.cs
@@ -10,7 +10,7 @@ using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
-using ShardingCore.EFCores.OptionsExtensions;
+using ShardingCore.EFCores;
using ShardingCore.Helpers;
using ShardingCore.Utils;
using Volo.Abp.Domain.Entities;
diff --git a/samples/Samples.AbpSharding/AbstractShardingAbpZeroDbContext.cs b/samples/Samples.AbpSharding/AbstractShardingAbpZeroDbContext.cs
index b2cb0748..ff81b29d 100644
--- a/samples/Samples.AbpSharding/AbstractShardingAbpZeroDbContext.cs
+++ b/samples/Samples.AbpSharding/AbstractShardingAbpZeroDbContext.cs
@@ -18,7 +18,7 @@ using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using ShardingCore.Core.VirtualDatabase.VirtualDataSources;
using ShardingCore.Core.VirtualRoutes.TableRoutes.RouteTails.Abstractions;
-using ShardingCore.EFCores.OptionsExtensions;
+using ShardingCore.EFCores;
using ShardingCore.Extensions;
using ShardingCore.Sharding;
using ShardingCore.Sharding.Abstractions;
diff --git a/samples/Samples.AbpSharding/Samples.AbpSharding.csproj b/samples/Samples.AbpSharding/Samples.AbpSharding.csproj
index b62ce798..87474750 100644
--- a/samples/Samples.AbpSharding/Samples.AbpSharding.csproj
+++ b/samples/Samples.AbpSharding/Samples.AbpSharding.csproj
@@ -11,7 +11,7 @@
-
+
diff --git a/samples/Samples.AutoByDate.SqlServer/RemoveForeignKeyMigrationsModelDiffer.cs b/samples/Samples.AutoByDate.SqlServer/RemoveForeignKeyMigrationsModelDiffer.cs
index bdbac891..42a59e41 100644
--- a/samples/Samples.AutoByDate.SqlServer/RemoveForeignKeyMigrationsModelDiffer.cs
+++ b/samples/Samples.AutoByDate.SqlServer/RemoveForeignKeyMigrationsModelDiffer.cs
@@ -20,9 +20,6 @@ namespace Samples.AutoByDate.SqlServer
{
nameof(SysUserLog1ByDay)
};
- public RemoveForeignKeyMigrationsModelDiffer(IRelationalTypeMappingSource typeMappingSource, IMigrationsAnnotationProvider migrationsAnnotations, IChangeDetector changeDetector, IUpdateAdapterFactory updateAdapterFactory, CommandBatchPreparerDependencies commandBatchPreparerDependencies) : base(typeMappingSource, migrationsAnnotations, changeDetector, updateAdapterFactory, commandBatchPreparerDependencies)
- {
- }
public override IReadOnlyList GetDifferences(IRelationalModel? source, IRelationalModel? target)
{
@@ -34,5 +31,9 @@ namespace Samples.AutoByDate.SqlServer
}
return sourceOperations;
}
+
+ public RemoveForeignKeyMigrationsModelDiffer(IRelationalTypeMappingSource typeMappingSource, IMigrationsAnnotationProvider migrationsAnnotations, IChangeDetector changeDetector, IUpdateAdapterFactory updateAdapterFactory, CommandBatchPreparerDependencies commandBatchPreparerDependencies) : base(typeMappingSource, migrationsAnnotations, changeDetector, updateAdapterFactory, commandBatchPreparerDependencies)
+ {
+ }
}
}
diff --git a/samples/Samples.AutoByDate.SqlServer/Samples.AutoByDate.SqlServer.csproj b/samples/Samples.AutoByDate.SqlServer/Samples.AutoByDate.SqlServer.csproj
index 61fa7c10..37b0ff4c 100644
--- a/samples/Samples.AutoByDate.SqlServer/Samples.AutoByDate.SqlServer.csproj
+++ b/samples/Samples.AutoByDate.SqlServer/Samples.AutoByDate.SqlServer.csproj
@@ -9,7 +9,7 @@
-
+
diff --git a/src/ShardingCore/EFCores/EFCore2x/ScriptMigrationGenerator.cs b/src/ShardingCore/EFCores/EFCore2x/ScriptMigrationGenerator.cs
index e6c836c5..1f4e6a2f 100644
--- a/src/ShardingCore/EFCores/EFCore2x/ScriptMigrationGenerator.cs
+++ b/src/ShardingCore/EFCores/EFCore2x/ScriptMigrationGenerator.cs
@@ -1,4 +1,4 @@
-#if NETCOREAPP2_0
+#if NETCOREAPP2_0&&SHARDINGCORE2_6
using Microsoft.EntityFrameworkCore.Migrations;
using ShardingCore.Core.RuntimeContexts;
diff --git a/src/ShardingCore/EFCores/EFCore2x/ShardingChangeTracker.cs b/src/ShardingCore/EFCores/EFCore2x/ShardingChangeTracker.cs
new file mode 100644
index 00000000..abf643d6
--- /dev/null
+++ b/src/ShardingCore/EFCores/EFCore2x/ShardingChangeTracker.cs
@@ -0,0 +1,111 @@
+#if NETCOREAPP2_0&&SHARDINGCORE2_6
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.ChangeTracking;
+using Microsoft.EntityFrameworkCore.ChangeTracking.Internal;
+using Microsoft.EntityFrameworkCore.Metadata;
+using ShardingCore.Sharding.Abstractions;
+
+namespace ShardingCore.EFCores
+{
+ public class ShardingChangeTracker : ChangeTracker
+ {
+ private readonly DbContext _dbContext;
+
+ public ShardingChangeTracker(DbContext context, IStateManager stateManager, IChangeDetector changeDetector,
+ IModel model, IEntityEntryGraphIterator graphIterator) : base(context, stateManager, changeDetector, model,
+ graphIterator)
+ {
+ _dbContext = context;
+ }
+
+ public override bool HasChanges()
+ {
+ if (_dbContext is IShardingDbContext shardingDbContext)
+ {
+ return shardingDbContext.GetShardingExecutor().GetCurrentDbContexts().Any(o =>
+ o.Value.GetCurrentContexts().Any(r => r.Value.ChangeTracker.HasChanges()));
+ }
+
+ return base.HasChanges();
+ }
+
+ public override IEnumerable Entries()
+ {
+ if (_dbContext is IShardingDbContext shardingDbContext)
+ {
+ return shardingDbContext.GetShardingExecutor().GetCurrentDbContexts().SelectMany(o =>
+ o.Value.GetCurrentContexts().SelectMany(cd => cd.Value.ChangeTracker.Entries()));
+ }
+
+ return base.Entries();
+ }
+
+ public override IEnumerable> Entries()
+ {
+ if (_dbContext is IShardingDbContext shardingDbContext)
+ {
+ return shardingDbContext.GetShardingExecutor().GetCurrentDbContexts().SelectMany(o =>
+ o.Value.GetCurrentContexts().SelectMany(cd => cd.Value.ChangeTracker.Entries()));
+ }
+
+ return base.Entries();
+ }
+
+ public override void DetectChanges()
+ {
+ if (_dbContext is IShardingDbContext)
+ {
+ Do(c => c.DetectChanges());
+ return;
+ }
+ base.DetectChanges();
+ }
+
+ public override void AcceptAllChanges()
+ {
+ if (_dbContext is IShardingDbContext)
+ {
+ Do(c => c.AcceptAllChanges());
+ return;
+ }
+ base.AcceptAllChanges();
+ }
+
+ private void Do(Action action)
+ {
+ var dataSourceDbContexts = ((IShardingDbContext)_dbContext).GetShardingExecutor().GetCurrentDbContexts();
+ foreach (var dataSourceDbContext in dataSourceDbContexts)
+ {
+ var currentContexts = dataSourceDbContext.Value.GetCurrentContexts();
+ foreach (var keyValuePair in currentContexts)
+ {
+ action(keyValuePair.Value.ChangeTracker);
+ }
+ }
+ }
+
+ public override void TrackGraph(object rootEntity, Action callback)
+ {
+ if (_dbContext is IShardingDbContext shardingDbContext)
+ {
+ var genericDbContext = shardingDbContext.CreateGenericDbContext(rootEntity);
+ genericDbContext.ChangeTracker.TrackGraph(rootEntity,callback);
+ // Do(c => c.TrackGraph(rootEntity,callback));
+ }
+ }
+
+ public override void TrackGraph(object rootEntity, TState state, Func callback)
+ {
+ if (_dbContext is IShardingDbContext shardingDbContext)
+ {
+ var genericDbContext = shardingDbContext.CreateGenericDbContext(rootEntity);
+ genericDbContext.ChangeTracker.TrackGraph(rootEntity,state,callback);
+ // Do(c => c.TrackGraph(rootEntity,callback));
+ }
+ }
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/ShardingCore/EFCores/EFCore2x/ShardingDbSetSource.cs b/src/ShardingCore/EFCores/EFCore2x/ShardingDbSetSource.cs
new file mode 100644
index 00000000..e4cf51b6
--- /dev/null
+++ b/src/ShardingCore/EFCores/EFCore2x/ShardingDbSetSource.cs
@@ -0,0 +1,62 @@
+#if NETCOREAPP2_0 && SHARDINGCORE2_6
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Internal;
+using System;
+using System.Collections.Concurrent;
+using System.Reflection;
+
+namespace ShardingCore.EFCores
+{
+ /*
+ * @Author: xjm
+ * @Description:
+ * @Date: Saturday, 14 August 2021 10:17:43
+ * @Email: 326308290@qq.com
+ */
+
+ ///
+ /// 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/EFCore2x/ShardingInternalDbQuery.cs
similarity index 90%
rename from src/ShardingCore/EFCores/ShardingInternalDbQuery.cs
rename to src/ShardingCore/EFCores/EFCore2x/ShardingInternalDbQuery.cs
index ec5cb4b7..38b171a2 100644
--- a/src/ShardingCore/EFCores/ShardingInternalDbQuery.cs
+++ b/src/ShardingCore/EFCores/EFCore2x/ShardingInternalDbQuery.cs
@@ -1,4 +1,5 @@
-using System;
+#if NETCOREAPP2_0 && SHARDINGCORE2_6
+using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.EntityFrameworkCore;
@@ -13,7 +14,7 @@ namespace ShardingCore.EFCores
* @Ver: 1.0
* @Email: 326308290@qq.com
*/
-#if NETCOREAPP2_0
+
public class ShardingInternalDbQuery : InternalDbQuery where TQuery : class
{
@@ -21,5 +22,6 @@ namespace ShardingCore.EFCores
{
}
}
-#endif
+
}
+#endif
diff --git a/src/ShardingCore/EFCores/EFCore2x/ShardingInternalDbSet.cs b/src/ShardingCore/EFCores/EFCore2x/ShardingInternalDbSet.cs
new file mode 100644
index 00000000..43eba354
--- /dev/null
+++ b/src/ShardingCore/EFCores/EFCore2x/ShardingInternalDbSet.cs
@@ -0,0 +1,427 @@
+#if NETCOREAPP2_0 && SHARDINGCORE2_6
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.ChangeTracking;
+using Microsoft.EntityFrameworkCore.Internal;
+using ShardingCore.Core;
+using ShardingCore.Sharding.Abstractions;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using ShardingCore.Core.EntityMetadatas;
+using ShardingCore.Core.RuntimeContexts;
+using ShardingCore.Core.TrackerManagers;
+using ShardingCore.Core.VirtualDatabase.VirtualDataSources;
+using ShardingCore.Core.VirtualRoutes.Abstractions;
+using ShardingCore.Exceptions;
+using ShardingCore.Extensions;
+using ShardingCore.Utils;
+
+namespace ShardingCore.EFCores
+{
+ /*
+ * @Author: xjm
+ * @Description:
+ * @Date: 2021/8/15 8:39:15
+ * @Ver: 1.0
+ * @Email: 326308290@qq.com
+ */
+
+ public class ShardingInternalDbSet : InternalDbSet
+ where TEntity : class
+ {
+ private readonly IShardingDbContext _context;
+ private readonly IShardingRuntimeContext _shardingRuntimeContext;
+ private LocalView? _localView;
+
+ public ShardingInternalDbSet(DbContext context) : base(context)
+ {
+ _context = (IShardingDbContext)context;
+ _shardingRuntimeContext = context.GetShardingRuntimeContext();
+ }
+
+ private IDataSourceRouteManager _dataSourceRouteManager;
+
+ protected IDataSourceRouteManager DataSourceRouteManager
+ {
+ get
+ {
+ if (null == _dataSourceRouteManager)
+ {
+ _dataSourceRouteManager = _shardingRuntimeContext.GetDataSourceRouteManager();
+ }
+
+ return _dataSourceRouteManager;
+ }
+ }
+
+ public override LocalView Local
+ {
+ get
+ {
+
+ if (((DbContext)_context).ChangeTracker.AutoDetectChangesEnabled)
+ {
+ ((DbContext)_context).ChangeTracker.DetectChanges();
+ }
+
+ return _localView ??= new ShardingLocalView(this);
+ }
+ }
+ private ITableRouteManager _tableRouteManager;
+
+ protected ITableRouteManager TableRouteManager
+ {
+ get
+ {
+ if (null == _tableRouteManager)
+ {
+ _tableRouteManager = _shardingRuntimeContext.GetTableRouteManager();
+ }
+
+ return _tableRouteManager;
+ }
+ }
+
+ private IEntityMetadataManager _entityMetadataManager;
+
+ protected IEntityMetadataManager EntityMetadataManager
+ {
+ get
+ {
+ if (null == _entityMetadataManager)
+ {
+ _entityMetadataManager = _shardingRuntimeContext.GetEntityMetadataManager();
+ }
+
+ return _entityMetadataManager;
+ }
+ }
+
+ private ITrackerManager _trackerManager;
+
+ protected ITrackerManager TrackerManager
+ {
+ get
+ {
+ if (null == _trackerManager)
+ {
+ _trackerManager = _shardingRuntimeContext.GetTrackerManager();
+ }
+
+ return _trackerManager;
+ }
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// 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.
+ ///
+ public override EntityEntry Add(TEntity entity)
+ {
+ var genericDbContext = _context.CreateGenericDbContext(entity);
+ return genericDbContext.Set().Add(entity);
+ }
+
+ public override async Task> AddAsync(TEntity entity, CancellationToken cancellationToken =
+ new CancellationToken())
+ {
+ var genericDbContext = _context.CreateGenericDbContext(entity);
+ return await genericDbContext.Set().AddAsync(entity, cancellationToken);
+ }
+
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// 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.
+ ///
+ public override EntityEntry Attach(TEntity entity)
+ {
+ var genericDbContext = _context.CreateGenericDbContext(entity);
+ return genericDbContext.Set().Attach(entity);
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// 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.
+ ///
+ public override EntityEntry Remove(TEntity entity)
+ {
+ Check.NotNull(entity, nameof(entity));
+
+ var genericDbContext = _context.CreateGenericDbContext(entity);
+ return genericDbContext.Set().Remove(entity);
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// 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.
+ ///
+ public override EntityEntry Update(TEntity entity)
+ {
+ var genericDbContext = _context.CreateGenericDbContext(entity);
+ return genericDbContext.Set().Update(entity);
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// 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.
+ ///
+ public override void AddRange(params TEntity[] entities)
+ {
+ var aggregateToDic = AggregateToDic(entities);
+ foreach (var aggregateKv in aggregateToDic)
+ {
+ aggregateKv.Key.Set().AddRange(aggregateKv.Value);
+ }
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// 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.
+ ///
+ public override async Task AddRangeAsync(params TEntity[] entities)
+ {
+ var aggregateToDic = AggregateToDic(entities);
+ foreach (var aggregateKv in aggregateToDic)
+ {
+ await aggregateKv.Key.Set().AddRangeAsync(aggregateKv.Value);
+ }
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// 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.
+ ///
+ public override void AttachRange(params TEntity[] entities)
+ {
+ var aggregateToDic = AggregateToDic(entities);
+ foreach (var aggregateKv in aggregateToDic)
+ {
+ aggregateKv.Key.Set().AttachRange(aggregateKv.Value);
+ }
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// 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.
+ ///
+ public override void RemoveRange(params TEntity[] entities)
+ {
+ Check.NotNull(entities, nameof(entities));
+ var aggregateToDic = AggregateToDic(entities);
+ foreach (var aggregateKv in aggregateToDic)
+ {
+ aggregateKv.Key.Set().RemoveRange(aggregateKv.Value);
+ }
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// 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.
+ ///
+ public override void UpdateRange(params TEntity[] entities)
+ {
+ var aggregateToDic = AggregateToDic(entities);
+ foreach (var aggregateKv in aggregateToDic)
+ {
+ aggregateKv.Key.Set().UpdateRange(aggregateKv.Value);
+ }
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// 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.
+ ///
+ public override void AddRange(IEnumerable entities)
+ {
+ var aggregateToDic = AggregateToDic(entities);
+ foreach (var aggregateKv in aggregateToDic)
+ {
+ aggregateKv.Key.Set().AddRange(aggregateKv.Value);
+ }
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// 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.
+ ///
+ public override async Task AddRangeAsync(
+ IEnumerable entities,
+ CancellationToken cancellationToken = default)
+ {
+ var aggregateToDic = AggregateToDic(entities);
+ foreach (var aggregateKv in aggregateToDic)
+ {
+ await aggregateKv.Key.Set().AddRangeAsync(aggregateKv.Value, cancellationToken);
+ }
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// 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.
+ ///
+ public override void AttachRange(IEnumerable entities)
+ {
+ var aggregateToDic = AggregateToDic(entities);
+ foreach (var aggregateKv in aggregateToDic)
+ {
+ aggregateKv.Key.Set().AttachRange(aggregateKv.Value);
+ }
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// 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.
+ ///
+ public override void RemoveRange(IEnumerable entities)
+ {
+ Check.NotNull(entities, nameof(entities));
+
+
+ var aggregateToDic = AggregateToDic(entities);
+ foreach (var aggregateKv in aggregateToDic)
+ {
+ aggregateKv.Key.Set().RemoveRange(aggregateKv.Value);
+ }
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// 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.
+ ///
+ public override void UpdateRange(IEnumerable entities)
+ {
+ var aggregateToDic = AggregateToDic(entities);
+ foreach (var aggregateKv in aggregateToDic)
+ {
+ aggregateKv.Key.Set().UpdateRange(aggregateKv.Value);
+ }
+ }
+
+ private Dictionary> AggregateToDic(IEnumerable entities)
+ {
+ return entities.Select(o =>
+ {
+ var dbContext = _context.CreateGenericDbContext(o);
+ return new
+ {
+ DbContext = dbContext,
+ Entity = o
+ };
+ }).GroupBy(g => g.DbContext).ToDictionary(o => o.Key, o => o.Select(g => g.Entity));
+ }
+
+ public override TEntity Find(params object[] keyValues)
+ {
+ var primaryKeyFindDbContext = GetDbContextByKeyValue(keyValues);
+ if (primaryKeyFindDbContext != null)
+ {
+ return primaryKeyFindDbContext.Set().Find(keyValues);
+ }
+
+ return base.Find(keyValues);
+ }
+
+ public override Task FindAsync(params object[] keyValues)
+ {
+ var primaryKeyFindDbContext = GetDbContextByKeyValue(keyValues);
+ if (primaryKeyFindDbContext != null)
+ {
+ return primaryKeyFindDbContext.Set().FindAsync(keyValues);
+ }
+ return base.FindAsync(keyValues);
+ }
+
+ public override Task FindAsync(object[] keyValues, CancellationToken cancellationToken)
+ {
+ var primaryKeyFindDbContext = GetDbContextByKeyValue(keyValues);
+ if (primaryKeyFindDbContext != null)
+ {
+ return primaryKeyFindDbContext.Set().FindAsync(keyValues, cancellationToken);
+ }
+ return base.FindAsync(keyValues, cancellationToken);
+ }
+
+ private DbContext GetDbContextByKeyValue(params object[] keyValues)
+ {
+ var entityMetadata = EntityMetadataManager.TryGet(typeof(TEntity));
+ if (entityMetadata == null)
+ {
+ throw new ShardingCoreInvalidOperationException(
+ $"cant found type:[{typeof(TEntity)}] in {nameof(IEntityMetadataManager)}");
+ }
+
+ //既不是分表也不是分库的话就是默认对象
+ if (!entityMetadata.IsShardingTable() && !entityMetadata.IsShardingDataSource())
+ {
+ var defaultDataSourceName = _shardingRuntimeContext.GetVirtualDataSource().DefaultDataSourceName;
+ var routeTailFactory = _shardingRuntimeContext.GetRouteTailFactory();
+ var routeTail = routeTailFactory.Create(string.Empty);
+ return _context.GetShareDbContext(defaultDataSourceName, routeTail);
+ }
+
+ if (keyValues.Length == 1)
+ {
+ //单key字段
+ if (entityMetadata.IsSingleKey)
+ {
+ var isShardingDataSource = entityMetadata.IsShardingDataSource();
+ var shardingDataSourceFieldIsKey = entityMetadata.ShardingDataSourceFieldIsKey();
+ if (isShardingDataSource && !shardingDataSourceFieldIsKey)
+ return null;
+ var isShardingTable = entityMetadata.IsShardingTable();
+ var shardingTableFieldIsKey = entityMetadata.ShardingTableFieldIsKey();
+ if (isShardingTable && !shardingTableFieldIsKey)
+ return null;
+ var primaryKeyValue = keyValues[0];
+ if (primaryKeyValue != null)
+ {
+ var dataSourceName = GetDataSourceName(primaryKeyValue);
+ var realEntityType = TrackerManager.TranslateEntityType(typeof(TEntity));
+ var tableTail = TableRouteManager.GetTableTail(dataSourceName, primaryKeyValue,realEntityType);
+ var routeTail = _shardingRuntimeContext.GetRouteTailFactory().Create(tableTail);
+ return _context.GetShareDbContext(dataSourceName, routeTail);
+ }
+ }
+ }
+
+ return null;
+ }
+
+ private string GetDataSourceName(object shardingKeyValue)
+ {
+ return DataSourceRouteManager.GetDataSourceName(shardingKeyValue);
+ }
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/ShardingCore/EFCores/EFCore2x/ShardingMigrator.cs b/src/ShardingCore/EFCores/EFCore2x/ShardingMigrator.cs
new file mode 100644
index 00000000..e460538a
--- /dev/null
+++ b/src/ShardingCore/EFCores/EFCore2x/ShardingMigrator.cs
@@ -0,0 +1,48 @@
+
+#if NETCOREAPP2_0&&SHARDINGCORE2_6
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Diagnostics;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Migrations.Internal;
+using Microsoft.EntityFrameworkCore.Storage;
+using ShardingCore.Core.RuntimeContexts;
+using ShardingCore.Extensions;
+using ShardingCore.Helpers;
+
+namespace ShardingCore.EFCores
+{
+
+ public class ShardingMigrator:Migrator
+ {
+ private readonly IShardingRuntimeContext _shardingRuntimeContext;
+
+
+ public ShardingMigrator(IShardingRuntimeContext shardingRuntimeContext, IMigrationsAssembly migrationsAssembly, IHistoryRepository historyRepository, IDatabaseCreator databaseCreator, IMigrationsSqlGenerator migrationsSqlGenerator, IRawSqlCommandBuilder rawSqlCommandBuilder, IMigrationCommandExecutor migrationCommandExecutor, IRelationalConnection connection, ISqlGenerationHelper sqlGenerationHelper, IDiagnosticsLogger logger, IDatabaseProvider databaseProvider) : base(migrationsAssembly, historyRepository, databaseCreator, migrationsSqlGenerator, rawSqlCommandBuilder, migrationCommandExecutor, connection, sqlGenerationHelper, logger, databaseProvider)
+ {
+ _shardingRuntimeContext = shardingRuntimeContext;
+ }
+ public override void Migrate(string targetMigration = null)
+ {
+ this.MigrateAsync(targetMigration).WaitAndUnwrapException(false);
+ // base.Migrate(targetMigration);
+ }
+
+ public override async Task MigrateAsync(string targetMigration = null, CancellationToken cancellationToken = new CancellationToken())
+ {
+ var virtualDataSource = _shardingRuntimeContext.GetVirtualDataSource();
+ var allDataSourceNames = virtualDataSource.GetAllDataSourceNames();
+ await DynamicShardingHelper.DynamicMigrateWithDataSourcesAsync(_shardingRuntimeContext, allDataSourceNames, null,targetMigration,cancellationToken).ConfigureAwait(false);
+
+ }
+ public override string GenerateScript(string fromMigration = null, string toMigration = null, bool idempotent = false)
+ {
+ return new ScriptMigrationGenerator(_shardingRuntimeContext, fromMigration, toMigration, idempotent).GenerateScript();
+ }
+
+ }
+}
+
+#endif
diff --git a/src/ShardingCore/EFCores/EFCore2x/ShardingModelSource.cs b/src/ShardingCore/EFCores/EFCore2x/ShardingModelSource.cs
index 582b6b06..d9fdecba 100644
--- a/src/ShardingCore/EFCores/EFCore2x/ShardingModelSource.cs
+++ b/src/ShardingCore/EFCores/EFCore2x/ShardingModelSource.cs
@@ -1,4 +1,4 @@
-#if NETCOREAPP2_0
+#if NETCOREAPP2_0&&SHARDINGCORE2_6
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
diff --git a/src/ShardingCore/EFCores/EFCore2x/ShardingOptionsExtension.cs b/src/ShardingCore/EFCores/EFCore2x/ShardingOptionsExtension.cs
new file mode 100644
index 00000000..6aca963b
--- /dev/null
+++ b/src/ShardingCore/EFCores/EFCore2x/ShardingOptionsExtension.cs
@@ -0,0 +1,41 @@
+
+#if NETCOREAPP2_0 && SHARDINGCORE2_6
+using System;
+using System.Collections.Generic;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.Extensions.DependencyInjection;
+using ShardingCore.Core;
+using ShardingCore.Core.RuntimeContexts;
+
+namespace ShardingCore.EFCores
+{
+ /*
+ * @Author: xjm
+ * @Description:
+ * @Date: 2021/10/17 20:27:12
+ * @Ver: 1.0
+ * @Email: 326308290@qq.com
+ */
+ public class ShardingOptionsExtension: IDbContextOptionsExtension
+ {
+ public IShardingRuntimeContext ShardingRuntimeContext { get; }
+
+ public ShardingOptionsExtension(IShardingRuntimeContext shardingRuntimeContext)
+ {
+ ShardingRuntimeContext = shardingRuntimeContext;
+ }
+ public bool ApplyServices(IServiceCollection services)
+ {
+ services.AddSingleton(sp => ShardingRuntimeContext);
+ return true;
+ }
+ public long GetServiceProviderHashCode() => ShardingRuntimeContext.GetHashCode();
+
+ public void Validate(IDbContextOptions options)
+ {
+ }
+
+ public string LogFragment => "ShardingOptionsExtension";
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/ShardingCore/EFCores/EFCore2x/ShardingWrapOptionsExtension.cs b/src/ShardingCore/EFCores/EFCore2x/ShardingWrapOptionsExtension.cs
new file mode 100644
index 00000000..19e0d9a8
--- /dev/null
+++ b/src/ShardingCore/EFCores/EFCore2x/ShardingWrapOptionsExtension.cs
@@ -0,0 +1,37 @@
+#if NETCOREAPP2_0 && SHARDINGCORE2_6
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.Extensions.DependencyInjection;
+using ShardingCore.Core;
+
+namespace ShardingCore.EFCores
+{
+ /*
+ * @Author: xjm
+ * @Description:
+ * @Date: 2021/10/17 20:27:12
+ * @Ver: 1.0
+ * @Email: 326308290@qq.com
+ */
+
+
+
+ public class ShardingWrapOptionsExtension: IDbContextOptionsExtension
+ {
+ public bool ApplyServices(IServiceCollection services)
+ {
+ return false;
+ }
+
+ public long GetServiceProviderHashCode() => 0;
+
+ public void Validate(IDbContextOptions options)
+ {
+ }
+
+ public string LogFragment => "ShardingWrapOptionsExtension";
+ }
+}
+#endif
diff --git a/src/ShardingCore/EFCores/EFCore2x/Tx/ShardingRelationalTransaction.cs b/src/ShardingCore/EFCores/EFCore2x/Tx/ShardingRelationalTransaction.cs
new file mode 100644
index 00000000..9ce5bbc6
--- /dev/null
+++ b/src/ShardingCore/EFCores/EFCore2x/Tx/ShardingRelationalTransaction.cs
@@ -0,0 +1,62 @@
+#if NETCOREAPP2_0&&SHARDINGCORE2_6
+using System;
+using System.Collections.Generic;
+using System.Data.Common;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Diagnostics;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Storage;
+using ShardingCore.Exceptions;
+using ShardingCore.Sharding.Abstractions;
+
+namespace ShardingCore.EFCores
+{
+ /*
+ * @Author: xjm
+ * @Description:
+ * @Date: 2021/9/5 20:37:36
+ * @Ver: 1.0
+ * @Email: 326308290@qq.com
+ */
+ public class ShardingRelationalTransaction : RelationalTransaction
+ {
+ private readonly IShardingDbContext _shardingDbContext;
+ private readonly IShardingDbContextExecutor _shardingDbContextExecutor;
+ public ShardingRelationalTransaction(IShardingDbContext shardingDbContext, IRelationalConnection connection, DbTransaction transaction,IDiagnosticsLogger logger, bool transactionOwned) : base(connection, transaction, logger, transactionOwned)
+ {
+ _shardingDbContext =
+ shardingDbContext??throw new ShardingCoreInvalidOperationException($"should implement {nameof(IShardingDbContext)}");
+ _shardingDbContextExecutor = shardingDbContext.GetShardingExecutor() ??
+ throw new ShardingCoreInvalidOperationException(
+ $"{shardingDbContext.GetType()} cant get {nameof(IShardingDbContextExecutor)} from {nameof(shardingDbContext.GetShardingExecutor)}");
+
+ }
+
+ //protected override void ClearTransaction()
+ //{
+ // if (_canClear)
+ // {
+ // base.ClearTransaction();
+ // _supportShardingTransaction.NotifyShardingTransaction(null);
+ // }
+ //}f
+ public override void Commit()
+ {
+ base.Commit();
+ _shardingDbContextExecutor.Commit();
+ _shardingDbContextExecutor.NotifyShardingTransaction();
+ }
+
+ public override void Rollback()
+ {
+ base.Rollback();
+ _shardingDbContextExecutor.Rollback();
+ _shardingDbContextExecutor.NotifyShardingTransaction();
+ }
+
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/ShardingCore/EFCores/EFCore2x/Tx/ShardingRelationalTransactionFactory.cs b/src/ShardingCore/EFCores/EFCore2x/Tx/ShardingRelationalTransactionFactory.cs
new file mode 100644
index 00000000..fdadf322
--- /dev/null
+++ b/src/ShardingCore/EFCores/EFCore2x/Tx/ShardingRelationalTransactionFactory.cs
@@ -0,0 +1,49 @@
+#if NETCOREAPP2_0 && SHARDINGCORE2_6
+using System;
+using System.Collections.Generic;
+using System.Data.Common;
+using System.Text;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Diagnostics;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Storage;
+using ShardingCore.Extensions;
+using ShardingCore.Sharding.Abstractions;
+
+namespace ShardingCore.EFCores
+{
+ /*
+ * @Author: xjm
+ * @Description:
+ * @Date: 2021/9/5 16:03:04
+ * @Ver: 1.0
+ * @Email: 326308290@qq.com
+ */
+
+
+ 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)
+ {
+ var shardingDbContext = GetDbContext(connection) as IShardingDbContext;
+ return new ShardingRelationalTransaction(shardingDbContext, connection, transaction, logger,
+ transactionOwned);
+ }
+
+ private DbContext GetDbContext(IRelationalConnection connection)
+ {
+ var namedConnectionStringResolver = ((RelationalConnectionDependencies)connection.GetPropertyValue("Dependencies")).ConnectionStringResolver;
+ var serviceProvider = (IServiceProvider)namedConnectionStringResolver.GetPropertyValue("ApplicationServiceProvider");
+ var dbContext = (DbContext)serviceProvider.GetService(typeof(TShardingDbContext));
+ return dbContext;
+ }
+ }
+}
+#endif
diff --git a/src/ShardingCore/EFCores/EFCore2x/Tx/ShardingRelationalTransactionManager.cs b/src/ShardingCore/EFCores/EFCore2x/Tx/ShardingRelationalTransactionManager.cs
new file mode 100644
index 00000000..9031ef81
--- /dev/null
+++ b/src/ShardingCore/EFCores/EFCore2x/Tx/ShardingRelationalTransactionManager.cs
@@ -0,0 +1,101 @@
+#if NETCOREAPP2_0 && SHARDINGCORE2_6
+using System;
+using System.Collections.Generic;
+using System.Data;
+using System.Data.Common;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Storage;
+using ShardingCore.Exceptions;
+using ShardingCore.Extensions;
+using ShardingCore.Sharding.Abstractions;
+
+namespace ShardingCore.EFCores
+{
+ /*
+ * @Author: xjm
+ * @Description:
+ * @Date: 2021/10/20 10:08:42
+ * @Ver: 1.0
+ * @Email: 326308290@qq.com
+ */
+ ///
+ /// manage transaction
+ ///
+ public class ShardingRelationalTransactionManager : IRelationalTransactionManager where TShardingDbContext : DbContext, IShardingDbContext
+ {
+ private readonly IRelationalConnection _relationalConnection;
+ private readonly IShardingDbContext _shardingDbContext;
+ private readonly IShardingDbContextExecutor _shardingDbContextExecutor;
+
+
+
+ public ShardingRelationalTransactionManager(IRelationalConnection relationalConnection)
+ {
+ _relationalConnection = relationalConnection;
+ _shardingDbContext = GetDbContext(relationalConnection) as IShardingDbContext??throw new ShardingCoreInvalidOperationException($"should implement {nameof(IShardingDbContext)}");
+ _shardingDbContextExecutor = _shardingDbContext.GetShardingExecutor();
+ }
+ private DbContext GetDbContext(IRelationalConnection connection)
+ {
+ var namedConnectionStringResolver = ((RelationalConnectionDependencies)connection.GetPropertyValue("Dependencies")).ConnectionStringResolver;
+ var serviceProvider = (IServiceProvider)namedConnectionStringResolver.GetPropertyValue("ApplicationServiceProvider");
+ var dbContext = (DbContext)serviceProvider.GetService(typeof(TShardingDbContext));
+ return dbContext;
+ }
+
+ public void ResetState()
+ {
+ _relationalConnection.ResetState();
+ }
+
+ public IDbContextTransaction BeginTransaction()
+ {
+ return BeginTransaction(IsolationLevel.Unspecified);
+ }
+
+ public Task BeginTransactionAsync(CancellationToken cancellationToken = new CancellationToken())
+ {
+ return BeginTransactionAsync(IsolationLevel.Unspecified, cancellationToken);
+ }
+
+ public void CommitTransaction()
+ {
+ _relationalConnection.CommitTransaction();
+ }
+
+
+ public void RollbackTransaction()
+ {
+ _relationalConnection.RollbackTransaction();
+ }
+
+
+ public IDbContextTransaction CurrentTransaction => _relationalConnection.CurrentTransaction;
+ public IDbContextTransaction BeginTransaction(IsolationLevel isolationLevel)
+ {
+ var dbContextTransaction = _relationalConnection.BeginTransaction(isolationLevel);
+ _shardingDbContextExecutor.NotifyShardingTransaction();
+ return dbContextTransaction;
+ }
+
+ public async Task BeginTransactionAsync(IsolationLevel isolationLevel,
+ CancellationToken cancellationToken = new CancellationToken())
+ {
+ var dbContextTransaction = await _relationalConnection.BeginTransactionAsync(isolationLevel, cancellationToken);
+ _shardingDbContextExecutor.NotifyShardingTransaction();
+ return dbContextTransaction;
+ }
+
+ public IDbContextTransaction UseTransaction(DbTransaction transaction)
+ {
+ var dbContextTransaction = _relationalConnection.UseTransaction(transaction);
+ _shardingDbContextExecutor.NotifyShardingTransaction();
+ return dbContextTransaction;
+ }
+ }
+}
+
+#endif
\ No newline at end of file
diff --git a/src/ShardingCore/EFCores/EFCore2x/UnionAllMergeOptionsExtension.cs b/src/ShardingCore/EFCores/EFCore2x/UnionAllMergeOptionsExtension.cs
new file mode 100644
index 00000000..ba870e3f
--- /dev/null
+++ b/src/ShardingCore/EFCores/EFCore2x/UnionAllMergeOptionsExtension.cs
@@ -0,0 +1,33 @@
+#if NETCOREAPP2_0 && SHARDINGCORE2_6
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.Extensions.DependencyInjection;
+
+namespace ShardingCore.EFCores
+{
+ /*
+ * @Author: xjm
+ * @Description:
+ * @Date: 2021/10/17 20:27:12
+ * @Ver: 1.0
+ * @Email: 326308290@qq.com
+ */
+ public class UnionAllMergeOptionsExtension: IDbContextOptionsExtension
+ {
+ public bool ApplyServices(IServiceCollection services)
+ {
+ return false;
+ }
+
+ public long GetServiceProviderHashCode() => 0;
+
+ public void Validate(IDbContextOptions options)
+ {
+ }
+
+ public string LogFragment => "UnionAllMergeOptionsExtension";
+ }
+}
+#endif
diff --git a/src/ShardingCore/EFCores/EFCore3x/ScriptMigrationGenerator.cs b/src/ShardingCore/EFCores/EFCore3x/ScriptMigrationGenerator.cs
index 72d85261..8704b5f7 100644
--- a/src/ShardingCore/EFCores/EFCore3x/ScriptMigrationGenerator.cs
+++ b/src/ShardingCore/EFCores/EFCore3x/ScriptMigrationGenerator.cs
@@ -1,4 +1,4 @@
-#if NETCOREAPP3_0 || NETSTANDARD2_0 || NETSTANDARD2_0
+#if (NETCOREAPP3_0 || NETSTANDARD2_0 )&&SHARDINGCORE2_6
using Microsoft.EntityFrameworkCore.Migrations;
using ShardingCore.Core.RuntimeContexts;
diff --git a/src/ShardingCore/EFCores/EFCore3x/ShardingChangeTracker.cs b/src/ShardingCore/EFCores/EFCore3x/ShardingChangeTracker.cs
new file mode 100644
index 00000000..1d565221
--- /dev/null
+++ b/src/ShardingCore/EFCores/EFCore3x/ShardingChangeTracker.cs
@@ -0,0 +1,123 @@
+#if (NETCOREAPP3_0 || NETSTANDARD2_0 )&&SHARDINGCORE2_6
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.ChangeTracking;
+using Microsoft.EntityFrameworkCore.ChangeTracking.Internal;
+using Microsoft.EntityFrameworkCore.Metadata;
+using ShardingCore.Sharding.Abstractions;
+
+namespace ShardingCore.EFCores
+{
+ public class ShardingChangeTracker : ChangeTracker
+ {
+ private readonly DbContext _dbContext;
+
+ public ShardingChangeTracker(DbContext context, IStateManager stateManager, IChangeDetector changeDetector,
+ IModel model, IEntityEntryGraphIterator graphIterator) : base(context, stateManager, changeDetector, model,
+ graphIterator)
+ {
+ _dbContext = context;
+ }
+
+
+ public override bool HasChanges()
+ {
+ if (_dbContext is IShardingDbContext shardingDbContext)
+ {
+ return shardingDbContext.GetShardingExecutor().GetCurrentDbContexts().Any(o =>
+ o.Value.GetCurrentContexts().Any(r => r.Value.ChangeTracker.HasChanges()));
+ }
+
+ return base.HasChanges();
+ }
+
+ public override IEnumerable Entries()
+ {
+ if (_dbContext is IShardingDbContext shardingDbContext)
+ {
+ return shardingDbContext.GetShardingExecutor().GetCurrentDbContexts().SelectMany(o =>
+ o.Value.GetCurrentContexts().SelectMany(cd => cd.Value.ChangeTracker.Entries()));
+ }
+
+ return base.Entries();
+ }
+
+ public override IEnumerable> Entries()
+ {
+ if (_dbContext is IShardingDbContext shardingDbContext)
+ {
+ return shardingDbContext.GetShardingExecutor().GetCurrentDbContexts().SelectMany(o =>
+ o.Value.GetCurrentContexts().SelectMany(cd => cd.Value.ChangeTracker.Entries()));
+ }
+
+ return base.Entries();
+ }
+
+ public override void DetectChanges()
+ {
+ if (_dbContext is IShardingDbContext)
+ {
+ Do(c => c.DetectChanges());
+ return;
+ }
+ base.DetectChanges();
+ }
+
+ public override void AcceptAllChanges()
+ {
+ if (_dbContext is IShardingDbContext)
+ {
+ Do(c => c.AcceptAllChanges());
+ return;
+ }
+ base.AcceptAllChanges();
+ }
+
+ private void Do(Action action)
+ {
+ var dataSourceDbContexts = ((IShardingDbContext)_dbContext).GetShardingExecutor().GetCurrentDbContexts();
+ foreach (var dataSourceDbContext in dataSourceDbContexts)
+ {
+ var currentContexts = dataSourceDbContext.Value.GetCurrentContexts();
+ foreach (var keyValuePair in currentContexts)
+ {
+ action(keyValuePair.Value.ChangeTracker);
+ }
+ }
+ }
+
+ public override void TrackGraph(object rootEntity, Action callback)
+ {
+ if (_dbContext is IShardingDbContext shardingDbContext)
+ {
+ var genericDbContext = shardingDbContext.CreateGenericDbContext(rootEntity);
+ genericDbContext.ChangeTracker.TrackGraph(rootEntity,callback);
+ // Do(c => c.TrackGraph(rootEntity,callback));
+ }
+ }
+
+ public override void TrackGraph(object rootEntity, TState state, Func, bool> callback) where TState : default
+ {
+ if (_dbContext is IShardingDbContext shardingDbContext)
+ {
+ var genericDbContext = shardingDbContext.CreateGenericDbContext(rootEntity);
+ genericDbContext.ChangeTracker.TrackGraph(rootEntity,state,callback);
+ // Do(c => c.TrackGraph(rootEntity,callback));
+ }
+ }
+
+ public override void CascadeChanges()
+ {
+ if (_dbContext is IShardingDbContext)
+ {
+ Do(c => c.CascadeChanges());
+ return;
+ }
+ base.CascadeChanges();
+ }
+
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/ShardingCore/EFCores/EFCore3x/ShardingDbSetSource.cs b/src/ShardingCore/EFCores/EFCore3x/ShardingDbSetSource.cs
new file mode 100644
index 00000000..2a289b61
--- /dev/null
+++ b/src/ShardingCore/EFCores/EFCore3x/ShardingDbSetSource.cs
@@ -0,0 +1,48 @@
+#if (NETCOREAPP3_0 || NETSTANDARD2_0) && SHARDINGCORE2_6
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Internal;
+using System;
+using System.Collections.Concurrent;
+using System.Reflection;
+
+namespace ShardingCore.EFCores
+{
+ /*
+ * @Author: xjm
+ * @Description:
+ * @Date: Saturday, 14 August 2021 10:17:43
+ * @Email: 326308290@qq.com
+ */
+
+ public class ShardingDbSetSource:IDbSetSource
+ {
+
+ private static readonly MethodInfo _genericCreateSet
+ = typeof(ShardingDbSetSource).GetTypeInfo().GetDeclaredMethod(nameof(CreateSetFactory));
+
+ private readonly ConcurrentDictionary> _cache
+ = new ConcurrentDictionary>();
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// 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.
+ ///
+ public virtual object Create(DbContext context, Type type)
+ => CreateCore(context, type, _genericCreateSet);
+
+ 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);
+ }
+
+}
+#endif
\ No newline at end of file
diff --git a/src/ShardingCore/EFCores/EFCore3x/ShardingInternalDbSet.cs b/src/ShardingCore/EFCores/EFCore3x/ShardingInternalDbSet.cs
new file mode 100644
index 00000000..c9489220
--- /dev/null
+++ b/src/ShardingCore/EFCores/EFCore3x/ShardingInternalDbSet.cs
@@ -0,0 +1,436 @@
+#if (NETCOREAPP3_0 || NETSTANDARD2_0) && SHARDINGCORE2_6
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.ChangeTracking;
+using Microsoft.EntityFrameworkCore.Internal;
+using ShardingCore.Core;
+using ShardingCore.Sharding.Abstractions;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using ShardingCore.Core.EntityMetadatas;
+using ShardingCore.Core.RuntimeContexts;
+using ShardingCore.Core.TrackerManagers;
+using ShardingCore.Core.VirtualDatabase.VirtualDataSources;
+using ShardingCore.Core.VirtualRoutes.Abstractions;
+using ShardingCore.Exceptions;
+using ShardingCore.Extensions;
+using ShardingCore.Utils;
+
+namespace ShardingCore.EFCores
+{
+ /*
+ * @Author: xjm
+ * @Description:
+ * @Date: 2021/8/15 8:39:15
+ * @Ver: 1.0
+ * @Email: 326308290@qq.com
+ */
+
+ public class ShardingInternalDbSet : InternalDbSet
+ where TEntity : class
+ {
+ private readonly IShardingDbContext _context;
+ private readonly IShardingRuntimeContext _shardingRuntimeContext;
+ private LocalView? _localView;
+
+
+ public ShardingInternalDbSet(DbContext context) : base(context)
+ {
+ _context = (IShardingDbContext)context;
+ _shardingRuntimeContext = context.GetShardingRuntimeContext();
+ }
+
+ private IDataSourceRouteManager _dataSourceRouteManager;
+
+ protected IDataSourceRouteManager DataSourceRouteManager
+ {
+ get
+ {
+ if (null == _dataSourceRouteManager)
+ {
+ _dataSourceRouteManager = _shardingRuntimeContext.GetDataSourceRouteManager();
+ }
+
+ return _dataSourceRouteManager;
+ }
+ }
+
+ public override LocalView Local
+ {
+ get
+ {
+
+ if (((DbContext)_context).ChangeTracker.AutoDetectChangesEnabled)
+ {
+ ((DbContext)_context).ChangeTracker.DetectChanges();
+ }
+
+ return _localView ??= new ShardingLocalView(this);
+ }
+ }
+ private ITableRouteManager _tableRouteManager;
+
+ protected ITableRouteManager TableRouteManager
+ {
+ get
+ {
+ if (null == _tableRouteManager)
+ {
+ _tableRouteManager = _shardingRuntimeContext.GetTableRouteManager();
+ }
+
+ return _tableRouteManager;
+ }
+ }
+
+ private IEntityMetadataManager _entityMetadataManager;
+
+ protected IEntityMetadataManager EntityMetadataManager
+ {
+ get
+ {
+ if (null == _entityMetadataManager)
+ {
+ _entityMetadataManager = _shardingRuntimeContext.GetEntityMetadataManager();
+ }
+
+ return _entityMetadataManager;
+ }
+ }
+
+ private ITrackerManager _trackerManager;
+
+ protected ITrackerManager TrackerManager
+ {
+ get
+ {
+ if (null == _trackerManager)
+ {
+ _trackerManager = _shardingRuntimeContext.GetTrackerManager();
+ }
+
+ return _trackerManager;
+ }
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// 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.
+ ///
+ public override EntityEntry Add(TEntity entity)
+ {
+ var genericDbContext = _context.CreateGenericDbContext(entity);
+ return genericDbContext.Set().Add(entity);
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// 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.
+ ///
+ public override async ValueTask> AddAsync(
+ TEntity entity,
+ CancellationToken cancellationToken = default)
+ {
+ var genericDbContext = _context.CreateGenericDbContext(entity);
+ return await genericDbContext.Set().AddAsync(entity, cancellationToken);
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// 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.
+ ///
+ public override EntityEntry Attach(TEntity entity)
+ {
+ var genericDbContext = _context.CreateGenericDbContext(entity);
+ return genericDbContext.Set().Attach(entity);
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// 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.
+ ///
+ public override EntityEntry Remove(TEntity entity)
+ {
+ Check.NotNull(entity, nameof(entity));
+
+ var genericDbContext = _context.CreateGenericDbContext(entity);
+ return genericDbContext.Set().Remove(entity);
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// 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.
+ ///
+ public override EntityEntry Update(TEntity entity)
+ {
+ var genericDbContext = _context.CreateGenericDbContext(entity);
+ return genericDbContext.Set().Update(entity);
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// 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.
+ ///
+ public override void AddRange(params TEntity[] entities)
+ {
+ var aggregateToDic = AggregateToDic(entities);
+ foreach (var aggregateKv in aggregateToDic)
+ {
+ aggregateKv.Key.Set().AddRange(aggregateKv.Value);
+ }
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// 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.
+ ///
+ public override async Task AddRangeAsync(params TEntity[] entities)
+ {
+ var aggregateToDic = AggregateToDic(entities);
+ foreach (var aggregateKv in aggregateToDic)
+ {
+ await aggregateKv.Key.Set().AddRangeAsync(aggregateKv.Value);
+ }
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// 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.
+ ///
+ public override void AttachRange(params TEntity[] entities)
+ {
+ var aggregateToDic = AggregateToDic(entities);
+ foreach (var aggregateKv in aggregateToDic)
+ {
+ aggregateKv.Key.Set().AttachRange(aggregateKv.Value);
+ }
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// 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.
+ ///
+ public override void RemoveRange(params TEntity[] entities)
+ {
+ Check.NotNull(entities, nameof(entities));
+ var aggregateToDic = AggregateToDic(entities);
+ foreach (var aggregateKv in aggregateToDic)
+ {
+ aggregateKv.Key.Set().RemoveRange(aggregateKv.Value);
+ }
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// 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.
+ ///
+ public override void UpdateRange(params TEntity[] entities)
+ {
+ var aggregateToDic = AggregateToDic(entities);
+ foreach (var aggregateKv in aggregateToDic)
+ {
+ aggregateKv.Key.Set().UpdateRange(aggregateKv.Value);
+ }
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// 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.
+ ///
+ public override void AddRange(IEnumerable entities)
+ {
+ var aggregateToDic = AggregateToDic(entities);
+ foreach (var aggregateKv in aggregateToDic)
+ {
+ aggregateKv.Key.Set().AddRange(aggregateKv.Value);
+ }
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// 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.
+ ///
+ public override async Task AddRangeAsync(
+ IEnumerable entities,
+ CancellationToken cancellationToken = default)
+ {
+ var aggregateToDic = AggregateToDic(entities);
+ foreach (var aggregateKv in aggregateToDic)
+ {
+ await aggregateKv.Key.Set().AddRangeAsync(aggregateKv.Value, cancellationToken);
+ }
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// 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.
+ ///
+ public override void AttachRange(IEnumerable entities)
+ {
+ var aggregateToDic = AggregateToDic(entities);
+ foreach (var aggregateKv in aggregateToDic)
+ {
+ aggregateKv.Key.Set().AttachRange(aggregateKv.Value);
+ }
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// 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.
+ ///
+ public override void RemoveRange(IEnumerable entities)
+ {
+ Check.NotNull(entities, nameof(entities));
+
+
+ var aggregateToDic = AggregateToDic(entities);
+ foreach (var aggregateKv in aggregateToDic)
+ {
+ aggregateKv.Key.Set().RemoveRange(aggregateKv.Value);
+ }
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// 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.
+ ///
+ public override void UpdateRange(IEnumerable entities)
+ {
+ var aggregateToDic = AggregateToDic(entities);
+ foreach (var aggregateKv in aggregateToDic)
+ {
+ aggregateKv.Key.Set().UpdateRange(aggregateKv.Value);
+ }
+ }
+
+ private Dictionary> AggregateToDic(IEnumerable entities)
+ {
+ return entities.Select(o =>
+ {
+ var dbContext = _context.CreateGenericDbContext(o);
+ return new
+ {
+ DbContext = dbContext,
+ Entity = o
+ };
+ }).GroupBy(g => g.DbContext).ToDictionary(o => o.Key, o => o.Select(g => g.Entity));
+ }
+
+ public override TEntity Find(params object[] keyValues)
+ {
+ var primaryKeyFindDbContext = GetDbContextByKeyValue(keyValues);
+ if (primaryKeyFindDbContext != null)
+ {
+ return primaryKeyFindDbContext.Set().Find(keyValues);
+ }
+
+ return base.Find(keyValues);
+ }
+
+ public override ValueTask FindAsync(params object[] keyValues)
+ {
+ var primaryKeyFindDbContext = GetDbContextByKeyValue(keyValues);
+ if (primaryKeyFindDbContext != null)
+ {
+ return primaryKeyFindDbContext.Set().FindAsync(keyValues);
+ }
+
+ return base.FindAsync(keyValues);
+ }
+
+ public override ValueTask FindAsync(object[] keyValues, CancellationToken cancellationToken)
+ {
+ var primaryKeyFindDbContext = GetDbContextByKeyValue(keyValues);
+ if (primaryKeyFindDbContext != null)
+ {
+ return primaryKeyFindDbContext.Set().FindAsync(keyValues, cancellationToken);
+ }
+
+ return base.FindAsync(keyValues, cancellationToken);
+ }
+
+ private DbContext GetDbContextByKeyValue(params object[] keyValues)
+ {
+ var entityMetadata = EntityMetadataManager.TryGet(typeof(TEntity));
+ if (entityMetadata == null)
+ {
+ throw new ShardingCoreInvalidOperationException(
+ $"cant found type:[{typeof(TEntity)}] in {nameof(IEntityMetadataManager)}");
+ }
+
+ //既不是分表也不是分库的话就是默认对象
+ if (!entityMetadata.IsShardingTable() && !entityMetadata.IsShardingDataSource())
+ {
+ var defaultDataSourceName = _shardingRuntimeContext.GetVirtualDataSource().DefaultDataSourceName;
+ var routeTailFactory = _shardingRuntimeContext.GetRouteTailFactory();
+ var routeTail = routeTailFactory.Create(string.Empty);
+ return _context.GetShareDbContext(defaultDataSourceName, routeTail);
+ }
+
+ if (keyValues.Length == 1)
+ {
+ //单key字段
+ if (entityMetadata.IsSingleKey)
+ {
+ var isShardingDataSource = entityMetadata.IsShardingDataSource();
+ var shardingDataSourceFieldIsKey = entityMetadata.ShardingDataSourceFieldIsKey();
+ if (isShardingDataSource && !shardingDataSourceFieldIsKey)
+ return null;
+ var isShardingTable = entityMetadata.IsShardingTable();
+ var shardingTableFieldIsKey = entityMetadata.ShardingTableFieldIsKey();
+ if (isShardingTable && !shardingTableFieldIsKey)
+ return null;
+ var primaryKeyValue = keyValues[0];
+ if (primaryKeyValue != null)
+ {
+ var dataSourceName = GetDataSourceName(primaryKeyValue);
+ var realEntityType = TrackerManager.TranslateEntityType(typeof(TEntity));
+ var tableTail = TableRouteManager.GetTableTail(dataSourceName, primaryKeyValue,realEntityType);
+ var routeTail = _shardingRuntimeContext.GetRouteTailFactory().Create(tableTail);
+ return _context.GetShareDbContext(dataSourceName, routeTail);
+ }
+ }
+ }
+
+ return null;
+ }
+
+ private string GetDataSourceName(object shardingKeyValue)
+ {
+ return DataSourceRouteManager.GetDataSourceName(shardingKeyValue);
+ }
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/ShardingCore/EFCores/EFCore3x/ShardingMigrator.cs b/src/ShardingCore/EFCores/EFCore3x/ShardingMigrator.cs
new file mode 100644
index 00000000..f43a14c4
--- /dev/null
+++ b/src/ShardingCore/EFCores/EFCore3x/ShardingMigrator.cs
@@ -0,0 +1,47 @@
+
+#if (NETCOREAPP3_0 || NETSTANDARD2_0)&&SHARDINGCORE2_6
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Diagnostics;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Migrations.Internal;
+using Microsoft.EntityFrameworkCore.Storage;
+using ShardingCore.Core.RuntimeContexts;
+using ShardingCore.Extensions;
+using ShardingCore.Helpers;
+
+
+namespace ShardingCore.EFCores
+{
+ public class ShardingMigrator:Migrator
+ {
+ private readonly IShardingRuntimeContext _shardingRuntimeContext;
+
+
+ public ShardingMigrator(IShardingRuntimeContext shardingRuntimeContext, IMigrationsAssembly migrationsAssembly, IHistoryRepository historyRepository, IDatabaseCreator databaseCreator, IMigrationsSqlGenerator migrationsSqlGenerator, IRawSqlCommandBuilder rawSqlCommandBuilder, IMigrationCommandExecutor migrationCommandExecutor, IRelationalConnection connection, ISqlGenerationHelper sqlGenerationHelper, ICurrentDbContext currentContext, IDiagnosticsLogger logger, IDiagnosticsLogger commandLogger, IDatabaseProvider databaseProvider) : base(migrationsAssembly, historyRepository, databaseCreator, migrationsSqlGenerator, rawSqlCommandBuilder, migrationCommandExecutor, connection, sqlGenerationHelper, currentContext, logger, commandLogger, databaseProvider)
+ {
+ _shardingRuntimeContext = shardingRuntimeContext;
+ }
+ public override void Migrate(string targetMigration = null)
+ {
+ this.MigrateAsync(targetMigration).WaitAndUnwrapException(false);
+ // base.Migrate(targetMigration);
+ }
+
+ public override async Task MigrateAsync(string targetMigration = null, CancellationToken cancellationToken = new CancellationToken())
+ {
+ var virtualDataSource = _shardingRuntimeContext.GetVirtualDataSource();
+ var allDataSourceNames = virtualDataSource.GetAllDataSourceNames();
+ await DynamicShardingHelper.DynamicMigrateWithDataSourcesAsync(_shardingRuntimeContext, allDataSourceNames, null,targetMigration,cancellationToken).ConfigureAwait(false);
+
+ }
+ public override string GenerateScript(string fromMigration = null, string toMigration = null, bool idempotent = false)
+ {
+ return new ScriptMigrationGenerator(_shardingRuntimeContext, fromMigration, toMigration, idempotent).GenerateScript();
+ }
+ }
+}
+
+#endif
\ No newline at end of file
diff --git a/src/ShardingCore/EFCores/EFCore3x/ShardingModelSource.cs b/src/ShardingCore/EFCores/EFCore3x/ShardingModelSource.cs
index 41c7af90..3a07a231 100644
--- a/src/ShardingCore/EFCores/EFCore3x/ShardingModelSource.cs
+++ b/src/ShardingCore/EFCores/EFCore3x/ShardingModelSource.cs
@@ -1,4 +1,4 @@
-#if NETCOREAPP3_0 || NETSTANDARD2_0
+#if (NETCOREAPP3_0 || NETSTANDARD2_0)&&SHARDINGCORE2_6
using System;
using System.Collections.Generic;
using System.Linq;
diff --git a/src/ShardingCore/EFCores/EFCore3x/ShardingOptionsExtension.cs b/src/ShardingCore/EFCores/EFCore3x/ShardingOptionsExtension.cs
new file mode 100644
index 00000000..5c3d0107
--- /dev/null
+++ b/src/ShardingCore/EFCores/EFCore3x/ShardingOptionsExtension.cs
@@ -0,0 +1,58 @@
+#if (NETCOREAPP3_0 || NETSTANDARD2_0)&&SHARDINGCORE2_6
+using System;
+using System.Collections.Generic;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.Extensions.DependencyInjection;
+using ShardingCore.Core;
+using ShardingCore.Core.RuntimeContexts;
+
+namespace ShardingCore.EFCores
+{
+ /*
+ * @Author: xjm
+ * @Description:
+ * @Date: 2021/10/17 20:27:12
+ * @Ver: 1.0
+ * @Email: 326308290@qq.com
+ */
+
+ public class ShardingOptionsExtension: IDbContextOptionsExtension
+ {
+ public IShardingRuntimeContext ShardingRuntimeContext { get; }
+
+ public ShardingOptionsExtension(IShardingRuntimeContext shardingRuntimeContext)
+ {
+ ShardingRuntimeContext = shardingRuntimeContext;
+ }
+ public void ApplyServices(IServiceCollection services)
+ {
+ services.AddSingleton(sp => ShardingRuntimeContext);
+ }
+
+ public void Validate(IDbContextOptions options)
+ {
+ }
+
+
+ public DbContextOptionsExtensionInfo Info => new ShardingOptionsExtensionInfo(this);
+
+ private class ShardingOptionsExtensionInfo : DbContextOptionsExtensionInfo
+ {
+ private readonly ShardingOptionsExtension _shardingOptionsExtension;
+ public ShardingOptionsExtensionInfo(IDbContextOptionsExtension extension) : base(extension)
+ {
+ _shardingOptionsExtension = (ShardingOptionsExtension)extension;
+ }
+
+
+ public override long GetServiceProviderHashCode() => _shardingOptionsExtension.ShardingRuntimeContext.GetHashCode();
+
+ public override void PopulateDebugInfo(IDictionary debugInfo) { }
+
+ public override bool IsDatabaseProvider => false;
+ public override string LogFragment => "ShardingOptionsExtension";
+ }
+ }
+}
+
+#endif
\ No newline at end of file
diff --git a/src/ShardingCore/EFCores/EFCore3x/ShardingWrapOptionsExtension.cs b/src/ShardingCore/EFCores/EFCore3x/ShardingWrapOptionsExtension.cs
new file mode 100644
index 00000000..afc92e05
--- /dev/null
+++ b/src/ShardingCore/EFCores/EFCore3x/ShardingWrapOptionsExtension.cs
@@ -0,0 +1,46 @@
+#if (NETCOREAPP3_0 || NETSTANDARD2_0) && SHARDINGCORE2_6
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.Extensions.DependencyInjection;
+using ShardingCore.Core;
+
+namespace ShardingCore.EFCores
+{
+ /*
+ * @Author: xjm
+ * @Description:
+ * @Date: 2021/10/17 20:27:12
+ * @Ver: 1.0
+ * @Email: 326308290@qq.com
+ */
+
+ public class ShardingWrapOptionsExtension: IDbContextOptionsExtension
+ {
+ public void ApplyServices(IServiceCollection services)
+ {
+ }
+
+ public void Validate(IDbContextOptions options)
+ {
+ }
+
+
+ public DbContextOptionsExtensionInfo Info => new ShardingWrapDbContextOptionsExtensionInfo(this);
+
+ private class ShardingWrapDbContextOptionsExtensionInfo : DbContextOptionsExtensionInfo
+ {
+ public ShardingWrapDbContextOptionsExtensionInfo(IDbContextOptionsExtension extension) : base(extension) { }
+
+ public override long GetServiceProviderHashCode() => 0;
+
+ public override void PopulateDebugInfo(IDictionary debugInfo) { }
+
+ public override bool IsDatabaseProvider => false;
+ public override string LogFragment => "ShardingWrapOptionsExtension";
+ }
+ }
+
+}
+#endif
diff --git a/src/ShardingCore/EFCores/EFCore3x/Tx/ShardingRelationalTransaction.cs b/src/ShardingCore/EFCores/EFCore3x/Tx/ShardingRelationalTransaction.cs
new file mode 100644
index 00000000..fd9af368
--- /dev/null
+++ b/src/ShardingCore/EFCores/EFCore3x/Tx/ShardingRelationalTransaction.cs
@@ -0,0 +1,74 @@
+#if (NETCOREAPP3_0 || NETSTANDARD2_0)&&SHARDINGCORE2_6
+using System;
+using System.Collections.Generic;
+using System.Data.Common;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Diagnostics;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Storage;
+using ShardingCore.Exceptions;
+using ShardingCore.Sharding.Abstractions;
+
+namespace ShardingCore.EFCores
+{
+ /*
+ * @Author: xjm
+ * @Description:
+ * @Date: 2021/9/5 20:37:36
+ * @Ver: 1.0
+ * @Email: 326308290@qq.com
+ */
+ public class ShardingRelationalTransaction : RelationalTransaction
+ {
+ private readonly IShardingDbContext _shardingDbContext;
+ private readonly IShardingDbContextExecutor _shardingDbContextExecutor;
+ public ShardingRelationalTransaction(IShardingDbContext shardingDbContext, IRelationalConnection connection,
+ DbTransaction transaction, Guid transactionId,
+ IDiagnosticsLogger logger, bool transactionOwned) : base(connection,
+ transaction, transactionId, logger, transactionOwned)
+ {
+ _shardingDbContext = shardingDbContext ??
+ throw new ShardingCoreInvalidOperationException(
+ $"should implement {nameof(IShardingDbContext)}");
+ _shardingDbContextExecutor = shardingDbContext.GetShardingExecutor() ??
+ throw new ShardingCoreInvalidOperationException(
+ $"{shardingDbContext.GetType()} cant get {nameof(IShardingDbContextExecutor)} from {nameof(shardingDbContext.GetShardingExecutor)}");
+ }
+
+ public override void Commit()
+ {
+ base.Commit();
+ _shardingDbContextExecutor.Commit();
+ _shardingDbContextExecutor.NotifyShardingTransaction();
+ }
+
+ public override void Rollback()
+ {
+ base.Rollback();
+ _shardingDbContextExecutor.Rollback();
+ _shardingDbContextExecutor.NotifyShardingTransaction();
+ }
+
+#if !NETCOREAPP2_0
+ public override async Task RollbackAsync(CancellationToken cancellationToken = new CancellationToken())
+ {
+ await base.RollbackAsync(cancellationToken);
+
+ await _shardingDbContextExecutor.RollbackAsync(cancellationToken);
+ _shardingDbContextExecutor.NotifyShardingTransaction();
+ }
+
+ public override async Task CommitAsync(CancellationToken cancellationToken = new CancellationToken())
+ {
+ await base.CommitAsync(cancellationToken);
+
+ await _shardingDbContextExecutor.CommitAsync(cancellationToken);
+ _shardingDbContextExecutor.NotifyShardingTransaction();
+ }
+#endif
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/ShardingCore/EFCores/EFCore3x/Tx/ShardingRelationalTransactionFactory.cs b/src/ShardingCore/EFCores/EFCore3x/Tx/ShardingRelationalTransactionFactory.cs
new file mode 100644
index 00000000..b4d6c20d
--- /dev/null
+++ b/src/ShardingCore/EFCores/EFCore3x/Tx/ShardingRelationalTransactionFactory.cs
@@ -0,0 +1,39 @@
+#if (NETCOREAPP3_0 || NETSTANDARD2_0) && SHARDINGCORE2_6
+using System;
+using System.Collections.Generic;
+using System.Data.Common;
+using System.Text;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Diagnostics;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Storage;
+using ShardingCore.Extensions;
+using ShardingCore.Sharding.Abstractions;
+
+namespace ShardingCore.EFCores
+{
+ /*
+ * @Author: xjm
+ * @Description:
+ * @Date: 2021/9/5 16:03:04
+ * @Ver: 1.0
+ * @Email: 326308290@qq.com
+ */
+
+ 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, Guid transactionId,
+ IDiagnosticsLogger logger, bool transactionOwned)
+ {
+ var shardingDbContext = connection.Context as IShardingDbContext;
+ return new ShardingRelationalTransaction(shardingDbContext, connection, transaction, transactionId, logger, transactionOwned);
+ }
+ }
+
+}
+#endif
diff --git a/src/ShardingCore/EFCores/EFCore3x/Tx/ShardingRelationalTransactionManager.cs b/src/ShardingCore/EFCores/EFCore3x/Tx/ShardingRelationalTransactionManager.cs
new file mode 100644
index 00000000..805df3b6
--- /dev/null
+++ b/src/ShardingCore/EFCores/EFCore3x/Tx/ShardingRelationalTransactionManager.cs
@@ -0,0 +1,103 @@
+#if (NETCOREAPP3_0 || NETSTANDARD2_0) && SHARDINGCORE2_6
+using System;
+using System.Collections.Generic;
+using System.Data;
+using System.Data.Common;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Storage;
+using ShardingCore.Exceptions;
+using ShardingCore.Extensions;
+using ShardingCore.Sharding.Abstractions;
+
+namespace ShardingCore.EFCores
+{
+ /*
+ * @Author: xjm
+ * @Description:
+ * @Date: 2021/10/20 10:08:42
+ * @Ver: 1.0
+ * @Email: 326308290@qq.com
+ */
+ ///
+ /// manage transaction
+ ///
+ public class ShardingRelationalTransactionManager : IRelationalTransactionManager where TShardingDbContext : DbContext, IShardingDbContext
+ {
+ private readonly IRelationalConnection _relationalConnection;
+ private readonly IShardingDbContext _shardingDbContext;
+ private readonly IShardingDbContextExecutor _shardingDbContextExecutor;
+
+ public ShardingRelationalTransactionManager(IRelationalConnection relationalConnection)
+ {
+ _relationalConnection = relationalConnection;
+ _shardingDbContext = relationalConnection.Context as IShardingDbContext??throw new ShardingCoreInvalidOperationException($"should implement {nameof(IShardingDbContext)}");
+ _shardingDbContextExecutor = _shardingDbContext.GetShardingExecutor();
+ }
+
+ public void ResetState()
+ {
+ _relationalConnection.ResetState();
+ }
+
+ public IDbContextTransaction BeginTransaction()
+ {
+ return BeginTransaction(IsolationLevel.Unspecified);
+ }
+
+ public Task BeginTransactionAsync(CancellationToken cancellationToken = new CancellationToken())
+ {
+ return BeginTransactionAsync(IsolationLevel.Unspecified, cancellationToken);
+ }
+
+ public void CommitTransaction()
+ {
+ _relationalConnection.CommitTransaction();
+ }
+
+
+ public void RollbackTransaction()
+ {
+ _relationalConnection.RollbackTransaction();
+ }
+
+
+ public IDbContextTransaction CurrentTransaction => _relationalConnection.CurrentTransaction;
+ public IDbContextTransaction BeginTransaction(IsolationLevel isolationLevel)
+ {
+ var dbContextTransaction = _relationalConnection.BeginTransaction(isolationLevel);
+ _shardingDbContextExecutor.NotifyShardingTransaction();
+ return dbContextTransaction;
+ }
+
+ public async Task BeginTransactionAsync(IsolationLevel isolationLevel,
+ CancellationToken cancellationToken = new CancellationToken())
+ {
+ var dbContextTransaction = await _relationalConnection.BeginTransactionAsync(isolationLevel, cancellationToken);
+ _shardingDbContextExecutor.NotifyShardingTransaction();
+ return dbContextTransaction;
+ }
+
+ public IDbContextTransaction UseTransaction(DbTransaction transaction)
+ {
+ var dbContextTransaction = _relationalConnection.UseTransaction(transaction);
+ _shardingDbContextExecutor.NotifyShardingTransaction();
+ return dbContextTransaction;
+ }
+
+ public Task ResetStateAsync(CancellationToken cancellationToken = new CancellationToken())
+ {
+ return _relationalConnection.ResetStateAsync(cancellationToken);
+ }
+
+ public async Task UseTransactionAsync(DbTransaction transaction, CancellationToken cancellationToken = new CancellationToken())
+ {
+ var dbContextTransaction = await _relationalConnection.UseTransactionAsync(transaction, cancellationToken);
+ _shardingDbContextExecutor.NotifyShardingTransaction();
+ return dbContextTransaction;
+ }
+ }
+}
+#endif
diff --git a/src/ShardingCore/EFCores/EFCore3x/UnionAllMergeOptionsExtension.cs b/src/ShardingCore/EFCores/EFCore3x/UnionAllMergeOptionsExtension.cs
new file mode 100644
index 00000000..78ee1299
--- /dev/null
+++ b/src/ShardingCore/EFCores/EFCore3x/UnionAllMergeOptionsExtension.cs
@@ -0,0 +1,43 @@
+#if (NETCOREAPP3_0 || NETSTANDARD2_0) && SHARDINGCORE2_6
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.Extensions.DependencyInjection;
+
+namespace ShardingCore.EFCores
+{
+ /*
+ * @Author: xjm
+ * @Description:
+ * @Date: 2021/10/17 20:27:12
+ * @Ver: 1.0
+ * @Email: 326308290@qq.com
+ */
+ public class UnionAllMergeOptionsExtension: IDbContextOptionsExtension
+ {
+ public void ApplyServices(IServiceCollection services)
+ {
+ }
+
+ public void Validate(IDbContextOptions options)
+ {
+ }
+
+
+ public DbContextOptionsExtensionInfo Info => new UnionAllMergeDbContextOptionsExtensionInfo(this);
+
+ private class UnionAllMergeDbContextOptionsExtensionInfo : DbContextOptionsExtensionInfo
+ {
+ public UnionAllMergeDbContextOptionsExtensionInfo(IDbContextOptionsExtension extension) : base(extension) { }
+
+ public override long GetServiceProviderHashCode() => 0;
+
+ public override void PopulateDebugInfo(IDictionary debugInfo) { }
+
+ public override bool IsDatabaseProvider => false;
+ public override string LogFragment => "UnionAllMergeOptionsExtension";
+ }
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/ShardingCore/EFCores/EFCore5x/ScriptMigrationGenerator.cs b/src/ShardingCore/EFCores/EFCore5x/ScriptMigrationGenerator.cs
index f66d964b..7e553f64 100644
--- a/src/ShardingCore/EFCores/EFCore5x/ScriptMigrationGenerator.cs
+++ b/src/ShardingCore/EFCores/EFCore5x/ScriptMigrationGenerator.cs
@@ -1,4 +1,4 @@
-#if NET5_0 || NETSTANDARD2_1
+#if (NET5_0 || NETSTANDARD2_1)&&SHARDINGCORE2_6
using Microsoft.EntityFrameworkCore.Migrations;
using ShardingCore.Core.RuntimeContexts;
diff --git a/src/ShardingCore/EFCores/ChangeTrackers/ShardingChangeTracker.cs b/src/ShardingCore/EFCores/EFCore5x/ShardingChangeTracker.cs
similarity index 85%
rename from src/ShardingCore/EFCores/ChangeTrackers/ShardingChangeTracker.cs
rename to src/ShardingCore/EFCores/EFCore5x/ShardingChangeTracker.cs
index 4e61c171..52451c4c 100644
--- a/src/ShardingCore/EFCores/ChangeTrackers/ShardingChangeTracker.cs
+++ b/src/ShardingCore/EFCores/EFCore5x/ShardingChangeTracker.cs
@@ -1,4 +1,5 @@
-using System;
+#if (NET5_0 || NETSTANDARD2_1)&&SHARDINGCORE2_6
+using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.EntityFrameworkCore;
@@ -7,7 +8,7 @@ using Microsoft.EntityFrameworkCore.ChangeTracking.Internal;
using Microsoft.EntityFrameworkCore.Metadata;
using ShardingCore.Sharding.Abstractions;
-namespace ShardingCore.EFCores.ChangeTrackers
+namespace ShardingCore.EFCores
{
public class ShardingChangeTracker : ChangeTracker
{
@@ -20,10 +21,6 @@ namespace ShardingCore.EFCores.ChangeTrackers
_dbContext = context;
}
-#if !NETCOREAPP2_0 && !NETSTANDARD2_0 && !NETCOREAPP3_0 && !NETSTANDARD2_1 && !NET5_0 && !NET6_0
- error
-#endif
-
public override bool HasChanges()
{
if (_dbContext is IShardingDbContext shardingDbContext)
@@ -100,7 +97,6 @@ namespace ShardingCore.EFCores.ChangeTrackers
}
}
-#if !NETCOREAPP2_0
public override void TrackGraph(object rootEntity, TState state, Func, bool> callback) where TState : default
{
if (_dbContext is IShardingDbContext shardingDbContext)
@@ -121,8 +117,6 @@ namespace ShardingCore.EFCores.ChangeTrackers
base.CascadeChanges();
}
-#endif
-#if !NETCOREAPP2_0 && !NETCOREAPP3_0 && !NETSTANDARD2_0
public override void Clear()
{
if (_dbContext is IShardingDbContext)
@@ -132,18 +126,7 @@ namespace ShardingCore.EFCores.ChangeTrackers
}
base.Clear();
}
-#endif
-#if NETCOREAPP2_0
- public override void TrackGraph(object rootEntity, TState state, Func callback)
- {
- if (_dbContext is IShardingDbContext shardingDbContext)
- {
- var genericDbContext = shardingDbContext.CreateGenericDbContext(rootEntity);
- genericDbContext.ChangeTracker.TrackGraph(rootEntity,state,callback);
- // Do(c => c.TrackGraph(rootEntity,callback));
- }
- }
-#endif
}
-}
\ No newline at end of file
+}
+#endif
\ No newline at end of file
diff --git a/src/ShardingCore/EFCores/EFCore5x/ShardingDbSetSource.cs b/src/ShardingCore/EFCores/EFCore5x/ShardingDbSetSource.cs
new file mode 100644
index 00000000..7f0e9f5d
--- /dev/null
+++ b/src/ShardingCore/EFCores/EFCore5x/ShardingDbSetSource.cs
@@ -0,0 +1,57 @@
+#if (NET5_0 || NETSTANDARD2_1 ) && SHARDINGCORE2_6
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Internal;
+using System;
+using System.Collections.Concurrent;
+using System.Reflection;
+
+namespace ShardingCore.EFCores
+{
+ /*
+ * @Author: xjm
+ * @Description:
+ * @Date: Saturday, 14 August 2021 10:17:43
+ * @Email: 326308290@qq.com
+ */
+
+ public class ShardingDbSetSource : IDbSetSource
+ {
+
+ private static readonly MethodInfo _genericCreateSet
+ = typeof(ShardingDbSetSource).GetTypeInfo().GetDeclaredMethod(nameof(CreateSetFactory));
+
+ private readonly ConcurrentDictionary<(Type Type, string Name), Func> _cache
+ = new ConcurrentDictionary<(Type Type, string Name), Func>();
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// 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.
+ ///
+ public virtual object Create(DbContext context, Type type)
+ => CreateCore(context, type, null, _genericCreateSet);
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// 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.
+ ///
+ public virtual object Create(DbContext context, string name, Type type)
+ => CreateCore(context, type, name, _genericCreateSet);
+
+ private object CreateCore(DbContext context, Type type, string name, MethodInfo createMethod)
+ => _cache.GetOrAdd(
+ (type, name),
+ t => (Func)createMethod
+ .MakeGenericMethod(t.Type)
+ .Invoke(null, null))(context, name);
+
+ private static Func CreateSetFactory()
+ where TEntity : class
+ => (c, name) => new ShardingInternalDbSet(c, name);
+ }
+
+}
+#endif
\ No newline at end of file
diff --git a/src/ShardingCore/EFCores/EFCore5x/ShardingInternalDbSet.cs b/src/ShardingCore/EFCores/EFCore5x/ShardingInternalDbSet.cs
new file mode 100644
index 00000000..d75780b7
--- /dev/null
+++ b/src/ShardingCore/EFCores/EFCore5x/ShardingInternalDbSet.cs
@@ -0,0 +1,439 @@
+#if (NET5_0 || NETSTANDARD2_1 ) && SHARDINGCORE2_6
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.ChangeTracking;
+using Microsoft.EntityFrameworkCore.Internal;
+using ShardingCore.Core;
+using ShardingCore.Sharding.Abstractions;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using ShardingCore.Core.EntityMetadatas;
+using ShardingCore.Core.RuntimeContexts;
+using ShardingCore.Core.TrackerManagers;
+using ShardingCore.Core.VirtualDatabase.VirtualDataSources;
+using ShardingCore.Core.VirtualRoutes.Abstractions;
+using ShardingCore.Exceptions;
+using ShardingCore.Extensions;
+using ShardingCore.Utils;
+
+namespace ShardingCore.EFCores
+{
+ /*
+ * @Author: xjm
+ * @Description:
+ * @Date: 2021/8/15 8:39:15
+ * @Ver: 1.0
+ * @Email: 326308290@qq.com
+ */
+
+ public class ShardingInternalDbSet : InternalDbSet
+ where TEntity : class
+ {
+ private readonly IShardingDbContext _context;
+ private readonly IShardingRuntimeContext _shardingRuntimeContext;
+ private LocalView? _localView;
+
+
+
+ public ShardingInternalDbSet(DbContext context, string entityTypeName) : base(context, entityTypeName)
+ {
+ _context = (IShardingDbContext)context;
+ _shardingRuntimeContext = context.GetShardingRuntimeContext();
+ }
+
+ private IDataSourceRouteManager _dataSourceRouteManager;
+
+ protected IDataSourceRouteManager DataSourceRouteManager
+ {
+ get
+ {
+ if (null == _dataSourceRouteManager)
+ {
+ _dataSourceRouteManager = _shardingRuntimeContext.GetDataSourceRouteManager();
+ }
+
+ return _dataSourceRouteManager;
+ }
+ }
+
+ public override LocalView Local
+ {
+ get
+ {
+
+ if (((DbContext)_context).ChangeTracker.AutoDetectChangesEnabled)
+ {
+ ((DbContext)_context).ChangeTracker.DetectChanges();
+ }
+
+ return _localView ??= new ShardingLocalView(this);
+ }
+ }
+ private ITableRouteManager _tableRouteManager;
+
+ protected ITableRouteManager TableRouteManager
+ {
+ get
+ {
+ if (null == _tableRouteManager)
+ {
+ _tableRouteManager = _shardingRuntimeContext.GetTableRouteManager();
+ }
+
+ return _tableRouteManager;
+ }
+ }
+
+ private IEntityMetadataManager _entityMetadataManager;
+
+ protected IEntityMetadataManager EntityMetadataManager
+ {
+ get
+ {
+ if (null == _entityMetadataManager)
+ {
+ _entityMetadataManager = _shardingRuntimeContext.GetEntityMetadataManager();
+ }
+
+ return _entityMetadataManager;
+ }
+ }
+
+ private ITrackerManager _trackerManager;
+
+ protected ITrackerManager TrackerManager
+ {
+ get
+ {
+ if (null == _trackerManager)
+ {
+ _trackerManager = _shardingRuntimeContext.GetTrackerManager();
+ }
+
+ return _trackerManager;
+ }
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// 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.
+ ///
+ public override EntityEntry Add(TEntity entity)
+ {
+ var genericDbContext = _context.CreateGenericDbContext(entity);
+ return genericDbContext.Set().Add(entity);
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// 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.
+ ///
+ public override async ValueTask> AddAsync(
+ TEntity entity,
+ CancellationToken cancellationToken = default)
+ {
+ var genericDbContext = _context.CreateGenericDbContext(entity);
+ return await genericDbContext.Set().AddAsync(entity, cancellationToken);
+ }
+
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// 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.
+ ///
+ public override EntityEntry Attach(TEntity entity)
+ {
+ var genericDbContext = _context.CreateGenericDbContext(entity);
+ return genericDbContext.Set().Attach(entity);
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// 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.
+ ///
+ public override EntityEntry Remove(TEntity entity)
+ {
+ Check.NotNull(entity, nameof(entity));
+
+ var genericDbContext = _context.CreateGenericDbContext(entity);
+ return genericDbContext.Set().Remove(entity);
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// 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.
+ ///
+ public override EntityEntry Update(TEntity entity)
+ {
+ var genericDbContext = _context.CreateGenericDbContext(entity);
+ return genericDbContext.Set().Update(entity);
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// 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.
+ ///
+ public override void AddRange(params TEntity[] entities)
+ {
+ var aggregateToDic = AggregateToDic(entities);
+ foreach (var aggregateKv in aggregateToDic)
+ {
+ aggregateKv.Key.Set().AddRange(aggregateKv.Value);
+ }
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// 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.
+ ///
+ public override async Task AddRangeAsync(params TEntity[] entities)
+ {
+ var aggregateToDic = AggregateToDic(entities);
+ foreach (var aggregateKv in aggregateToDic)
+ {
+ await aggregateKv.Key.Set().AddRangeAsync(aggregateKv.Value);
+ }
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// 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.
+ ///
+ public override void AttachRange(params TEntity[] entities)
+ {
+ var aggregateToDic = AggregateToDic(entities);
+ foreach (var aggregateKv in aggregateToDic)
+ {
+ aggregateKv.Key.Set().AttachRange(aggregateKv.Value);
+ }
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// 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.
+ ///
+ public override void RemoveRange(params TEntity[] entities)
+ {
+ Check.NotNull(entities, nameof(entities));
+ var aggregateToDic = AggregateToDic(entities);
+ foreach (var aggregateKv in aggregateToDic)
+ {
+ aggregateKv.Key.Set().RemoveRange(aggregateKv.Value);
+ }
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// 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.
+ ///
+ public override void UpdateRange(params TEntity[] entities)
+ {
+ var aggregateToDic = AggregateToDic(entities);
+ foreach (var aggregateKv in aggregateToDic)
+ {
+ aggregateKv.Key.Set().UpdateRange(aggregateKv.Value);
+ }
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// 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.
+ ///
+ public override void AddRange(IEnumerable entities)
+ {
+ var aggregateToDic = AggregateToDic(entities);
+ foreach (var aggregateKv in aggregateToDic)
+ {
+ aggregateKv.Key.Set().AddRange(aggregateKv.Value);
+ }
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// 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.
+ ///
+ public override async Task AddRangeAsync(
+ IEnumerable entities,
+ CancellationToken cancellationToken = default)
+ {
+ var aggregateToDic = AggregateToDic(entities);
+ foreach (var aggregateKv in aggregateToDic)
+ {
+ await aggregateKv.Key.Set().AddRangeAsync(aggregateKv.Value, cancellationToken);
+ }
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// 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.
+ ///
+ public override void AttachRange(IEnumerable entities)
+ {
+ var aggregateToDic = AggregateToDic(entities);
+ foreach (var aggregateKv in aggregateToDic)
+ {
+ aggregateKv.Key.Set().AttachRange(aggregateKv.Value);
+ }
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// 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.
+ ///
+ public override void RemoveRange(IEnumerable entities)
+ {
+ Check.NotNull(entities, nameof(entities));
+
+
+ var aggregateToDic = AggregateToDic(entities);
+ foreach (var aggregateKv in aggregateToDic)
+ {
+ aggregateKv.Key.Set().RemoveRange(aggregateKv.Value);
+ }
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// 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.
+ ///
+ public override void UpdateRange(IEnumerable entities)
+ {
+ var aggregateToDic = AggregateToDic(entities);
+ foreach (var aggregateKv in aggregateToDic)
+ {
+ aggregateKv.Key.Set().UpdateRange(aggregateKv.Value);
+ }
+ }
+
+ private Dictionary> AggregateToDic(IEnumerable entities)
+ {
+ return entities.Select(o =>
+ {
+ var dbContext = _context.CreateGenericDbContext(o);
+ return new
+ {
+ DbContext = dbContext,
+ Entity = o
+ };
+ }).GroupBy(g => g.DbContext).ToDictionary(o => o.Key, o => o.Select(g => g.Entity));
+ }
+
+ public override TEntity Find(params object[] keyValues)
+ {
+ var primaryKeyFindDbContext = GetDbContextByKeyValue(keyValues);
+ if (primaryKeyFindDbContext != null)
+ {
+ return primaryKeyFindDbContext.Set().Find(keyValues);
+ }
+
+ return base.Find(keyValues);
+ }
+
+ public override ValueTask FindAsync(params object[] keyValues)
+ {
+ var primaryKeyFindDbContext = GetDbContextByKeyValue(keyValues);
+ if (primaryKeyFindDbContext != null)
+ {
+ return primaryKeyFindDbContext.Set().FindAsync(keyValues);
+ }
+
+ return base.FindAsync(keyValues);
+ }
+
+ public override ValueTask FindAsync(object[] keyValues, CancellationToken cancellationToken)
+ {
+ var primaryKeyFindDbContext = GetDbContextByKeyValue(keyValues);
+ if (primaryKeyFindDbContext != null)
+ {
+ return primaryKeyFindDbContext.Set().FindAsync(keyValues, cancellationToken);
+ }
+
+ return base.FindAsync(keyValues, cancellationToken);
+ }
+
+
+ private DbContext GetDbContextByKeyValue(params object[] keyValues)
+ {
+ var entityMetadata = EntityMetadataManager.TryGet(typeof(TEntity));
+ if (entityMetadata == null)
+ {
+ throw new ShardingCoreInvalidOperationException(
+ $"cant found type:[{typeof(TEntity)}] in {nameof(IEntityMetadataManager)}");
+ }
+
+ //既不是分表也不是分库的话就是默认对象
+ if (!entityMetadata.IsShardingTable() && !entityMetadata.IsShardingDataSource())
+ {
+ var defaultDataSourceName = _shardingRuntimeContext.GetVirtualDataSource().DefaultDataSourceName;
+ var routeTailFactory = _shardingRuntimeContext.GetRouteTailFactory();
+ var routeTail = routeTailFactory.Create(string.Empty);
+ return _context.GetShareDbContext(defaultDataSourceName, routeTail);
+ }
+
+ if (keyValues.Length == 1)
+ {
+ //单key字段
+ if (entityMetadata.IsSingleKey)
+ {
+ var isShardingDataSource = entityMetadata.IsShardingDataSource();
+ var shardingDataSourceFieldIsKey = entityMetadata.ShardingDataSourceFieldIsKey();
+ if (isShardingDataSource && !shardingDataSourceFieldIsKey)
+ return null;
+ var isShardingTable = entityMetadata.IsShardingTable();
+ var shardingTableFieldIsKey = entityMetadata.ShardingTableFieldIsKey();
+ if (isShardingTable && !shardingTableFieldIsKey)
+ return null;
+ var primaryKeyValue = keyValues[0];
+ if (primaryKeyValue != null)
+ {
+ var dataSourceName = GetDataSourceName(primaryKeyValue);
+ var realEntityType = TrackerManager.TranslateEntityType(typeof(TEntity));
+ var tableTail = TableRouteManager.GetTableTail(dataSourceName, primaryKeyValue,realEntityType);
+ var routeTail = _shardingRuntimeContext.GetRouteTailFactory().Create(tableTail);
+ return _context.GetShareDbContext(dataSourceName, routeTail);
+ }
+ }
+ }
+
+ return null;
+ }
+
+ private string GetDataSourceName(object shardingKeyValue)
+ {
+ return DataSourceRouteManager.GetDataSourceName(shardingKeyValue);
+ }
+ }
+}
+#endif
diff --git a/src/ShardingCore/EFCores/EFCore5x/ShardingMigrator.cs b/src/ShardingCore/EFCores/EFCore5x/ShardingMigrator.cs
new file mode 100644
index 00000000..c2d297cc
--- /dev/null
+++ b/src/ShardingCore/EFCores/EFCore5x/ShardingMigrator.cs
@@ -0,0 +1,50 @@
+
+#if (NET5_0 || NETSTANDARD2_1)&&SHARDINGCORE2_6
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Diagnostics;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Migrations.Internal;
+using Microsoft.EntityFrameworkCore.Storage;
+using ShardingCore.Core.RuntimeContexts;
+using ShardingCore.Extensions;
+using ShardingCore.Helpers;
+using Microsoft.EntityFrameworkCore.Metadata.Conventions.Infrastructure;
+
+namespace ShardingCore.EFCores
+{
+ public class ShardingMigrator:Migrator
+ {
+ private readonly IShardingRuntimeContext _shardingRuntimeContext;
+
+
+ public ShardingMigrator(IShardingRuntimeContext shardingRuntimeContext, IMigrationsAssembly migrationsAssembly, IHistoryRepository historyRepository, IDatabaseCreator databaseCreator, IMigrationsSqlGenerator migrationsSqlGenerator, IRawSqlCommandBuilder rawSqlCommandBuilder, IMigrationCommandExecutor migrationCommandExecutor, IRelationalConnection connection, ISqlGenerationHelper sqlGenerationHelper, ICurrentDbContext currentContext, IConventionSetBuilder conventionSetBuilder, IDiagnosticsLogger logger, IDiagnosticsLogger commandLogger, IDatabaseProvider databaseProvider) : base(migrationsAssembly, historyRepository, databaseCreator, migrationsSqlGenerator, rawSqlCommandBuilder, migrationCommandExecutor, connection, sqlGenerationHelper, currentContext, conventionSetBuilder, logger, commandLogger, databaseProvider)
+ {
+ _shardingRuntimeContext = shardingRuntimeContext;
+ }
+ public override void Migrate(string targetMigration = null)
+ {
+ this.MigrateAsync(targetMigration).WaitAndUnwrapException(false);
+ // base.Migrate(targetMigration);
+ }
+
+ public override async Task MigrateAsync(string targetMigration = null, CancellationToken cancellationToken = new CancellationToken())
+ {
+ var virtualDataSource = _shardingRuntimeContext.GetVirtualDataSource();
+ var allDataSourceNames = virtualDataSource.GetAllDataSourceNames();
+ await DynamicShardingHelper.DynamicMigrateWithDataSourcesAsync(_shardingRuntimeContext, allDataSourceNames, null,targetMigration,cancellationToken).ConfigureAwait(false);
+
+ }
+
+ public override string GenerateScript(string fromMigration = null, string toMigration = null,
+ MigrationsSqlGenerationOptions options = MigrationsSqlGenerationOptions.Default)
+ {
+ return new ScriptMigrationGenerator(_shardingRuntimeContext, fromMigration, toMigration, options).GenerateScript();
+ }
+ }
+
+}
+
+#endif
\ No newline at end of file
diff --git a/src/ShardingCore/EFCores/EFCore5x/ShardingModelSource.cs b/src/ShardingCore/EFCores/EFCore5x/ShardingModelSource.cs
index d2243a14..2afed500 100644
--- a/src/ShardingCore/EFCores/EFCore5x/ShardingModelSource.cs
+++ b/src/ShardingCore/EFCores/EFCore5x/ShardingModelSource.cs
@@ -1,4 +1,4 @@
-#if NET5_0 || NETSTANDARD2_1
+#if (NET5_0 || NETSTANDARD2_1)&&SHARDINGCORE2_6
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
diff --git a/src/ShardingCore/EFCores/EFCore5x/ShardingOptionsExtension.cs b/src/ShardingCore/EFCores/EFCore5x/ShardingOptionsExtension.cs
new file mode 100644
index 00000000..a6e984fb
--- /dev/null
+++ b/src/ShardingCore/EFCores/EFCore5x/ShardingOptionsExtension.cs
@@ -0,0 +1,58 @@
+#if (NET5_0 || NETSTANDARD2_1) && SHARDINGCORE2_6
+using System;
+using System.Collections.Generic;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.Extensions.DependencyInjection;
+using ShardingCore.Core;
+using ShardingCore.Core.RuntimeContexts;
+
+namespace ShardingCore.EFCores
+{
+ /*
+ * @Author: xjm
+ * @Description:
+ * @Date: 2021/10/17 20:27:12
+ * @Ver: 1.0
+ * @Email: 326308290@qq.com
+ */
+
+ public class ShardingOptionsExtension: IDbContextOptionsExtension
+ {
+ public IShardingRuntimeContext ShardingRuntimeContext { get; }
+
+ public ShardingOptionsExtension(IShardingRuntimeContext shardingRuntimeContext)
+ {
+ ShardingRuntimeContext = shardingRuntimeContext;
+ }
+ public void ApplyServices(IServiceCollection services)
+ {
+ services.AddSingleton(sp => ShardingRuntimeContext);
+ }
+
+ public void Validate(IDbContextOptions options)
+ {
+ }
+
+
+ public DbContextOptionsExtensionInfo Info => new ShardingOptionsExtensionInfo(this);
+
+ private class ShardingOptionsExtensionInfo : DbContextOptionsExtensionInfo
+ {
+ private readonly ShardingOptionsExtension _shardingOptionsExtension;
+ public ShardingOptionsExtensionInfo(IDbContextOptionsExtension extension) : base(extension)
+ {
+ _shardingOptionsExtension = (ShardingOptionsExtension)extension;
+ }
+
+
+ public override long GetServiceProviderHashCode() => _shardingOptionsExtension.ShardingRuntimeContext.GetHashCode();
+
+ public override void PopulateDebugInfo(IDictionary debugInfo) { }
+
+ public override bool IsDatabaseProvider => false;
+ public override string LogFragment => "ShardingOptionsExtension";
+ }
+ }
+}
+
+#endif
\ No newline at end of file
diff --git a/src/ShardingCore/EFCores/EFCore5x/ShardingWrapOptionsExtension.cs b/src/ShardingCore/EFCores/EFCore5x/ShardingWrapOptionsExtension.cs
new file mode 100644
index 00000000..193cb799
--- /dev/null
+++ b/src/ShardingCore/EFCores/EFCore5x/ShardingWrapOptionsExtension.cs
@@ -0,0 +1,48 @@
+#if (NET5_0 || NETSTANDARD2_1) && SHARDINGCORE2_6
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.Extensions.DependencyInjection;
+using ShardingCore.Core;
+
+namespace ShardingCore.EFCores
+{
+ /*
+ * @Author: xjm
+ * @Description:
+ * @Date: 2021/10/17 20:27:12
+ * @Ver: 1.0
+ * @Email: 326308290@qq.com
+ */
+
+
+
+ public class ShardingWrapOptionsExtension: IDbContextOptionsExtension
+ {
+ public void ApplyServices(IServiceCollection services)
+ {
+ }
+
+ public void Validate(IDbContextOptions options)
+ {
+ }
+
+
+ public DbContextOptionsExtensionInfo Info => new ShardingWrapDbContextOptionsExtensionInfo(this);
+
+ private class ShardingWrapDbContextOptionsExtensionInfo : DbContextOptionsExtensionInfo
+ {
+ public ShardingWrapDbContextOptionsExtensionInfo(IDbContextOptionsExtension extension) : base(extension) { }
+
+ public override long GetServiceProviderHashCode() => 0;
+
+ public override void PopulateDebugInfo(IDictionary debugInfo) { }
+
+ public override bool IsDatabaseProvider => false;
+ public override string LogFragment => "ShardingWrapOptionsExtension";
+ }
+ }
+}
+
+#endif
diff --git a/src/ShardingCore/EFCores/RelationTransactions/ShardingRelationalTransaction.cs b/src/ShardingCore/EFCores/EFCore5x/Tx/ShardingRelationalTransaction.cs
similarity index 69%
rename from src/ShardingCore/EFCores/RelationTransactions/ShardingRelationalTransaction.cs
rename to src/ShardingCore/EFCores/EFCore5x/Tx/ShardingRelationalTransaction.cs
index 0cfc15c7..828ab689 100644
--- a/src/ShardingCore/EFCores/RelationTransactions/ShardingRelationalTransaction.cs
+++ b/src/ShardingCore/EFCores/EFCore5x/Tx/ShardingRelationalTransaction.cs
@@ -1,4 +1,5 @@
-using System;
+#if (NET5_0 || NETSTANDARD2_1)&&SHARDINGCORE2_6
+using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Text;
@@ -20,26 +21,11 @@ namespace ShardingCore.EFCores
* @Ver: 1.0
* @Email: 326308290@qq.com
*/
-#if !NETCOREAPP2_0 && !NETSTANDARD2_0 && !NETCOREAPP3_0 && !NETSTANDARD2_1 && !NET5_0 && !NET6_0
- error
-#endif
public class ShardingRelationalTransaction : RelationalTransaction
{
private readonly IShardingDbContext _shardingDbContext;
private readonly IShardingDbContextExecutor _shardingDbContextExecutor;
-#if NET6_0
- public ShardingRelationalTransaction(IShardingDbContext shardingDbContext, IRelationalConnection connection, DbTransaction transaction, Guid transactionId, IDiagnosticsLogger logger, bool transactionOwned, ISqlGenerationHelper sqlGenerationHelper) : base(connection, transaction, transactionId, logger, transactionOwned, sqlGenerationHelper)
- {
- _shardingDbContext =
- shardingDbContext ?? throw new ShardingCoreInvalidOperationException($"should implement {nameof(IShardingDbContext)}");
- _shardingDbContextExecutor = shardingDbContext.GetShardingExecutor() ??
- throw new ShardingCoreInvalidOperationException(
- $"{shardingDbContext.GetType()} cant get {nameof(IShardingDbContextExecutor)} from {nameof(shardingDbContext.GetShardingExecutor)}");
- }
-
-#endif
-#if NETCOREAPP3_0 || NETSTANDARD2_0 || NET5_0 || NETSTANDARD2_1
public ShardingRelationalTransaction(IShardingDbContext shardingDbContext, IRelationalConnection connection,
DbTransaction transaction, Guid transactionId,
IDiagnosticsLogger logger, bool transactionOwned) : base(connection,
@@ -53,19 +39,6 @@ namespace ShardingCore.EFCores
$"{shardingDbContext.GetType()} cant get {nameof(IShardingDbContextExecutor)} from {nameof(shardingDbContext.GetShardingExecutor)}");
}
-#endif
-#if NETCOREAPP2_0
- public ShardingRelationalTransaction(IShardingDbContext shardingDbContext, IRelationalConnection connection, DbTransaction transaction,IDiagnosticsLogger logger, bool transactionOwned) : base(connection, transaction, logger, transactionOwned)
- {
- _shardingDbContext =
- shardingDbContext??throw new ShardingCoreInvalidOperationException($"should implement {nameof(IShardingDbContext)}");
- _shardingDbContextExecutor = shardingDbContext.GetShardingExecutor() ??
- throw new ShardingCoreInvalidOperationException(
- $"{shardingDbContext.GetType()} cant get {nameof(IShardingDbContextExecutor)} from {nameof(shardingDbContext.GetShardingExecutor)}");
-
- }
-
-#endif
//protected override void ClearTransaction()
//{
// if (_canClear)
@@ -88,7 +61,6 @@ namespace ShardingCore.EFCores
_shardingDbContextExecutor.NotifyShardingTransaction();
}
-#if !NETCOREAPP2_0
public override async Task RollbackAsync(CancellationToken cancellationToken = new CancellationToken())
{
await base.RollbackAsync(cancellationToken);
@@ -104,7 +76,6 @@ namespace ShardingCore.EFCores
await _shardingDbContextExecutor.CommitAsync(cancellationToken);
_shardingDbContextExecutor.NotifyShardingTransaction();
}
-#if !NETCOREAPP3_0&&!NETSTANDARD2_0
public override void CreateSavepoint(string name)
{
base.CreateSavepoint(name);
@@ -140,7 +111,6 @@ namespace ShardingCore.EFCores
await base.ReleaseSavepointAsync(name, cancellationToken);
await _shardingDbContextExecutor.ReleaseSavepointAsync(name,cancellationToken);
}
-#endif
-#endif
}
-}
\ No newline at end of file
+}
+#endif
\ No newline at end of file
diff --git a/src/ShardingCore/EFCores/EFCore5x/Tx/ShardingRelationalTransactionFactory.cs b/src/ShardingCore/EFCores/EFCore5x/Tx/ShardingRelationalTransactionFactory.cs
new file mode 100644
index 00000000..3a52e2f0
--- /dev/null
+++ b/src/ShardingCore/EFCores/EFCore5x/Tx/ShardingRelationalTransactionFactory.cs
@@ -0,0 +1,39 @@
+#if (NET5_0 || NETSTANDARD2_1) && SHARDINGCORE2_6
+using System;
+using System.Collections.Generic;
+using System.Data.Common;
+using System.Text;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Diagnostics;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Storage;
+using ShardingCore.Extensions;
+using ShardingCore.Sharding.Abstractions;
+
+namespace ShardingCore.EFCores
+{
+ /*
+ * @Author: xjm
+ * @Description:
+ * @Date: 2021/9/5 16:03:04
+ * @Ver: 1.0
+ * @Email: 326308290@qq.com
+ */
+
+
+ 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, Guid transactionId,
+ IDiagnosticsLogger logger, bool transactionOwned)
+ {
+ var shardingDbContext = connection.Context as IShardingDbContext;
+ return new ShardingRelationalTransaction(shardingDbContext, connection, transaction, transactionId, logger, transactionOwned);
+ }
+ }
+}
+#endif
diff --git a/src/ShardingCore/EFCores/EFCore5x/Tx/ShardingRelationalTransactionManager.cs b/src/ShardingCore/EFCores/EFCore5x/Tx/ShardingRelationalTransactionManager.cs
new file mode 100644
index 00000000..64481077
--- /dev/null
+++ b/src/ShardingCore/EFCores/EFCore5x/Tx/ShardingRelationalTransactionManager.cs
@@ -0,0 +1,125 @@
+#if (NET5_0 || NETSTANDARD2_1) && SHARDINGCORE2_6
+
+using System;
+using System.Collections.Generic;
+using System.Data;
+using System.Data.Common;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Storage;
+using ShardingCore.Exceptions;
+using ShardingCore.Extensions;
+using ShardingCore.Sharding.Abstractions;
+
+namespace ShardingCore.EFCores
+{
+ /*
+ * @Author: xjm
+ * @Description:
+ * @Date: 2021/10/20 10:08:42
+ * @Ver: 1.0
+ * @Email: 326308290@qq.com
+ */
+ ///
+ /// manage transaction
+ ///
+ public class ShardingRelationalTransactionManager : IRelationalTransactionManager where TShardingDbContext : DbContext, IShardingDbContext
+ {
+ private readonly IRelationalConnection _relationalConnection;
+ private readonly IShardingDbContext _shardingDbContext;
+ private readonly IShardingDbContextExecutor _shardingDbContextExecutor;
+ public ShardingRelationalTransactionManager(IRelationalConnection relationalConnection)
+ {
+ _relationalConnection = relationalConnection;
+ _shardingDbContext = relationalConnection.Context as IShardingDbContext??throw new ShardingCoreInvalidOperationException($"should implement {nameof(IShardingDbContext)}");
+ _shardingDbContextExecutor = _shardingDbContext.GetShardingExecutor();
+ }
+
+ public void ResetState()
+ {
+ _relationalConnection.ResetState();
+ }
+
+ public IDbContextTransaction BeginTransaction()
+ {
+ return BeginTransaction(IsolationLevel.Unspecified);
+ }
+
+ public Task BeginTransactionAsync(CancellationToken cancellationToken = new CancellationToken())
+ {
+ return BeginTransactionAsync(IsolationLevel.Unspecified, cancellationToken);
+ }
+
+ public void CommitTransaction()
+ {
+ _relationalConnection.CommitTransaction();
+ }
+
+
+ public void RollbackTransaction()
+ {
+ _relationalConnection.RollbackTransaction();
+ }
+
+
+ public IDbContextTransaction CurrentTransaction => _relationalConnection.CurrentTransaction;
+ public IDbContextTransaction BeginTransaction(IsolationLevel isolationLevel)
+ {
+ var dbContextTransaction = _relationalConnection.BeginTransaction(isolationLevel);
+ _shardingDbContextExecutor.NotifyShardingTransaction();
+ return dbContextTransaction;
+ }
+
+ public async Task BeginTransactionAsync(IsolationLevel isolationLevel,
+ CancellationToken cancellationToken = new CancellationToken())
+ {
+ var dbContextTransaction = await _relationalConnection.BeginTransactionAsync(isolationLevel, cancellationToken);
+ _shardingDbContextExecutor.NotifyShardingTransaction();
+ return dbContextTransaction;
+ }
+
+ public IDbContextTransaction UseTransaction(DbTransaction transaction)
+ {
+ var dbContextTransaction = _relationalConnection.UseTransaction(transaction);
+ _shardingDbContextExecutor.NotifyShardingTransaction();
+ return dbContextTransaction;
+ }
+
+ public Task ResetStateAsync(CancellationToken cancellationToken = new CancellationToken())
+ {
+ return _relationalConnection.ResetStateAsync(cancellationToken);
+ }
+
+ public async Task UseTransactionAsync(DbTransaction transaction, CancellationToken cancellationToken = new CancellationToken())
+ {
+ var dbContextTransaction = await _relationalConnection.UseTransactionAsync(transaction, cancellationToken);
+ _shardingDbContextExecutor.NotifyShardingTransaction();
+ return dbContextTransaction;
+ }
+
+ public Task CommitTransactionAsync(CancellationToken cancellationToken = new CancellationToken())
+ {
+ return _relationalConnection.CommitTransactionAsync(cancellationToken);
+ }
+ public Task RollbackTransactionAsync(CancellationToken cancellationToken = new CancellationToken())
+ {
+ return _relationalConnection.RollbackTransactionAsync(cancellationToken);
+ }
+ public IDbContextTransaction UseTransaction(DbTransaction transaction, Guid transactionId)
+ {
+ var dbContextTransaction = _relationalConnection.UseTransaction(transaction, transactionId);
+ _shardingDbContextExecutor.NotifyShardingTransaction();
+ return dbContextTransaction;
+ }
+ public async Task UseTransactionAsync(DbTransaction transaction, Guid transactionId,
+ CancellationToken cancellationToken = new CancellationToken())
+ {
+ var dbContextTransaction = await _relationalConnection.UseTransactionAsync(transaction, transactionId, cancellationToken);
+ _shardingDbContextExecutor.NotifyShardingTransaction();
+ return dbContextTransaction;
+ }
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/ShardingCore/EFCores/EFCore5x/UnionAllMergeOptionsExtension.cs b/src/ShardingCore/EFCores/EFCore5x/UnionAllMergeOptionsExtension.cs
new file mode 100644
index 00000000..f48e0902
--- /dev/null
+++ b/src/ShardingCore/EFCores/EFCore5x/UnionAllMergeOptionsExtension.cs
@@ -0,0 +1,47 @@
+#if (NET5_0 || NETSTANDARD2_1) && SHARDINGCORE2_6
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.Extensions.DependencyInjection;
+
+namespace ShardingCore.EFCores
+{
+ /*
+ * @Author: xjm
+ * @Description:
+ * @Date: 2021/10/17 20:27:12
+ * @Ver: 1.0
+ * @Email: 326308290@qq.com
+ */
+
+
+
+ public class UnionAllMergeOptionsExtension: IDbContextOptionsExtension
+ {
+ public void ApplyServices(IServiceCollection services)
+ {
+ }
+
+ public void Validate(IDbContextOptions options)
+ {
+ }
+
+
+ public DbContextOptionsExtensionInfo Info => new UnionAllMergeDbContextOptionsExtensionInfo(this);
+
+ private class UnionAllMergeDbContextOptionsExtensionInfo : DbContextOptionsExtensionInfo
+ {
+ public UnionAllMergeDbContextOptionsExtensionInfo(IDbContextOptionsExtension extension) : base(extension) { }
+
+ public override long GetServiceProviderHashCode() => 0;
+
+ public override void PopulateDebugInfo(IDictionary debugInfo) { }
+
+ public override bool IsDatabaseProvider => false;
+ public override string LogFragment => "UnionAllMergeOptionsExtension";
+ }
+ }
+}
+
+#endif
diff --git a/src/ShardingCore/EFCores/EFCore6x/ScriptMigrationGenerator.cs b/src/ShardingCore/EFCores/EFCore6x/ScriptMigrationGenerator.cs
index 3f556d01..3412d11a 100644
--- a/src/ShardingCore/EFCores/EFCore6x/ScriptMigrationGenerator.cs
+++ b/src/ShardingCore/EFCores/EFCore6x/ScriptMigrationGenerator.cs
@@ -1,4 +1,4 @@
-#if NET6_0
+#if NET6_0&&SHARDINGCORE2_6
using Microsoft.EntityFrameworkCore.Migrations;
using ShardingCore.Core.RuntimeContexts;
diff --git a/src/ShardingCore/EFCores/EFCore6x/ShardingChangeTracker.cs b/src/ShardingCore/EFCores/EFCore6x/ShardingChangeTracker.cs
new file mode 100644
index 00000000..80be06b1
--- /dev/null
+++ b/src/ShardingCore/EFCores/EFCore6x/ShardingChangeTracker.cs
@@ -0,0 +1,132 @@
+#if NET6_0&&SHARDINGCORE2_6
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.ChangeTracking;
+using Microsoft.EntityFrameworkCore.ChangeTracking.Internal;
+using Microsoft.EntityFrameworkCore.Metadata;
+using ShardingCore.Sharding.Abstractions;
+
+namespace ShardingCore.EFCores
+{
+ public class ShardingChangeTracker : ChangeTracker
+ {
+ private readonly DbContext _dbContext;
+
+ public ShardingChangeTracker(DbContext context, IStateManager stateManager, IChangeDetector changeDetector,
+ IModel model, IEntityEntryGraphIterator graphIterator) : base(context, stateManager, changeDetector, model,
+ graphIterator)
+ {
+ _dbContext = context;
+ }
+
+ public override bool HasChanges()
+ {
+ if (_dbContext is IShardingDbContext shardingDbContext)
+ {
+ return shardingDbContext.GetShardingExecutor().GetCurrentDbContexts().Any(o =>
+ o.Value.GetCurrentContexts().Any(r => r.Value.ChangeTracker.HasChanges()));
+ }
+
+ return base.HasChanges();
+ }
+
+ public override IEnumerable Entries()
+ {
+ if (_dbContext is IShardingDbContext shardingDbContext)
+ {
+ return shardingDbContext.GetShardingExecutor().GetCurrentDbContexts().SelectMany(o =>
+ o.Value.GetCurrentContexts().SelectMany(cd => cd.Value.ChangeTracker.Entries()));
+ }
+
+ return base.Entries();
+ }
+
+ public override IEnumerable> Entries()
+ {
+ if (_dbContext is IShardingDbContext shardingDbContext)
+ {
+ return shardingDbContext.GetShardingExecutor().GetCurrentDbContexts().SelectMany(o =>
+ o.Value.GetCurrentContexts().SelectMany(cd => cd.Value.ChangeTracker.Entries()));
+ }
+
+ return base.Entries();
+ }
+
+ public override void DetectChanges()
+ {
+ if (_dbContext is IShardingDbContext)
+ {
+ Do(c => c.DetectChanges());
+ return;
+ }
+ base.DetectChanges();
+ }
+
+ public override void AcceptAllChanges()
+ {
+ if (_dbContext is IShardingDbContext)
+ {
+ Do(c => c.AcceptAllChanges());
+ return;
+ }
+ base.AcceptAllChanges();
+ }
+
+ private void Do(Action action)
+ {
+ var dataSourceDbContexts = ((IShardingDbContext)_dbContext).GetShardingExecutor().GetCurrentDbContexts();
+ foreach (var dataSourceDbContext in dataSourceDbContexts)
+ {
+ var currentContexts = dataSourceDbContext.Value.GetCurrentContexts();
+ foreach (var keyValuePair in currentContexts)
+ {
+ action(keyValuePair.Value.ChangeTracker);
+ }
+ }
+ }
+
+ public override void TrackGraph(object rootEntity, Action callback)
+ {
+ if (_dbContext is IShardingDbContext shardingDbContext)
+ {
+ var genericDbContext = shardingDbContext.CreateGenericDbContext(rootEntity);
+ genericDbContext.ChangeTracker.TrackGraph(rootEntity,callback);
+ // Do(c => c.TrackGraph(rootEntity,callback));
+ }
+ }
+
+ public override void TrackGraph(object rootEntity, TState state, Func, bool> callback) where TState : default
+ {
+ if (_dbContext is IShardingDbContext shardingDbContext)
+ {
+ var genericDbContext = shardingDbContext.CreateGenericDbContext(rootEntity);
+ genericDbContext.ChangeTracker.TrackGraph(rootEntity,state,callback);
+ // Do(c => c.TrackGraph(rootEntity,callback));
+ }
+ }
+
+ public override void CascadeChanges()
+ {
+ if (_dbContext is IShardingDbContext)
+ {
+ Do(c => c.CascadeChanges());
+ return;
+ }
+ base.CascadeChanges();
+ }
+
+ public override void Clear()
+ {
+ if (_dbContext is IShardingDbContext)
+ {
+ Do(c => c.Clear());
+ return;
+ }
+ base.Clear();
+ }
+
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/ShardingCore/EFCores/EFCore6x/ShardingDbSetSource.cs b/src/ShardingCore/EFCores/EFCore6x/ShardingDbSetSource.cs
new file mode 100644
index 00000000..96c40d89
--- /dev/null
+++ b/src/ShardingCore/EFCores/EFCore6x/ShardingDbSetSource.cs
@@ -0,0 +1,57 @@
+#if NET6_0 && SHARDINGCORE2_6
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Internal;
+using System;
+using System.Collections.Concurrent;
+using System.Reflection;
+
+namespace ShardingCore.EFCores
+{
+ /*
+ * @Author: xjm
+ * @Description:
+ * @Date: Saturday, 14 August 2021 10:17:43
+ * @Email: 326308290@qq.com
+ */
+
+ public class ShardingDbSetSource : IDbSetSource
+ {
+
+ private static readonly MethodInfo _genericCreateSet
+ = typeof(ShardingDbSetSource).GetTypeInfo().GetDeclaredMethod(nameof(CreateSetFactory));
+
+ private readonly ConcurrentDictionary<(Type Type, string Name), Func> _cache
+ = new ConcurrentDictionary<(Type Type, string Name), Func>();
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// 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.
+ ///
+ public virtual object Create(DbContext context, Type type)
+ => CreateCore(context, type, null, _genericCreateSet);
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// 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.
+ ///
+ public virtual object Create(DbContext context, string name, Type type)
+ => CreateCore(context, type, name, _genericCreateSet);
+
+ private object CreateCore(DbContext context, Type type, string name, MethodInfo createMethod)
+ => _cache.GetOrAdd(
+ (type, name),
+ t => (Func)createMethod
+ .MakeGenericMethod(t.Type)
+ .Invoke(null, null))(context, name);
+
+ private static Func CreateSetFactory()
+ where TEntity : class
+ => (c, name) => new ShardingInternalDbSet(c, name);
+ }
+
+}
+#endif
\ No newline at end of file
diff --git a/src/ShardingCore/EFCores/EFCore6x/ShardingInternalDbSet.cs b/src/ShardingCore/EFCores/EFCore6x/ShardingInternalDbSet.cs
new file mode 100644
index 00000000..6b227177
--- /dev/null
+++ b/src/ShardingCore/EFCores/EFCore6x/ShardingInternalDbSet.cs
@@ -0,0 +1,436 @@
+#if NET6_0 && SHARDINGCORE2_6
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.ChangeTracking;
+using Microsoft.EntityFrameworkCore.Internal;
+using ShardingCore.Core;
+using ShardingCore.Sharding.Abstractions;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using ShardingCore.Core.EntityMetadatas;
+using ShardingCore.Core.RuntimeContexts;
+using ShardingCore.Core.TrackerManagers;
+using ShardingCore.Core.VirtualDatabase.VirtualDataSources;
+using ShardingCore.Core.VirtualRoutes.Abstractions;
+using ShardingCore.Exceptions;
+using ShardingCore.Extensions;
+using ShardingCore.Utils;
+
+namespace ShardingCore.EFCores
+{
+ /*
+ * @Author: xjm
+ * @Description:
+ * @Date: 2021/8/15 8:39:15
+ * @Ver: 1.0
+ * @Email: 326308290@qq.com
+ */
+ public class ShardingInternalDbSet : InternalDbSet
+ where TEntity : class
+ {
+ private readonly IShardingDbContext _context;
+ private readonly IShardingRuntimeContext _shardingRuntimeContext;
+ private LocalView? _localView;
+
+
+
+ public ShardingInternalDbSet(DbContext context, string entityTypeName) : base(context, entityTypeName)
+ {
+ _context = (IShardingDbContext)context;
+ _shardingRuntimeContext = context.GetShardingRuntimeContext();
+ }
+
+ private IDataSourceRouteManager _dataSourceRouteManager;
+
+ protected IDataSourceRouteManager DataSourceRouteManager
+ {
+ get
+ {
+ if (null == _dataSourceRouteManager)
+ {
+ _dataSourceRouteManager = _shardingRuntimeContext.GetDataSourceRouteManager();
+ }
+
+ return _dataSourceRouteManager;
+ }
+ }
+
+ public override LocalView Local
+ {
+ get
+ {
+
+ if (((DbContext)_context).ChangeTracker.AutoDetectChangesEnabled)
+ {
+ ((DbContext)_context).ChangeTracker.DetectChanges();
+ }
+
+ return _localView ??= new ShardingLocalView(this);
+ }
+ }
+ private ITableRouteManager _tableRouteManager;
+
+ protected ITableRouteManager TableRouteManager
+ {
+ get
+ {
+ if (null == _tableRouteManager)
+ {
+ _tableRouteManager = _shardingRuntimeContext.GetTableRouteManager();
+ }
+
+ return _tableRouteManager;
+ }
+ }
+
+ private IEntityMetadataManager _entityMetadataManager;
+
+ protected IEntityMetadataManager EntityMetadataManager
+ {
+ get
+ {
+ if (null == _entityMetadataManager)
+ {
+ _entityMetadataManager = _shardingRuntimeContext.GetEntityMetadataManager();
+ }
+
+ return _entityMetadataManager;
+ }
+ }
+
+ private ITrackerManager _trackerManager;
+
+ protected ITrackerManager TrackerManager
+ {
+ get
+ {
+ if (null == _trackerManager)
+ {
+ _trackerManager = _shardingRuntimeContext.GetTrackerManager();
+ }
+
+ return _trackerManager;
+ }
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// 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.
+ ///
+ public override EntityEntry Add(TEntity entity)
+ {
+ var genericDbContext = _context.CreateGenericDbContext(entity);
+ return genericDbContext.Set().Add(entity);
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// 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.
+ ///
+ public override async ValueTask> AddAsync(
+ TEntity entity,
+ CancellationToken cancellationToken = default)
+ {
+ var genericDbContext = _context.CreateGenericDbContext(entity);
+ return await genericDbContext.Set().AddAsync(entity, cancellationToken);
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// 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.
+ ///
+ public override EntityEntry Attach(TEntity entity)
+ {
+ var genericDbContext = _context.CreateGenericDbContext(entity);
+ return genericDbContext.Set().Attach(entity);
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// 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.
+ ///
+ public override EntityEntry Remove(TEntity entity)
+ {
+ Check.NotNull(entity, nameof(entity));
+
+ var genericDbContext = _context.CreateGenericDbContext(entity);
+ return genericDbContext.Set().Remove(entity);
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// 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.
+ ///
+ public override EntityEntry Update(TEntity entity)
+ {
+ var genericDbContext = _context.CreateGenericDbContext(entity);
+ return genericDbContext.Set().Update(entity);
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// 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.
+ ///
+ public override void AddRange(params TEntity[] entities)
+ {
+ var aggregateToDic = AggregateToDic(entities);
+ foreach (var aggregateKv in aggregateToDic)
+ {
+ aggregateKv.Key.Set().AddRange(aggregateKv.Value);
+ }
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// 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.
+ ///
+ public override async Task AddRangeAsync(params TEntity[] entities)
+ {
+ var aggregateToDic = AggregateToDic(entities);
+ foreach (var aggregateKv in aggregateToDic)
+ {
+ await aggregateKv.Key.Set().AddRangeAsync(aggregateKv.Value);
+ }
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// 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.
+ ///
+ public override void AttachRange(params TEntity[] entities)
+ {
+ var aggregateToDic = AggregateToDic(entities);
+ foreach (var aggregateKv in aggregateToDic)
+ {
+ aggregateKv.Key.Set().AttachRange(aggregateKv.Value);
+ }
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// 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.
+ ///
+ public override void RemoveRange(params TEntity[] entities)
+ {
+ Check.NotNull(entities, nameof(entities));
+ var aggregateToDic = AggregateToDic(entities);
+ foreach (var aggregateKv in aggregateToDic)
+ {
+ aggregateKv.Key.Set().RemoveRange(aggregateKv.Value);
+ }
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// 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.
+ ///
+ public override void UpdateRange(params TEntity[] entities)
+ {
+ var aggregateToDic = AggregateToDic(entities);
+ foreach (var aggregateKv in aggregateToDic)
+ {
+ aggregateKv.Key.Set().UpdateRange(aggregateKv.Value);
+ }
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// 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.
+ ///
+ public override void AddRange(IEnumerable entities)
+ {
+ var aggregateToDic = AggregateToDic(entities);
+ foreach (var aggregateKv in aggregateToDic)
+ {
+ aggregateKv.Key.Set().AddRange(aggregateKv.Value);
+ }
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// 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.
+ ///
+ public override async Task AddRangeAsync(
+ IEnumerable entities,
+ CancellationToken cancellationToken = default)
+ {
+ var aggregateToDic = AggregateToDic(entities);
+ foreach (var aggregateKv in aggregateToDic)
+ {
+ await aggregateKv.Key.Set().AddRangeAsync(aggregateKv.Value, cancellationToken);
+ }
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// 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.
+ ///
+ public override void AttachRange(IEnumerable entities)
+ {
+ var aggregateToDic = AggregateToDic(entities);
+ foreach (var aggregateKv in aggregateToDic)
+ {
+ aggregateKv.Key.Set().AttachRange(aggregateKv.Value);
+ }
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// 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.
+ ///
+ public override void RemoveRange(IEnumerable entities)
+ {
+ Check.NotNull(entities, nameof(entities));
+
+
+ var aggregateToDic = AggregateToDic(entities);
+ foreach (var aggregateKv in aggregateToDic)
+ {
+ aggregateKv.Key.Set().RemoveRange(aggregateKv.Value);
+ }
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// 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.
+ ///
+ public override void UpdateRange(IEnumerable entities)
+ {
+ var aggregateToDic = AggregateToDic(entities);
+ foreach (var aggregateKv in aggregateToDic)
+ {
+ aggregateKv.Key.Set().UpdateRange(aggregateKv.Value);
+ }
+ }
+
+ private Dictionary> AggregateToDic(IEnumerable entities)
+ {
+ return entities.Select(o =>
+ {
+ var dbContext = _context.CreateGenericDbContext(o);
+ return new
+ {
+ DbContext = dbContext,
+ Entity = o
+ };
+ }).GroupBy(g => g.DbContext).ToDictionary(o => o.Key, o => o.Select(g => g.Entity));
+ }
+
+ public override TEntity Find(params object[] keyValues)
+ {
+ var primaryKeyFindDbContext = GetDbContextByKeyValue(keyValues);
+ if (primaryKeyFindDbContext != null)
+ {
+ return primaryKeyFindDbContext.Set().Find(keyValues);
+ }
+
+ return base.Find(keyValues);
+ }
+
+ public override ValueTask FindAsync(params object[] keyValues)
+ {
+ var primaryKeyFindDbContext = GetDbContextByKeyValue(keyValues);
+ if (primaryKeyFindDbContext != null)
+ {
+ return primaryKeyFindDbContext.Set().FindAsync(keyValues);
+ }
+
+ return base.FindAsync(keyValues);
+ }
+
+ public override ValueTask FindAsync(object[] keyValues, CancellationToken cancellationToken)
+ {
+ var primaryKeyFindDbContext = GetDbContextByKeyValue(keyValues);
+ if (primaryKeyFindDbContext != null)
+ {
+ return primaryKeyFindDbContext.Set().FindAsync(keyValues, cancellationToken);
+ }
+
+ return base.FindAsync(keyValues, cancellationToken);
+ }
+
+ private DbContext GetDbContextByKeyValue(params object[] keyValues)
+ {
+ var entityMetadata = EntityMetadataManager.TryGet(typeof(TEntity));
+ if (entityMetadata == null)
+ {
+ throw new ShardingCoreInvalidOperationException(
+ $"cant found type:[{typeof(TEntity)}] in {nameof(IEntityMetadataManager)}");
+ }
+
+ //既不是分表也不是分库的话就是默认对象
+ if (!entityMetadata.IsShardingTable() && !entityMetadata.IsShardingDataSource())
+ {
+ var defaultDataSourceName = _shardingRuntimeContext.GetVirtualDataSource().DefaultDataSourceName;
+ var routeTailFactory = _shardingRuntimeContext.GetRouteTailFactory();
+ var routeTail = routeTailFactory.Create(string.Empty);
+ return _context.GetShareDbContext(defaultDataSourceName, routeTail);
+ }
+
+ if (keyValues.Length == 1)
+ {
+ //单key字段
+ if (entityMetadata.IsSingleKey)
+ {
+ var isShardingDataSource = entityMetadata.IsShardingDataSource();
+ var shardingDataSourceFieldIsKey = entityMetadata.ShardingDataSourceFieldIsKey();
+ if (isShardingDataSource && !shardingDataSourceFieldIsKey)
+ return null;
+ var isShardingTable = entityMetadata.IsShardingTable();
+ var shardingTableFieldIsKey = entityMetadata.ShardingTableFieldIsKey();
+ if (isShardingTable && !shardingTableFieldIsKey)
+ return null;
+ var primaryKeyValue = keyValues[0];
+ if (primaryKeyValue != null)
+ {
+ var dataSourceName = GetDataSourceName(primaryKeyValue);
+ var realEntityType = TrackerManager.TranslateEntityType(typeof(TEntity));
+ var tableTail = TableRouteManager.GetTableTail(dataSourceName, primaryKeyValue,realEntityType);
+ var routeTail = _shardingRuntimeContext.GetRouteTailFactory().Create(tableTail);
+ return _context.GetShareDbContext(dataSourceName, routeTail);
+ }
+ }
+ }
+
+ return null;
+ }
+
+ private string GetDataSourceName(object shardingKeyValue)
+ {
+ return DataSourceRouteManager.GetDataSourceName