修改添加对EFCORE7的支持
This commit is contained in:
parent
9a4306dd8d
commit
32d4d79a53
|
@ -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}
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\ShardingCore\ShardingCore.csproj" />
|
||||
<ProjectReference Include="..\..\src2_6\ShardingCore.2_6\ShardingCore.2_6.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -11,8 +11,8 @@
|
|||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="6.0.8" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\ShardingCore\ShardingCore.csproj" />
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src2_6\ShardingCore.2_6\ShardingCore.2_6.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\ShardingCore\ShardingCore.csproj" />
|
||||
<ProjectReference Include="..\..\src2_6\ShardingCore.2_6\ShardingCore.2_6.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="6.0.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\ShardingCore\ShardingCore.csproj" />
|
||||
<ProjectReference Include="..\..\src2_6\ShardingCore.2_6\ShardingCore.2_6.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -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<MigrationOperation> 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)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
|
@ -13,7 +13,7 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\ShardingCore\ShardingCore.csproj" />
|
||||
<ProjectReference Include="..\..\src2_6\ShardingCore.2_6\ShardingCore.2_6.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\ShardingCore\ShardingCore.csproj" />
|
||||
<ProjectReference Include="..\..\src2_6\ShardingCore.2_6\ShardingCore.2_6.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\ShardingCore\ShardingCore.csproj" />
|
||||
<ProjectReference Include="..\..\src2_6\ShardingCore.2_6\ShardingCore.2_6.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\ShardingCore\ShardingCore.csproj" />
|
||||
<ProjectReference Include="..\..\src2_6\ShardingCore.2_6\ShardingCore.2_6.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\ShardingCore\ShardingCore.csproj" />
|
||||
<ProjectReference Include="..\..\src2_6\ShardingCore.2_6\ShardingCore.2_6.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\ShardingCore\ShardingCore.csproj" />
|
||||
<ProjectReference Include="..\..\src2_6\ShardingCore.2_6\ShardingCore.2_6.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\ShardingCore\ShardingCore.csproj" />
|
||||
<ProjectReference Include="..\..\src2_6\ShardingCore.2_6\ShardingCore.2_6.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="3.1.23" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\ShardingCore\ShardingCore.csproj" />
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src2_6\ShardingCore.2_6\ShardingCore.2_6.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\ShardingCore\ShardingCore.csproj" />
|
||||
<ProjectReference Include="..\..\src2_6\ShardingCore.2_6\ShardingCore.2_6.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\ShardingCore\ShardingCore.csproj" />
|
||||
<ProjectReference Include="..\..\src2_6\ShardingCore.2_6\ShardingCore.2_6.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\ShardingCore\ShardingCore.csproj" />
|
||||
<ProjectReference Include="..\..\src2_6\ShardingCore.2_6\ShardingCore.2_6.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\test\ShardingCore.Test\ShardingCore.Test.csproj" />
|
||||
<ProjectReference Include="..\..\src2_6\ShardingCore.2_6\ShardingCore.2_6.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -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<MigrationOperation> 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)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\ShardingCore\ShardingCore.csproj" />
|
||||
<ProjectReference Include="..\..\src2_6\ShardingCore.2_6\ShardingCore.2_6.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#if NETCOREAPP2_0
|
||||
#if NETCOREAPP2_0&&SHARDINGCORE2_6
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using ShardingCore.Core.RuntimeContexts;
|
||||
|
||||
|
|
|
@ -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<EntityEntry> 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<EntityEntry<TEntity>> Entries<TEntity>()
|
||||
{
|
||||
if (_dbContext is IShardingDbContext shardingDbContext)
|
||||
{
|
||||
return shardingDbContext.GetShardingExecutor().GetCurrentDbContexts().SelectMany(o =>
|
||||
o.Value.GetCurrentContexts().SelectMany(cd => cd.Value.ChangeTracker.Entries<TEntity>()));
|
||||
}
|
||||
|
||||
return base.Entries<TEntity>();
|
||||
}
|
||||
|
||||
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<ChangeTracker> 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<EntityEntryGraphNode> 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<TState>(object rootEntity, TState state, Func<EntityEntryGraphNode, TState, bool> callback)
|
||||
{
|
||||
if (_dbContext is IShardingDbContext shardingDbContext)
|
||||
{
|
||||
var genericDbContext = shardingDbContext.CreateGenericDbContext(rootEntity);
|
||||
genericDbContext.ChangeTracker.TrackGraph(rootEntity,state,callback);
|
||||
// Do(c => c.TrackGraph(rootEntity,callback));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -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
|
||||
*/
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
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<Type, Func<DbContext, object>> _cache
|
||||
= new ConcurrentDictionary<Type, Func<DbContext, object>>();
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public virtual object Create(DbContext context, Type type)
|
||||
=> CreateCore(context, type, _genericCreateSet);
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
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<DbContext, object>)createMethod
|
||||
.MakeGenericMethod(t)
|
||||
.Invoke(null, null))(context);
|
||||
|
||||
private static Func<DbContext, object> CreateSetFactory<TEntity>()
|
||||
where TEntity : class
|
||||
=> c => new ShardingInternalDbSet<TEntity>(c);
|
||||
|
||||
private static Func<DbContext, DbQuery<TQuery>> CreateQueryFactory<TQuery>()
|
||||
where TQuery : class
|
||||
=> c => new ShardingInternalDbQuery<TQuery>(c);
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -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<TQuery> : InternalDbQuery<TQuery> where TQuery : class
|
||||
{
|
||||
|
@ -21,5 +22,6 @@ namespace ShardingCore.EFCores
|
|||
{
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
#endif
|
|
@ -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<TEntity> : InternalDbSet<TEntity>
|
||||
where TEntity : class
|
||||
{
|
||||
private readonly IShardingDbContext _context;
|
||||
private readonly IShardingRuntimeContext _shardingRuntimeContext;
|
||||
private LocalView<TEntity>? _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<TEntity> Local
|
||||
{
|
||||
get
|
||||
{
|
||||
|
||||
if (((DbContext)_context).ChangeTracker.AutoDetectChangesEnabled)
|
||||
{
|
||||
((DbContext)_context).ChangeTracker.DetectChanges();
|
||||
}
|
||||
|
||||
return _localView ??= new ShardingLocalView<TEntity>(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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public override EntityEntry<TEntity> Add(TEntity entity)
|
||||
{
|
||||
var genericDbContext = _context.CreateGenericDbContext(entity);
|
||||
return genericDbContext.Set<TEntity>().Add(entity);
|
||||
}
|
||||
|
||||
public override async Task<EntityEntry<TEntity>> AddAsync(TEntity entity, CancellationToken cancellationToken =
|
||||
new CancellationToken())
|
||||
{
|
||||
var genericDbContext = _context.CreateGenericDbContext(entity);
|
||||
return await genericDbContext.Set<TEntity>().AddAsync(entity, cancellationToken);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public override EntityEntry<TEntity> Attach(TEntity entity)
|
||||
{
|
||||
var genericDbContext = _context.CreateGenericDbContext(entity);
|
||||
return genericDbContext.Set<TEntity>().Attach(entity);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public override EntityEntry<TEntity> Remove(TEntity entity)
|
||||
{
|
||||
Check.NotNull(entity, nameof(entity));
|
||||
|
||||
var genericDbContext = _context.CreateGenericDbContext(entity);
|
||||
return genericDbContext.Set<TEntity>().Remove(entity);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public override EntityEntry<TEntity> Update(TEntity entity)
|
||||
{
|
||||
var genericDbContext = _context.CreateGenericDbContext(entity);
|
||||
return genericDbContext.Set<TEntity>().Update(entity);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public override void AddRange(params TEntity[] entities)
|
||||
{
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.Set<TEntity>().AddRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public override async Task AddRangeAsync(params TEntity[] entities)
|
||||
{
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
await aggregateKv.Key.Set<TEntity>().AddRangeAsync(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public override void AttachRange(params TEntity[] entities)
|
||||
{
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.Set<TEntity>().AttachRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public override void RemoveRange(params TEntity[] entities)
|
||||
{
|
||||
Check.NotNull(entities, nameof(entities));
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.Set<TEntity>().RemoveRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public override void UpdateRange(params TEntity[] entities)
|
||||
{
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.Set<TEntity>().UpdateRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public override void AddRange(IEnumerable<TEntity> entities)
|
||||
{
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.Set<TEntity>().AddRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public override async Task AddRangeAsync(
|
||||
IEnumerable<TEntity> entities,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
await aggregateKv.Key.Set<TEntity>().AddRangeAsync(aggregateKv.Value, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public override void AttachRange(IEnumerable<TEntity> entities)
|
||||
{
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.Set<TEntity>().AttachRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public override void RemoveRange(IEnumerable<TEntity> entities)
|
||||
{
|
||||
Check.NotNull(entities, nameof(entities));
|
||||
|
||||
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.Set<TEntity>().RemoveRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public override void UpdateRange(IEnumerable<TEntity> entities)
|
||||
{
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.Set<TEntity>().UpdateRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
private Dictionary<DbContext, IEnumerable<TEntity>> AggregateToDic(IEnumerable<TEntity> 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<TEntity>().Find(keyValues);
|
||||
}
|
||||
|
||||
return base.Find(keyValues);
|
||||
}
|
||||
|
||||
public override Task<TEntity> FindAsync(params object[] keyValues)
|
||||
{
|
||||
var primaryKeyFindDbContext = GetDbContextByKeyValue(keyValues);
|
||||
if (primaryKeyFindDbContext != null)
|
||||
{
|
||||
return primaryKeyFindDbContext.Set<TEntity>().FindAsync(keyValues);
|
||||
}
|
||||
return base.FindAsync(keyValues);
|
||||
}
|
||||
|
||||
public override Task<TEntity> FindAsync(object[] keyValues, CancellationToken cancellationToken)
|
||||
{
|
||||
var primaryKeyFindDbContext = GetDbContextByKeyValue(keyValues);
|
||||
if (primaryKeyFindDbContext != null)
|
||||
{
|
||||
return primaryKeyFindDbContext.Set<TEntity>().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<TEntity>(dataSourceName, primaryKeyValue,realEntityType);
|
||||
var routeTail = _shardingRuntimeContext.GetRouteTailFactory().Create(tableTail);
|
||||
return _context.GetShareDbContext(dataSourceName, routeTail);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private string GetDataSourceName(object shardingKeyValue)
|
||||
{
|
||||
return DataSourceRouteManager.GetDataSourceName<TEntity>(shardingKeyValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -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<DbLoggerCategory.Migrations> 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
|
|
@ -1,4 +1,4 @@
|
|||
#if NETCOREAPP2_0
|
||||
#if NETCOREAPP2_0&&SHARDINGCORE2_6
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
|
|
|
@ -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<IShardingRuntimeContext>(sp => ShardingRuntimeContext);
|
||||
return true;
|
||||
}
|
||||
public long GetServiceProviderHashCode() => ShardingRuntimeContext.GetHashCode();
|
||||
|
||||
public void Validate(IDbContextOptions options)
|
||||
{
|
||||
}
|
||||
|
||||
public string LogFragment => "ShardingOptionsExtension";
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -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
|
|
@ -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<DbLoggerCategory.Database.Transaction> 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
|
|
@ -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<TShardingDbContext> : 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<DbLoggerCategory.Database.Transaction> 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
|
|
@ -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
|
||||
*/
|
||||
/// <summary>
|
||||
/// manage transaction
|
||||
/// </summary>
|
||||
public class ShardingRelationalTransactionManager<TShardingDbContext> : 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<IDbContextTransaction> 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<IDbContextTransaction> 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
|
|
@ -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
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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<EntityEntry> 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<EntityEntry<TEntity>> Entries<TEntity>()
|
||||
{
|
||||
if (_dbContext is IShardingDbContext shardingDbContext)
|
||||
{
|
||||
return shardingDbContext.GetShardingExecutor().GetCurrentDbContexts().SelectMany(o =>
|
||||
o.Value.GetCurrentContexts().SelectMany(cd => cd.Value.ChangeTracker.Entries<TEntity>()));
|
||||
}
|
||||
|
||||
return base.Entries<TEntity>();
|
||||
}
|
||||
|
||||
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<ChangeTracker> 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<EntityEntryGraphNode> 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<TState>(object rootEntity, TState state, Func<EntityEntryGraphNode<TState>, 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
|
|
@ -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<Type, Func<DbContext, object>> _cache
|
||||
= new ConcurrentDictionary<Type, Func<DbContext, object>>();
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
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<DbContext, object>)createMethod
|
||||
.MakeGenericMethod(t)
|
||||
.Invoke(null, null))(context);
|
||||
|
||||
private static Func<DbContext, object> CreateSetFactory<TEntity>()
|
||||
where TEntity : class
|
||||
=> c => new ShardingInternalDbSet<TEntity>(c);
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
|
@ -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<TEntity> : InternalDbSet<TEntity>
|
||||
where TEntity : class
|
||||
{
|
||||
private readonly IShardingDbContext _context;
|
||||
private readonly IShardingRuntimeContext _shardingRuntimeContext;
|
||||
private LocalView<TEntity>? _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<TEntity> Local
|
||||
{
|
||||
get
|
||||
{
|
||||
|
||||
if (((DbContext)_context).ChangeTracker.AutoDetectChangesEnabled)
|
||||
{
|
||||
((DbContext)_context).ChangeTracker.DetectChanges();
|
||||
}
|
||||
|
||||
return _localView ??= new ShardingLocalView<TEntity>(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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public override EntityEntry<TEntity> Add(TEntity entity)
|
||||
{
|
||||
var genericDbContext = _context.CreateGenericDbContext(entity);
|
||||
return genericDbContext.Set<TEntity>().Add(entity);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public override async ValueTask<EntityEntry<TEntity>> AddAsync(
|
||||
TEntity entity,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var genericDbContext = _context.CreateGenericDbContext(entity);
|
||||
return await genericDbContext.Set<TEntity>().AddAsync(entity, cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public override EntityEntry<TEntity> Attach(TEntity entity)
|
||||
{
|
||||
var genericDbContext = _context.CreateGenericDbContext(entity);
|
||||
return genericDbContext.Set<TEntity>().Attach(entity);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public override EntityEntry<TEntity> Remove(TEntity entity)
|
||||
{
|
||||
Check.NotNull(entity, nameof(entity));
|
||||
|
||||
var genericDbContext = _context.CreateGenericDbContext(entity);
|
||||
return genericDbContext.Set<TEntity>().Remove(entity);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public override EntityEntry<TEntity> Update(TEntity entity)
|
||||
{
|
||||
var genericDbContext = _context.CreateGenericDbContext(entity);
|
||||
return genericDbContext.Set<TEntity>().Update(entity);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public override void AddRange(params TEntity[] entities)
|
||||
{
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.Set<TEntity>().AddRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public override async Task AddRangeAsync(params TEntity[] entities)
|
||||
{
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
await aggregateKv.Key.Set<TEntity>().AddRangeAsync(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public override void AttachRange(params TEntity[] entities)
|
||||
{
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.Set<TEntity>().AttachRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public override void RemoveRange(params TEntity[] entities)
|
||||
{
|
||||
Check.NotNull(entities, nameof(entities));
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.Set<TEntity>().RemoveRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public override void UpdateRange(params TEntity[] entities)
|
||||
{
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.Set<TEntity>().UpdateRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public override void AddRange(IEnumerable<TEntity> entities)
|
||||
{
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.Set<TEntity>().AddRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public override async Task AddRangeAsync(
|
||||
IEnumerable<TEntity> entities,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
await aggregateKv.Key.Set<TEntity>().AddRangeAsync(aggregateKv.Value, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public override void AttachRange(IEnumerable<TEntity> entities)
|
||||
{
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.Set<TEntity>().AttachRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public override void RemoveRange(IEnumerable<TEntity> entities)
|
||||
{
|
||||
Check.NotNull(entities, nameof(entities));
|
||||
|
||||
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.Set<TEntity>().RemoveRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public override void UpdateRange(IEnumerable<TEntity> entities)
|
||||
{
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.Set<TEntity>().UpdateRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
private Dictionary<DbContext, IEnumerable<TEntity>> AggregateToDic(IEnumerable<TEntity> 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<TEntity>().Find(keyValues);
|
||||
}
|
||||
|
||||
return base.Find(keyValues);
|
||||
}
|
||||
|
||||
public override ValueTask<TEntity> FindAsync(params object[] keyValues)
|
||||
{
|
||||
var primaryKeyFindDbContext = GetDbContextByKeyValue(keyValues);
|
||||
if (primaryKeyFindDbContext != null)
|
||||
{
|
||||
return primaryKeyFindDbContext.Set<TEntity>().FindAsync(keyValues);
|
||||
}
|
||||
|
||||
return base.FindAsync(keyValues);
|
||||
}
|
||||
|
||||
public override ValueTask<TEntity> FindAsync(object[] keyValues, CancellationToken cancellationToken)
|
||||
{
|
||||
var primaryKeyFindDbContext = GetDbContextByKeyValue(keyValues);
|
||||
if (primaryKeyFindDbContext != null)
|
||||
{
|
||||
return primaryKeyFindDbContext.Set<TEntity>().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<TEntity>(dataSourceName, primaryKeyValue,realEntityType);
|
||||
var routeTail = _shardingRuntimeContext.GetRouteTailFactory().Create(tableTail);
|
||||
return _context.GetShareDbContext(dataSourceName, routeTail);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private string GetDataSourceName(object shardingKeyValue)
|
||||
{
|
||||
return DataSourceRouteManager.GetDataSourceName<TEntity>(shardingKeyValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -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<DbLoggerCategory.Migrations> logger, IDiagnosticsLogger<DbLoggerCategory.Database.Command> 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
|
|
@ -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;
|
||||
|
|
|
@ -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<IShardingRuntimeContext>(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<string, string> debugInfo) { }
|
||||
|
||||
public override bool IsDatabaseProvider => false;
|
||||
public override string LogFragment => "ShardingOptionsExtension";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -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<string, string> debugInfo) { }
|
||||
|
||||
public override bool IsDatabaseProvider => false;
|
||||
public override string LogFragment => "ShardingWrapOptionsExtension";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
|
@ -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<DbLoggerCategory.Database.Transaction> 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
|
|
@ -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<TShardingDbContext> : 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<DbLoggerCategory.Database.Transaction> logger, bool transactionOwned)
|
||||
{
|
||||
var shardingDbContext = connection.Context as IShardingDbContext;
|
||||
return new ShardingRelationalTransaction(shardingDbContext, connection, transaction, transactionId, logger, transactionOwned);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
|
@ -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
|
||||
*/
|
||||
/// <summary>
|
||||
/// manage transaction
|
||||
/// </summary>
|
||||
public class ShardingRelationalTransactionManager<TShardingDbContext> : 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<IDbContextTransaction> 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<IDbContextTransaction> 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<IDbContextTransaction> UseTransactionAsync(DbTransaction transaction, CancellationToken cancellationToken = new CancellationToken())
|
||||
{
|
||||
var dbContextTransaction = await _relationalConnection.UseTransactionAsync(transaction, cancellationToken);
|
||||
_shardingDbContextExecutor.NotifyShardingTransaction();
|
||||
return dbContextTransaction;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -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<string, string> debugInfo) { }
|
||||
|
||||
public override bool IsDatabaseProvider => false;
|
||||
public override string LogFragment => "UnionAllMergeOptionsExtension";
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -1,4 +1,4 @@
|
|||
#if NET5_0 || NETSTANDARD2_1
|
||||
#if (NET5_0 || NETSTANDARD2_1)&&SHARDINGCORE2_6
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using ShardingCore.Core.RuntimeContexts;
|
||||
|
||||
|
|
|
@ -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<TState>(object rootEntity, TState state, Func<EntityEntryGraphNode<TState>, 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<TState>(object rootEntity, TState state, Func<EntityEntryGraphNode, TState, bool> callback)
|
||||
{
|
||||
if (_dbContext is IShardingDbContext shardingDbContext)
|
||||
{
|
||||
var genericDbContext = shardingDbContext.CreateGenericDbContext(rootEntity);
|
||||
genericDbContext.ChangeTracker.TrackGraph(rootEntity,state,callback);
|
||||
// Do(c => c.TrackGraph(rootEntity,callback));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -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<DbContext, string, object>> _cache
|
||||
= new ConcurrentDictionary<(Type Type, string Name), Func<DbContext, string, object>>();
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public virtual object Create(DbContext context, Type type)
|
||||
=> CreateCore(context, type, null, _genericCreateSet);
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
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<DbContext, string, object>)createMethod
|
||||
.MakeGenericMethod(t.Type)
|
||||
.Invoke(null, null))(context, name);
|
||||
|
||||
private static Func<DbContext, string, object> CreateSetFactory<TEntity>()
|
||||
where TEntity : class
|
||||
=> (c, name) => new ShardingInternalDbSet<TEntity>(c, name);
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
|
@ -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<TEntity> : InternalDbSet<TEntity>
|
||||
where TEntity : class
|
||||
{
|
||||
private readonly IShardingDbContext _context;
|
||||
private readonly IShardingRuntimeContext _shardingRuntimeContext;
|
||||
private LocalView<TEntity>? _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<TEntity> Local
|
||||
{
|
||||
get
|
||||
{
|
||||
|
||||
if (((DbContext)_context).ChangeTracker.AutoDetectChangesEnabled)
|
||||
{
|
||||
((DbContext)_context).ChangeTracker.DetectChanges();
|
||||
}
|
||||
|
||||
return _localView ??= new ShardingLocalView<TEntity>(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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public override EntityEntry<TEntity> Add(TEntity entity)
|
||||
{
|
||||
var genericDbContext = _context.CreateGenericDbContext(entity);
|
||||
return genericDbContext.Set<TEntity>().Add(entity);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public override async ValueTask<EntityEntry<TEntity>> AddAsync(
|
||||
TEntity entity,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var genericDbContext = _context.CreateGenericDbContext(entity);
|
||||
return await genericDbContext.Set<TEntity>().AddAsync(entity, cancellationToken);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public override EntityEntry<TEntity> Attach(TEntity entity)
|
||||
{
|
||||
var genericDbContext = _context.CreateGenericDbContext(entity);
|
||||
return genericDbContext.Set<TEntity>().Attach(entity);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public override EntityEntry<TEntity> Remove(TEntity entity)
|
||||
{
|
||||
Check.NotNull(entity, nameof(entity));
|
||||
|
||||
var genericDbContext = _context.CreateGenericDbContext(entity);
|
||||
return genericDbContext.Set<TEntity>().Remove(entity);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public override EntityEntry<TEntity> Update(TEntity entity)
|
||||
{
|
||||
var genericDbContext = _context.CreateGenericDbContext(entity);
|
||||
return genericDbContext.Set<TEntity>().Update(entity);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public override void AddRange(params TEntity[] entities)
|
||||
{
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.Set<TEntity>().AddRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public override async Task AddRangeAsync(params TEntity[] entities)
|
||||
{
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
await aggregateKv.Key.Set<TEntity>().AddRangeAsync(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public override void AttachRange(params TEntity[] entities)
|
||||
{
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.Set<TEntity>().AttachRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public override void RemoveRange(params TEntity[] entities)
|
||||
{
|
||||
Check.NotNull(entities, nameof(entities));
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.Set<TEntity>().RemoveRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public override void UpdateRange(params TEntity[] entities)
|
||||
{
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.Set<TEntity>().UpdateRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public override void AddRange(IEnumerable<TEntity> entities)
|
||||
{
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.Set<TEntity>().AddRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public override async Task AddRangeAsync(
|
||||
IEnumerable<TEntity> entities,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
await aggregateKv.Key.Set<TEntity>().AddRangeAsync(aggregateKv.Value, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public override void AttachRange(IEnumerable<TEntity> entities)
|
||||
{
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.Set<TEntity>().AttachRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public override void RemoveRange(IEnumerable<TEntity> entities)
|
||||
{
|
||||
Check.NotNull(entities, nameof(entities));
|
||||
|
||||
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.Set<TEntity>().RemoveRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public override void UpdateRange(IEnumerable<TEntity> entities)
|
||||
{
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.Set<TEntity>().UpdateRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
private Dictionary<DbContext, IEnumerable<TEntity>> AggregateToDic(IEnumerable<TEntity> 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<TEntity>().Find(keyValues);
|
||||
}
|
||||
|
||||
return base.Find(keyValues);
|
||||
}
|
||||
|
||||
public override ValueTask<TEntity> FindAsync(params object[] keyValues)
|
||||
{
|
||||
var primaryKeyFindDbContext = GetDbContextByKeyValue(keyValues);
|
||||
if (primaryKeyFindDbContext != null)
|
||||
{
|
||||
return primaryKeyFindDbContext.Set<TEntity>().FindAsync(keyValues);
|
||||
}
|
||||
|
||||
return base.FindAsync(keyValues);
|
||||
}
|
||||
|
||||
public override ValueTask<TEntity> FindAsync(object[] keyValues, CancellationToken cancellationToken)
|
||||
{
|
||||
var primaryKeyFindDbContext = GetDbContextByKeyValue(keyValues);
|
||||
if (primaryKeyFindDbContext != null)
|
||||
{
|
||||
return primaryKeyFindDbContext.Set<TEntity>().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<TEntity>(dataSourceName, primaryKeyValue,realEntityType);
|
||||
var routeTail = _shardingRuntimeContext.GetRouteTailFactory().Create(tableTail);
|
||||
return _context.GetShareDbContext(dataSourceName, routeTail);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private string GetDataSourceName(object shardingKeyValue)
|
||||
{
|
||||
return DataSourceRouteManager.GetDataSourceName<TEntity>(shardingKeyValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -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<DbLoggerCategory.Migrations> logger, IDiagnosticsLogger<DbLoggerCategory.Database.Command> 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
|
|
@ -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;
|
||||
|
|
|
@ -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<IShardingRuntimeContext>(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<string, string> debugInfo) { }
|
||||
|
||||
public override bool IsDatabaseProvider => false;
|
||||
public override string LogFragment => "ShardingOptionsExtension";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -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<string, string> debugInfo) { }
|
||||
|
||||
public override bool IsDatabaseProvider => false;
|
||||
public override string LogFragment => "ShardingWrapOptionsExtension";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -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<DbLoggerCategory.Database.Transaction> 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<DbLoggerCategory.Database.Transaction> 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<DbLoggerCategory.Database.Transaction> 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
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -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<TShardingDbContext> : 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<DbLoggerCategory.Database.Transaction> logger, bool transactionOwned)
|
||||
{
|
||||
var shardingDbContext = connection.Context as IShardingDbContext;
|
||||
return new ShardingRelationalTransaction(shardingDbContext, connection, transaction, transactionId, logger, transactionOwned);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -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
|
||||
*/
|
||||
/// <summary>
|
||||
/// manage transaction
|
||||
/// </summary>
|
||||
public class ShardingRelationalTransactionManager<TShardingDbContext> : 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<IDbContextTransaction> 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<IDbContextTransaction> 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<IDbContextTransaction> 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<IDbContextTransaction> UseTransactionAsync(DbTransaction transaction, Guid transactionId,
|
||||
CancellationToken cancellationToken = new CancellationToken())
|
||||
{
|
||||
var dbContextTransaction = await _relationalConnection.UseTransactionAsync(transaction, transactionId, cancellationToken);
|
||||
_shardingDbContextExecutor.NotifyShardingTransaction();
|
||||
return dbContextTransaction;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -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<string, string> debugInfo) { }
|
||||
|
||||
public override bool IsDatabaseProvider => false;
|
||||
public override string LogFragment => "UnionAllMergeOptionsExtension";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,4 +1,4 @@
|
|||
#if NET6_0
|
||||
#if NET6_0&&SHARDINGCORE2_6
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using ShardingCore.Core.RuntimeContexts;
|
||||
|
||||
|
|
|
@ -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<EntityEntry> 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<EntityEntry<TEntity>> Entries<TEntity>()
|
||||
{
|
||||
if (_dbContext is IShardingDbContext shardingDbContext)
|
||||
{
|
||||
return shardingDbContext.GetShardingExecutor().GetCurrentDbContexts().SelectMany(o =>
|
||||
o.Value.GetCurrentContexts().SelectMany(cd => cd.Value.ChangeTracker.Entries<TEntity>()));
|
||||
}
|
||||
|
||||
return base.Entries<TEntity>();
|
||||
}
|
||||
|
||||
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<ChangeTracker> 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<EntityEntryGraphNode> 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<TState>(object rootEntity, TState state, Func<EntityEntryGraphNode<TState>, 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
|
|
@ -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<DbContext, string, object>> _cache
|
||||
= new ConcurrentDictionary<(Type Type, string Name), Func<DbContext, string, object>>();
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public virtual object Create(DbContext context, Type type)
|
||||
=> CreateCore(context, type, null, _genericCreateSet);
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
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<DbContext, string, object>)createMethod
|
||||
.MakeGenericMethod(t.Type)
|
||||
.Invoke(null, null))(context, name);
|
||||
|
||||
private static Func<DbContext, string, object> CreateSetFactory<TEntity>()
|
||||
where TEntity : class
|
||||
=> (c, name) => new ShardingInternalDbSet<TEntity>(c, name);
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
|
@ -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<TEntity> : InternalDbSet<TEntity>
|
||||
where TEntity : class
|
||||
{
|
||||
private readonly IShardingDbContext _context;
|
||||
private readonly IShardingRuntimeContext _shardingRuntimeContext;
|
||||
private LocalView<TEntity>? _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<TEntity> Local
|
||||
{
|
||||
get
|
||||
{
|
||||
|
||||
if (((DbContext)_context).ChangeTracker.AutoDetectChangesEnabled)
|
||||
{
|
||||
((DbContext)_context).ChangeTracker.DetectChanges();
|
||||
}
|
||||
|
||||
return _localView ??= new ShardingLocalView<TEntity>(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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public override EntityEntry<TEntity> Add(TEntity entity)
|
||||
{
|
||||
var genericDbContext = _context.CreateGenericDbContext(entity);
|
||||
return genericDbContext.Set<TEntity>().Add(entity);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public override async ValueTask<EntityEntry<TEntity>> AddAsync(
|
||||
TEntity entity,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var genericDbContext = _context.CreateGenericDbContext(entity);
|
||||
return await genericDbContext.Set<TEntity>().AddAsync(entity, cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public override EntityEntry<TEntity> Attach(TEntity entity)
|
||||
{
|
||||
var genericDbContext = _context.CreateGenericDbContext(entity);
|
||||
return genericDbContext.Set<TEntity>().Attach(entity);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public override EntityEntry<TEntity> Remove(TEntity entity)
|
||||
{
|
||||
Check.NotNull(entity, nameof(entity));
|
||||
|
||||
var genericDbContext = _context.CreateGenericDbContext(entity);
|
||||
return genericDbContext.Set<TEntity>().Remove(entity);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public override EntityEntry<TEntity> Update(TEntity entity)
|
||||
{
|
||||
var genericDbContext = _context.CreateGenericDbContext(entity);
|
||||
return genericDbContext.Set<TEntity>().Update(entity);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public override void AddRange(params TEntity[] entities)
|
||||
{
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.Set<TEntity>().AddRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public override async Task AddRangeAsync(params TEntity[] entities)
|
||||
{
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
await aggregateKv.Key.Set<TEntity>().AddRangeAsync(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public override void AttachRange(params TEntity[] entities)
|
||||
{
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.Set<TEntity>().AttachRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public override void RemoveRange(params TEntity[] entities)
|
||||
{
|
||||
Check.NotNull(entities, nameof(entities));
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.Set<TEntity>().RemoveRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public override void UpdateRange(params TEntity[] entities)
|
||||
{
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.Set<TEntity>().UpdateRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public override void AddRange(IEnumerable<TEntity> entities)
|
||||
{
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.Set<TEntity>().AddRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public override async Task AddRangeAsync(
|
||||
IEnumerable<TEntity> entities,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
await aggregateKv.Key.Set<TEntity>().AddRangeAsync(aggregateKv.Value, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public override void AttachRange(IEnumerable<TEntity> entities)
|
||||
{
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.Set<TEntity>().AttachRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public override void RemoveRange(IEnumerable<TEntity> entities)
|
||||
{
|
||||
Check.NotNull(entities, nameof(entities));
|
||||
|
||||
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.Set<TEntity>().RemoveRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public override void UpdateRange(IEnumerable<TEntity> entities)
|
||||
{
|
||||
var aggregateToDic = AggregateToDic(entities);
|
||||
foreach (var aggregateKv in aggregateToDic)
|
||||
{
|
||||
aggregateKv.Key.Set<TEntity>().UpdateRange(aggregateKv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
private Dictionary<DbContext, IEnumerable<TEntity>> AggregateToDic(IEnumerable<TEntity> 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<TEntity>().Find(keyValues);
|
||||
}
|
||||
|
||||
return base.Find(keyValues);
|
||||
}
|
||||
|
||||
public override ValueTask<TEntity> FindAsync(params object[] keyValues)
|
||||
{
|
||||
var primaryKeyFindDbContext = GetDbContextByKeyValue(keyValues);
|
||||
if (primaryKeyFindDbContext != null)
|
||||
{
|
||||
return primaryKeyFindDbContext.Set<TEntity>().FindAsync(keyValues);
|
||||
}
|
||||
|
||||
return base.FindAsync(keyValues);
|
||||
}
|
||||
|
||||
public override ValueTask<TEntity> FindAsync(object[] keyValues, CancellationToken cancellationToken)
|
||||
{
|
||||
var primaryKeyFindDbContext = GetDbContextByKeyValue(keyValues);
|
||||
if (primaryKeyFindDbContext != null)
|
||||
{
|
||||
return primaryKeyFindDbContext.Set<TEntity>().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<TEntity>(dataSourceName, primaryKeyValue,realEntityType);
|
||||
var routeTail = _shardingRuntimeContext.GetRouteTailFactory().Create(tableTail);
|
||||
return _context.GetShareDbContext(dataSourceName, routeTail);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private string GetDataSourceName(object shardingKeyValue)
|
||||
{
|
||||
return DataSourceRouteManager.GetDataSourceName<TEntity>(shardingKeyValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,49 @@
|
|||
|
||||
#if NET6_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, IModelRuntimeInitializer modelRuntimeInitializer, IDiagnosticsLogger<DbLoggerCategory.Migrations> logger, IRelationalCommandDiagnosticsLogger commandLogger, IDatabaseProvider databaseProvider) : base(migrationsAssembly, historyRepository, databaseCreator, migrationsSqlGenerator, rawSqlCommandBuilder, migrationCommandExecutor, connection, sqlGenerationHelper, currentContext, modelRuntimeInitializer, logger, commandLogger, databaseProvider)
|
||||
{
|
||||
_shardingRuntimeContext = shardingRuntimeContext;
|
||||
|
||||
}
|
||||
public override void Migrate(string targetMigration = null)
|
||||
{
|
||||
this.MigrateAsync(targetMigration).WaitAndUnwrapException(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
|
|
@ -1,5 +1,5 @@
|
|||
|
||||
#if NET6_0
|
||||
#if NET6_0&&SHARDINGCORE2_6
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
#if NET6_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<IShardingRuntimeContext>(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 int GetServiceProviderHashCode() =>
|
||||
_shardingOptionsExtension.ShardingRuntimeContext.GetHashCode();
|
||||
|
||||
public override bool ShouldUseSameServiceProvider(DbContextOptionsExtensionInfo other) => true;
|
||||
|
||||
public override void PopulateDebugInfo(IDictionary<string, string> debugInfo)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool IsDatabaseProvider => false;
|
||||
public override string LogFragment => "ShardingOptionsExtension";
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,56 @@
|
|||
#if NET6_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 ShardingWrapOptionsExtension()
|
||||
{
|
||||
}
|
||||
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 int GetServiceProviderHashCode() => 0;
|
||||
|
||||
public override bool ShouldUseSameServiceProvider(DbContextOptionsExtensionInfo other) => true;
|
||||
|
||||
public override void PopulateDebugInfo(IDictionary<string, string> debugInfo)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool IsDatabaseProvider => false;
|
||||
public override string LogFragment => "ShardingWrapOptionsExtension";
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,105 @@
|
|||
#if NET6_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<DbLoggerCategory.Database.Transaction> 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)}");
|
||||
|
||||
}
|
||||
|
||||
public override void Commit()
|
||||
{
|
||||
base.Commit();
|
||||
_shardingDbContextExecutor.Commit();
|
||||
_shardingDbContextExecutor.NotifyShardingTransaction();
|
||||
}
|
||||
|
||||
public override void Rollback()
|
||||
{
|
||||
base.Rollback();
|
||||
_shardingDbContextExecutor.Rollback();
|
||||
_shardingDbContextExecutor.NotifyShardingTransaction();
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
public override void CreateSavepoint(string name)
|
||||
{
|
||||
base.CreateSavepoint(name);
|
||||
_shardingDbContextExecutor.CreateSavepoint(name);
|
||||
}
|
||||
|
||||
public override async Task CreateSavepointAsync(string name, CancellationToken cancellationToken = new CancellationToken())
|
||||
{
|
||||
await base.CreateSavepointAsync(name, cancellationToken);
|
||||
await _shardingDbContextExecutor.CreateSavepointAsync(name,cancellationToken);
|
||||
}
|
||||
|
||||
public override void RollbackToSavepoint(string name)
|
||||
{
|
||||
base.RollbackToSavepoint(name);
|
||||
_shardingDbContextExecutor.RollbackToSavepoint(name);
|
||||
}
|
||||
|
||||
public override async Task RollbackToSavepointAsync(string name, CancellationToken cancellationToken = new CancellationToken())
|
||||
{
|
||||
await base.RollbackToSavepointAsync(name, cancellationToken);
|
||||
await _shardingDbContextExecutor.RollbackToSavepointAsync(name,cancellationToken);
|
||||
}
|
||||
|
||||
public override void ReleaseSavepoint(string name)
|
||||
{
|
||||
base.ReleaseSavepoint(name);
|
||||
_shardingDbContextExecutor.ReleaseSavepoint(name);
|
||||
}
|
||||
|
||||
public override async Task ReleaseSavepointAsync(string name, CancellationToken cancellationToken = new CancellationToken())
|
||||
{
|
||||
await base.ReleaseSavepointAsync(name, cancellationToken);
|
||||
await _shardingDbContextExecutor.ReleaseSavepointAsync(name,cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,39 @@
|
|||
#if NET6_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<TShardingDbContext> : 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<DbLoggerCategory.Database.Transaction> logger, bool transactionOwned)
|
||||
{
|
||||
var shardingDbContext = connection.Context as IShardingDbContext;
|
||||
return new ShardingRelationalTransaction(shardingDbContext, connection, transaction, transactionId, logger, transactionOwned, this.Dependencies.SqlGenerationHelper);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -1,4 +1,6 @@
|
|||
using System;
|
||||
#if NET6_0 && SHARDINGCORE2_6
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Data.Common;
|
||||
|
@ -28,31 +30,13 @@ namespace ShardingCore.EFCores
|
|||
private readonly IRelationalConnection _relationalConnection;
|
||||
private readonly IShardingDbContext _shardingDbContext;
|
||||
private readonly IShardingDbContextExecutor _shardingDbContextExecutor;
|
||||
#if !NETCOREAPP2_0
|
||||
public ShardingRelationalTransactionManager(IRelationalConnection relationalConnection)
|
||||
{
|
||||
_relationalConnection = relationalConnection;
|
||||
_shardingDbContext = relationalConnection.Context as IShardingDbContext??throw new ShardingCoreInvalidOperationException($"should implement {nameof(IShardingDbContext)}");
|
||||
_shardingDbContextExecutor = _shardingDbContext.GetShardingExecutor();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if NETCOREAPP2_0
|
||||
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;
|
||||
}
|
||||
|
||||
#endif
|
||||
public void ResetState()
|
||||
{
|
||||
_relationalConnection.ResetState();
|
||||
|
@ -102,7 +86,6 @@ namespace ShardingCore.EFCores
|
|||
_shardingDbContextExecutor.NotifyShardingTransaction();
|
||||
return dbContextTransaction;
|
||||
}
|
||||
#if !NETCOREAPP2_0
|
||||
|
||||
public Task ResetStateAsync(CancellationToken cancellationToken = new CancellationToken())
|
||||
{
|
||||
|
@ -115,7 +98,6 @@ namespace ShardingCore.EFCores
|
|||
_shardingDbContextExecutor.NotifyShardingTransaction();
|
||||
return dbContextTransaction;
|
||||
}
|
||||
#if !NETCOREAPP3_0 && !NETSTANDARD2_0
|
||||
|
||||
public Task CommitTransactionAsync(CancellationToken cancellationToken = new CancellationToken())
|
||||
{
|
||||
|
@ -138,8 +120,7 @@ namespace ShardingCore.EFCores
|
|||
_shardingDbContextExecutor.NotifyShardingTransaction();
|
||||
return dbContextTransaction;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,51 @@
|
|||
#if NET6_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 int GetServiceProviderHashCode() => 0;
|
||||
|
||||
public override bool ShouldUseSameServiceProvider(DbContextOptionsExtensionInfo other) => true;
|
||||
|
||||
public override void PopulateDebugInfo(IDictionary<string, string> debugInfo)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool IsDatabaseProvider => false;
|
||||
public override string LogFragment => "UnionAllMergeOptionsExtension";
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,28 @@
|
|||
#if SHARDINGCORE7
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using ShardingCore.Core.RuntimeContexts;
|
||||
|
||||
namespace ShardingCore.EFCores
|
||||
{
|
||||
public sealed class ScriptMigrationGenerator:AbstractScriptMigrationGenerator
|
||||
{
|
||||
private readonly string _fromMigration;
|
||||
private readonly string _toMigration;
|
||||
private readonly MigrationsSqlGenerationOptions _options;
|
||||
|
||||
public ScriptMigrationGenerator(IShardingRuntimeContext shardingRuntimeContext, string fromMigration = null,
|
||||
string toMigration = null,
|
||||
MigrationsSqlGenerationOptions options = MigrationsSqlGenerationOptions.Default) : base(shardingRuntimeContext)
|
||||
{
|
||||
_fromMigration = fromMigration;
|
||||
_toMigration = toMigration;
|
||||
_options = options;
|
||||
}
|
||||
|
||||
protected override string GenerateScriptSql(IMigrator migrator)
|
||||
{
|
||||
return migrator.GenerateScript(_fromMigration, _toMigration, _options);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,132 @@
|
|||
#if SHARDINGCORE7
|
||||
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<EntityEntry> 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<EntityEntry<TEntity>> Entries<TEntity>()
|
||||
{
|
||||
if (_dbContext is IShardingDbContext shardingDbContext)
|
||||
{
|
||||
return shardingDbContext.GetShardingExecutor().GetCurrentDbContexts().SelectMany(o =>
|
||||
o.Value.GetCurrentContexts().SelectMany(cd => cd.Value.ChangeTracker.Entries<TEntity>()));
|
||||
}
|
||||
|
||||
return base.Entries<TEntity>();
|
||||
}
|
||||
|
||||
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<ChangeTracker> 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<EntityEntryGraphNode> 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<TState>(object rootEntity, TState state, Func<EntityEntryGraphNode<TState>, 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
|
|
@ -0,0 +1,57 @@
|
|||
#if SHARDINGCORE7
|
||||
|
||||
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<DbContext, string, object>> _cache
|
||||
= new ConcurrentDictionary<(Type Type, string Name), Func<DbContext, string, object>>();
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public virtual object Create(DbContext context, Type type)
|
||||
=> CreateCore(context, type, null, _genericCreateSet);
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
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<DbContext, string, object>)createMethod
|
||||
.MakeGenericMethod(t.Type)
|
||||
.Invoke(null, null))(context, name);
|
||||
|
||||
private static Func<DbContext, string, object> CreateSetFactory<TEntity>()
|
||||
where TEntity : class
|
||||
=> (c, name) => new ShardingInternalDbSet<TEntity>(c, name);
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
|
@ -1,4 +1,5 @@
|
|||
using Microsoft.EntityFrameworkCore;
|
||||
#if SHARDINGCORE7
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.ChangeTracking;
|
||||
using Microsoft.EntityFrameworkCore.Internal;
|
||||
using ShardingCore.Core;
|
||||
|
@ -37,21 +38,11 @@ namespace ShardingCore.EFCores
|
|||
private readonly IShardingRuntimeContext _shardingRuntimeContext;
|
||||
private LocalView<TEntity>? _localView;
|
||||
|
||||
#if NET5_0 || NETSTANDARD2_1 || NET6_0
|
||||
|
||||
public ShardingInternalDbSet(DbContext context, string entityTypeName) : base(context, entityTypeName)
|
||||
{
|
||||
_context = (IShardingDbContext)context;
|
||||
_shardingRuntimeContext = context.GetShardingRuntimeContext();
|
||||
}
|
||||
#endif
|
||||
#if NETCOREAPP2_0 || NETCOREAPP3_0 || NETSTANDARD2_0
|
||||
public ShardingInternalDbSet(DbContext context) : base(context)
|
||||
{
|
||||
_context = (IShardingDbContext)context;
|
||||
_shardingRuntimeContext = context.GetShardingRuntimeContext();
|
||||
}
|
||||
#endif
|
||||
|
||||
private IDataSourceRouteManager _dataSourceRouteManager;
|
||||
|
||||
|
@ -144,7 +135,6 @@ namespace ShardingCore.EFCores
|
|||
/// any release. You should only use it directly in your code with extreme caution and knowing that
|
||||
/// doing so can result in application failures when updating to a new Entity Framework Core release.
|
||||
/// </summary>
|
||||
#if !NETCOREAPP2_0
|
||||
public override async ValueTask<EntityEntry<TEntity>> AddAsync(
|
||||
TEntity entity,
|
||||
CancellationToken cancellationToken = default)
|
||||
|
@ -152,16 +142,6 @@ namespace ShardingCore.EFCores
|
|||
var genericDbContext = _context.CreateGenericDbContext(entity);
|
||||
return await genericDbContext.Set<TEntity>().AddAsync(entity, cancellationToken);
|
||||
}
|
||||
#endif
|
||||
#if NETCOREAPP2_0
|
||||
public override async Task<EntityEntry<TEntity>> AddAsync(TEntity entity, CancellationToken cancellationToken =
|
||||
new CancellationToken())
|
||||
{
|
||||
var genericDbContext = _context.CreateGenericDbContext(entity);
|
||||
return await genericDbContext.Set<TEntity>().AddAsync(entity, cancellationToken);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
|
||||
|
@ -381,7 +361,6 @@ namespace ShardingCore.EFCores
|
|||
return base.Find(keyValues);
|
||||
}
|
||||
|
||||
#if !NETCOREAPP2_0
|
||||
public override ValueTask<TEntity> FindAsync(params object[] keyValues)
|
||||
{
|
||||
var primaryKeyFindDbContext = GetDbContextByKeyValue(keyValues);
|
||||
|
@ -403,28 +382,6 @@ namespace ShardingCore.EFCores
|
|||
|
||||
return base.FindAsync(keyValues, cancellationToken);
|
||||
}
|
||||
#endif
|
||||
#if NETCOREAPP2_0
|
||||
public override Task<TEntity> FindAsync(params object[] keyValues)
|
||||
{
|
||||
var primaryKeyFindDbContext = GetDbContextByKeyValue(keyValues);
|
||||
if (primaryKeyFindDbContext != null)
|
||||
{
|
||||
return primaryKeyFindDbContext.Set<TEntity>().FindAsync(keyValues);
|
||||
}
|
||||
return base.FindAsync(keyValues);
|
||||
}
|
||||
|
||||
public override Task<TEntity> FindAsync(object[] keyValues, CancellationToken cancellationToken)
|
||||
{
|
||||
var primaryKeyFindDbContext = GetDbContextByKeyValue(keyValues);
|
||||
if (primaryKeyFindDbContext != null)
|
||||
{
|
||||
return primaryKeyFindDbContext.Set<TEntity>().FindAsync(keyValues, cancellationToken);
|
||||
}
|
||||
return base.FindAsync(keyValues, cancellationToken);
|
||||
}
|
||||
#endif
|
||||
|
||||
private DbContext GetDbContextByKeyValue(params object[] keyValues)
|
||||
{
|
||||
|
@ -477,4 +434,6 @@ namespace ShardingCore.EFCores
|
|||
return DataSourceRouteManager.GetDataSourceName<TEntity>(shardingKeyValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,49 @@
|
|||
|
||||
#if SHARDINGCORE7
|
||||
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, IModelRuntimeInitializer modelRuntimeInitializer, IDiagnosticsLogger<DbLoggerCategory.Migrations> logger, IRelationalCommandDiagnosticsLogger commandLogger, IDatabaseProvider databaseProvider) : base(migrationsAssembly, historyRepository, databaseCreator, migrationsSqlGenerator, rawSqlCommandBuilder, migrationCommandExecutor, connection, sqlGenerationHelper, currentContext, modelRuntimeInitializer, logger, commandLogger, databaseProvider)
|
||||
{
|
||||
_shardingRuntimeContext = shardingRuntimeContext;
|
||||
|
||||
}
|
||||
public override void Migrate(string targetMigration = null)
|
||||
{
|
||||
this.MigrateAsync(targetMigration).WaitAndUnwrapException(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
|
|
@ -0,0 +1,134 @@
|
|||
|
||||
#if SHARDINGCORE7
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using ShardingCore.Core;
|
||||
using ShardingCore.Core.VirtualRoutes.TableRoutes.RouteTails.Abstractions;
|
||||
using ShardingCore.Exceptions;
|
||||
using ShardingCore.Sharding.Abstractions;
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace ShardingCore.EFCores
|
||||
{
|
||||
|
||||
public class ShardingModelSource : ModelSource, IShardingModelSource
|
||||
{
|
||||
private readonly object _syncObject = new();
|
||||
|
||||
public ShardingModelSource(ModelSourceDependencies dependencies) : base(dependencies)
|
||||
{
|
||||
Check.NotNull(dependencies, nameof(dependencies));
|
||||
Dependencies = dependencies;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dependencies for this service.
|
||||
/// </summary>
|
||||
protected override ModelSourceDependencies Dependencies { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets the model to be used.
|
||||
/// </summary>
|
||||
/// <param name="context">The context the model is being produced for.</param>
|
||||
/// <param name="modelCreationDependencies">The dependencies object used during the creation of the model.</param>
|
||||
/// <param name="designTime">Whether the model should contain design-time configuration.</param>
|
||||
/// <returns>The model to be used.</returns>
|
||||
public override IModel GetModel(
|
||||
DbContext context,
|
||||
ModelCreationDependencies modelCreationDependencies,
|
||||
bool designTime)
|
||||
{
|
||||
var priority = CacheItemPriority.High;
|
||||
var size = 200;
|
||||
var waitSeconds = 3;
|
||||
if (context is IShardingTableDbContext shardingTableDbContext)
|
||||
{
|
||||
if (shardingTableDbContext.RouteTail is null)
|
||||
{
|
||||
throw new ShardingCoreInvalidOperationException("db context model is inited before RouteTail set value");
|
||||
}
|
||||
if (shardingTableDbContext.RouteTail is INoCacheRouteTail)
|
||||
{
|
||||
var noCacheModel = this.CreateModel(context, modelCreationDependencies.ConventionSetBuilder, modelCreationDependencies.ModelDependencies);
|
||||
noCacheModel = modelCreationDependencies.ModelRuntimeInitializer.Initialize(noCacheModel, designTime, modelCreationDependencies.ValidationLogger);
|
||||
return noCacheModel;
|
||||
}
|
||||
else
|
||||
if (shardingTableDbContext.RouteTail is ISingleQueryRouteTail singleQueryRouteTail && singleQueryRouteTail.IsShardingTableQuery())
|
||||
{
|
||||
priority = CacheItemPriority.Normal;
|
||||
}
|
||||
}
|
||||
var cache = Dependencies.MemoryCache;
|
||||
var cacheKey = Dependencies.ModelCacheKeyFactory.Create(context, designTime);
|
||||
if (!cache.TryGetValue(cacheKey, out IModel model))
|
||||
{
|
||||
if (context is IShardingModelCacheOption shardingModelCacheOption)
|
||||
{
|
||||
priority = shardingModelCacheOption.GetModelCachePriority();
|
||||
size = shardingModelCacheOption.GetModelCacheEntrySize();
|
||||
waitSeconds = shardingModelCacheOption.GetModelCacheLockObjectSeconds();
|
||||
}
|
||||
// Make sure OnModelCreating really only gets called once, since it may not be thread safe.
|
||||
var acquire = Monitor.TryEnter(_syncObject, TimeSpan.FromSeconds(waitSeconds));
|
||||
if (!acquire)
|
||||
{
|
||||
throw new ShardingCoreInvalidOperationException("cache model timeout");
|
||||
}
|
||||
try
|
||||
{
|
||||
if (!cache.TryGetValue(cacheKey, out model))
|
||||
{
|
||||
model = CreateModel(
|
||||
context, modelCreationDependencies.ConventionSetBuilder, modelCreationDependencies.ModelDependencies);
|
||||
|
||||
model = modelCreationDependencies.ModelRuntimeInitializer.Initialize(
|
||||
model, designTime, modelCreationDependencies.ValidationLogger);
|
||||
|
||||
model = cache.Set(cacheKey, model, new MemoryCacheEntryOptions { Size = size, Priority = priority });
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
Monitor.Exit(_syncObject);
|
||||
}
|
||||
}
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
public IModelCacheKeyFactory GetModelCacheKeyFactory()
|
||||
{
|
||||
return Dependencies.ModelCacheKeyFactory;
|
||||
}
|
||||
|
||||
public object GetSyncObject()
|
||||
{
|
||||
return _syncObject;
|
||||
}
|
||||
|
||||
public void Remove(object key)
|
||||
{
|
||||
var acquire = Monitor.TryEnter(_syncObject, TimeSpan.FromSeconds(3));
|
||||
if (!acquire)
|
||||
{
|
||||
throw new ShardingCoreInvalidOperationException("cache model timeout");
|
||||
}
|
||||
try
|
||||
{
|
||||
|
||||
var cache = Dependencies.MemoryCache;
|
||||
cache.Remove(key);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Monitor.Exit(_syncObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,63 @@
|
|||
#if SHARDINGCORE7
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
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<IShardingRuntimeContext>(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 int GetServiceProviderHashCode() =>
|
||||
_shardingOptionsExtension.ShardingRuntimeContext.GetHashCode();
|
||||
|
||||
public override bool ShouldUseSameServiceProvider(DbContextOptionsExtensionInfo other) => true;
|
||||
|
||||
public override void PopulateDebugInfo(IDictionary<string, string> debugInfo)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool IsDatabaseProvider => false;
|
||||
public override string LogFragment => "ShardingOptionsExtension";
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,56 @@
|
|||
#if SHARDINGCORE7
|
||||
|
||||
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 ShardingWrapOptionsExtension()
|
||||
{
|
||||
}
|
||||
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 int GetServiceProviderHashCode() => 0;
|
||||
|
||||
public override bool ShouldUseSameServiceProvider(DbContextOptionsExtensionInfo other) => true;
|
||||
|
||||
public override void PopulateDebugInfo(IDictionary<string, string> debugInfo)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool IsDatabaseProvider => false;
|
||||
public override string LogFragment => "ShardingWrapOptionsExtension";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,103 @@
|
|||
#if SHARDINGCORE7
|
||||
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<DbLoggerCategory.Database.Transaction> 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)}");
|
||||
|
||||
}
|
||||
public override void Commit()
|
||||
{
|
||||
base.Commit();
|
||||
_shardingDbContextExecutor.Commit();
|
||||
_shardingDbContextExecutor.NotifyShardingTransaction();
|
||||
}
|
||||
|
||||
public override void Rollback()
|
||||
{
|
||||
base.Rollback();
|
||||
_shardingDbContextExecutor.Rollback();
|
||||
_shardingDbContextExecutor.NotifyShardingTransaction();
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
public override void CreateSavepoint(string name)
|
||||
{
|
||||
base.CreateSavepoint(name);
|
||||
_shardingDbContextExecutor.CreateSavepoint(name);
|
||||
}
|
||||
|
||||
public override async Task CreateSavepointAsync(string name, CancellationToken cancellationToken = new CancellationToken())
|
||||
{
|
||||
await base.CreateSavepointAsync(name, cancellationToken);
|
||||
await _shardingDbContextExecutor.CreateSavepointAsync(name,cancellationToken);
|
||||
}
|
||||
|
||||
public override void RollbackToSavepoint(string name)
|
||||
{
|
||||
base.RollbackToSavepoint(name);
|
||||
_shardingDbContextExecutor.RollbackToSavepoint(name);
|
||||
}
|
||||
|
||||
public override async Task RollbackToSavepointAsync(string name, CancellationToken cancellationToken = new CancellationToken())
|
||||
{
|
||||
await base.RollbackToSavepointAsync(name, cancellationToken);
|
||||
await _shardingDbContextExecutor.RollbackToSavepointAsync(name,cancellationToken);
|
||||
}
|
||||
|
||||
public override void ReleaseSavepoint(string name)
|
||||
{
|
||||
base.ReleaseSavepoint(name);
|
||||
_shardingDbContextExecutor.ReleaseSavepoint(name);
|
||||
}
|
||||
|
||||
public override async Task ReleaseSavepointAsync(string name, CancellationToken cancellationToken = new CancellationToken())
|
||||
{
|
||||
await base.ReleaseSavepointAsync(name, cancellationToken);
|
||||
await _shardingDbContextExecutor.ReleaseSavepointAsync(name,cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,39 @@
|
|||
#if SHARDINGCORE7
|
||||
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<TShardingDbContext> : 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<DbLoggerCategory.Database.Transaction> logger, bool transactionOwned)
|
||||
{
|
||||
var shardingDbContext = connection.Context as IShardingDbContext;
|
||||
return new ShardingRelationalTransaction(shardingDbContext, connection, transaction, transactionId, logger, transactionOwned, this.Dependencies.SqlGenerationHelper);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,125 @@
|
|||
#if SHARDINGCORE7
|
||||
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
|
||||
*/
|
||||
/// <summary>
|
||||
/// manage transaction
|
||||
/// </summary>
|
||||
public class ShardingRelationalTransactionManager<TShardingDbContext> : 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<IDbContextTransaction> 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<IDbContextTransaction> 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<IDbContextTransaction> 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<IDbContextTransaction> UseTransactionAsync(DbTransaction transaction, Guid transactionId,
|
||||
CancellationToken cancellationToken = new CancellationToken())
|
||||
{
|
||||
var dbContextTransaction = await _relationalConnection.UseTransactionAsync(transaction, transactionId, cancellationToken);
|
||||
_shardingDbContextExecutor.NotifyShardingTransaction();
|
||||
return dbContextTransaction;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,51 @@
|
|||
#if SHARDINGCORE7
|
||||
|
||||
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 int GetServiceProviderHashCode() => 0;
|
||||
|
||||
public override bool ShouldUseSameServiceProvider(DbContextOptionsExtensionInfo other) => true;
|
||||
|
||||
public override void PopulateDebugInfo(IDictionary<string, string> debugInfo)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool IsDatabaseProvider => false;
|
||||
public override string LogFragment => "UnionAllMergeOptionsExtension";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,129 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using ShardingCore.Core;
|
||||
using ShardingCore.Core.RuntimeContexts;
|
||||
|
||||
namespace ShardingCore.EFCores.OptionsExtensions
|
||||
{
|
||||
/*
|
||||
* @Author: xjm
|
||||
* @Description:
|
||||
* @Date: 2021/10/17 20:27:12
|
||||
* @Ver: 1.0
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
#if !NETCOREAPP2_0 && !NETSTANDARD2_0 && !NETCOREAPP3_0 && !NETSTANDARD2_1 && !NET5_0 && !NET6_0
|
||||
error
|
||||
#endif
|
||||
|
||||
#if NET6_0
|
||||
public class ShardingOptionsExtension : IDbContextOptionsExtension
|
||||
{
|
||||
public IShardingRuntimeContext ShardingRuntimeContext { get; }
|
||||
|
||||
public ShardingOptionsExtension(IShardingRuntimeContext shardingRuntimeContext)
|
||||
{
|
||||
ShardingRuntimeContext = shardingRuntimeContext;
|
||||
}
|
||||
|
||||
public void ApplyServices(IServiceCollection services)
|
||||
{
|
||||
services.AddSingleton<IShardingRuntimeContext>(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 int GetServiceProviderHashCode() =>
|
||||
_shardingOptionsExtension.ShardingRuntimeContext.GetHashCode();
|
||||
|
||||
public override bool ShouldUseSameServiceProvider(DbContextOptionsExtensionInfo other) => true;
|
||||
|
||||
public override void PopulateDebugInfo(IDictionary<string, string> debugInfo)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool IsDatabaseProvider => false;
|
||||
public override string LogFragment => "ShardingOptionsExtension";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if NETCOREAPP3_0 || NETSTANDARD2_0 || NET5_0 || NETSTANDARD2_1
|
||||
public class ShardingOptionsExtension: IDbContextOptionsExtension
|
||||
{
|
||||
public IShardingRuntimeContext ShardingRuntimeContext { get; }
|
||||
|
||||
public ShardingOptionsExtension(IShardingRuntimeContext shardingRuntimeContext)
|
||||
{
|
||||
ShardingRuntimeContext = shardingRuntimeContext;
|
||||
}
|
||||
public void ApplyServices(IServiceCollection services)
|
||||
{
|
||||
services.AddSingleton<IShardingRuntimeContext>(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<string, string> debugInfo) { }
|
||||
|
||||
public override bool IsDatabaseProvider => false;
|
||||
public override string LogFragment => "ShardingOptionsExtension";
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
#if NETCOREAPP2_0
|
||||
public class ShardingOptionsExtension: IDbContextOptionsExtension
|
||||
{
|
||||
public IShardingRuntimeContext ShardingRuntimeContext { get; }
|
||||
|
||||
public ShardingOptionsExtension(IShardingRuntimeContext shardingRuntimeContext)
|
||||
{
|
||||
ShardingRuntimeContext = shardingRuntimeContext;
|
||||
}
|
||||
public bool ApplyServices(IServiceCollection services)
|
||||
{
|
||||
services.AddSingleton<IShardingRuntimeContext>(sp => ShardingRuntimeContext);
|
||||
return true;
|
||||
}
|
||||
public long GetServiceProviderHashCode() => ShardingRuntimeContext.GetHashCode();
|
||||
|
||||
public void Validate(IDbContextOptions options)
|
||||
{
|
||||
}
|
||||
|
||||
public string LogFragment => "ShardingOptionsExtension";
|
||||
}
|
||||
#endif
|
||||
}
|
|
@ -1,105 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using ShardingCore.Core;
|
||||
|
||||
namespace ShardingCore.EFCores.OptionsExtensions
|
||||
{
|
||||
/*
|
||||
* @Author: xjm
|
||||
* @Description:
|
||||
* @Date: 2021/10/17 20:27:12
|
||||
* @Ver: 1.0
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
|
||||
#if !NETCOREAPP2_0 && !NETSTANDARD2_0 && !NETCOREAPP3_0 && !NETSTANDARD2_1 && !NET5_0 && !NET6_0
|
||||
error
|
||||
#endif
|
||||
#if NET6_0
|
||||
public class ShardingWrapOptionsExtension : IDbContextOptionsExtension
|
||||
{
|
||||
|
||||
public ShardingWrapOptionsExtension()
|
||||
{
|
||||
}
|
||||
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 int GetServiceProviderHashCode() => 0;
|
||||
|
||||
public override bool ShouldUseSameServiceProvider(DbContextOptionsExtensionInfo other) => true;
|
||||
|
||||
public override void PopulateDebugInfo(IDictionary<string, string> debugInfo)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool IsDatabaseProvider => false;
|
||||
public override string LogFragment => "ShardingWrapOptionsExtension";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if NETCOREAPP3_0 || NETSTANDARD2_0 || NET5_0 || NETSTANDARD2_1
|
||||
|
||||
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<string, string> debugInfo) { }
|
||||
|
||||
public override bool IsDatabaseProvider => false;
|
||||
public override string LogFragment => "ShardingWrapOptionsExtension";
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
#if NETCOREAPP2_0
|
||||
|
||||
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
|
||||
}
|
|
@ -1,100 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace ShardingCore.EFCores.OptionsExtensions
|
||||
{
|
||||
/*
|
||||
* @Author: xjm
|
||||
* @Description:
|
||||
* @Date: 2021/10/17 20:27:12
|
||||
* @Ver: 1.0
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
|
||||
#if !NETCOREAPP2_0 && !NETSTANDARD2_0 && !NETCOREAPP3_0 && !NETSTANDARD2_1 && !NET5_0 && !NET6_0
|
||||
error
|
||||
#endif
|
||||
#if NET6_0
|
||||
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 int GetServiceProviderHashCode() => 0;
|
||||
|
||||
public override bool ShouldUseSameServiceProvider(DbContextOptionsExtensionInfo other) => true;
|
||||
|
||||
public override void PopulateDebugInfo(IDictionary<string, string> debugInfo)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool IsDatabaseProvider => false;
|
||||
public override string LogFragment => "UnionAllMergeOptionsExtension";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if NETCOREAPP3_0 || NETSTANDARD2_0 || NET5_0 || NETSTANDARD2_1
|
||||
|
||||
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<string, string> debugInfo) { }
|
||||
|
||||
public override bool IsDatabaseProvider => false;
|
||||
public override string LogFragment => "UnionAllMergeOptionsExtension";
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
#if NETCOREAPP2_0
|
||||
|
||||
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
|
||||
}
|
|
@ -4,7 +4,7 @@ using Microsoft.EntityFrameworkCore.Infrastructure;
|
|||
using Microsoft.EntityFrameworkCore.Internal;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
|
||||
namespace ShardingCore.EFCores.ChangeTrackers
|
||||
namespace ShardingCore.EFCores
|
||||
{
|
||||
|
||||
public class ShardingChangeTrackerFactory:ChangeTrackerFactory
|
|
@ -1,138 +0,0 @@
|
|||
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
|
||||
*/
|
||||
#if !NETCOREAPP2_0 && !NETSTANDARD2_0 && !NETCOREAPP3_0 && !NETSTANDARD2_1 && !NET5_0 && !NET6_0
|
||||
error
|
||||
#endif
|
||||
#if NET5_0 || NETSTANDARD2_1 || NET6_0
|
||||
public class ShardingDbSetSource : IDbSetSource
|
||||
{
|
||||
|
||||
private static readonly MethodInfo _genericCreateSet
|
||||
= typeof(ShardingDbSetSource).GetTypeInfo().GetDeclaredMethod(nameof(CreateSetFactory));
|
||||
|
||||
private readonly ConcurrentDictionary<(Type Type, string Name), Func<DbContext, string, object>> _cache
|
||||
= new ConcurrentDictionary<(Type Type, string Name), Func<DbContext, string, object>>();
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public virtual object Create(DbContext context, Type type)
|
||||
=> CreateCore(context, type, null, _genericCreateSet);
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
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<DbContext, string, object>)createMethod
|
||||
.MakeGenericMethod(t.Type)
|
||||
.Invoke(null, null))(context, name);
|
||||
|
||||
private static Func<DbContext, string, object> CreateSetFactory<TEntity>()
|
||||
where TEntity : class
|
||||
=> (c, name) => new ShardingInternalDbSet<TEntity>(c, name);
|
||||
}
|
||||
#endif
|
||||
#if NETCOREAPP3_0 || NETSTANDARD2_0
|
||||
public class ShardingDbSetSource:IDbSetSource
|
||||
{
|
||||
|
||||
private static readonly MethodInfo _genericCreateSet
|
||||
= typeof(ShardingDbSetSource).GetTypeInfo().GetDeclaredMethod(nameof(CreateSetFactory));
|
||||
|
||||
private readonly ConcurrentDictionary<Type, Func<DbContext, object>> _cache
|
||||
= new ConcurrentDictionary<Type, Func<DbContext, object>>();
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
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<DbContext, object>)createMethod
|
||||
.MakeGenericMethod(t)
|
||||
.Invoke(null, null))(context);
|
||||
|
||||
private static Func<DbContext, object> CreateSetFactory<TEntity>()
|
||||
where TEntity : class
|
||||
=> c => new ShardingInternalDbSet<TEntity>(c);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if NETCOREAPP2_0
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
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<Type, Func<DbContext, object>> _cache
|
||||
= new ConcurrentDictionary<Type, Func<DbContext, object>>();
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public virtual object Create(DbContext context, Type type)
|
||||
=> CreateCore(context, type, _genericCreateSet);
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
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<DbContext, object>)createMethod
|
||||
.MakeGenericMethod(t)
|
||||
.Invoke(null, null))(context);
|
||||
|
||||
private static Func<DbContext, object> CreateSetFactory<TEntity>()
|
||||
where TEntity : class
|
||||
=> c => new ShardingInternalDbSet<TEntity>(c);
|
||||
|
||||
private static Func<DbContext, DbQuery<TQuery>> CreateQueryFactory<TQuery>()
|
||||
where TQuery : class
|
||||
=> c => new ShardingInternalDbQuery<TQuery>(c);
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
|
@ -1,101 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
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.DbContextCreator;
|
||||
using ShardingCore.Core.RuntimeContexts;
|
||||
using ShardingCore.Core.ServiceProviders;
|
||||
using ShardingCore.Core.ShardingConfigurations;
|
||||
using ShardingCore.Core.ShardingMigrations.Abstractions;
|
||||
using ShardingCore.Core.VirtualDatabase.VirtualDataSources;
|
||||
using ShardingCore.Core.VirtualRoutes.TableRoutes.RouteTails.Abstractions;
|
||||
using ShardingCore.Exceptions;
|
||||
using ShardingCore.Extensions;
|
||||
using ShardingCore.Helpers;
|
||||
using ShardingCore.Sharding.Abstractions;
|
||||
using ShardingCore.Sharding.ShardingDbContextExecutors;
|
||||
|
||||
#if !NETCOREAPP2_0
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Conventions.Infrastructure;
|
||||
|
||||
#endif
|
||||
|
||||
namespace ShardingCore.EFCores
|
||||
{
|
||||
public class ShardingMigrator:Migrator
|
||||
{
|
||||
private readonly IShardingRuntimeContext _shardingRuntimeContext;
|
||||
|
||||
#if !NETCOREAPP2_0 && !NETSTANDARD2_0 && !NETCOREAPP3_0 && !NETSTANDARD2_1 && !NET5_0 && !NET6_0
|
||||
error
|
||||
#endif
|
||||
|
||||
#if NET6_0
|
||||
public ShardingMigrator(IShardingRuntimeContext shardingRuntimeContext,IMigrationsAssembly migrationsAssembly, IHistoryRepository historyRepository, IDatabaseCreator databaseCreator, IMigrationsSqlGenerator migrationsSqlGenerator, IRawSqlCommandBuilder rawSqlCommandBuilder, IMigrationCommandExecutor migrationCommandExecutor, IRelationalConnection connection, ISqlGenerationHelper sqlGenerationHelper, ICurrentDbContext currentContext, IModelRuntimeInitializer modelRuntimeInitializer, IDiagnosticsLogger<DbLoggerCategory.Migrations> logger, IRelationalCommandDiagnosticsLogger commandLogger, IDatabaseProvider databaseProvider) : base(migrationsAssembly, historyRepository, databaseCreator, migrationsSqlGenerator, rawSqlCommandBuilder, migrationCommandExecutor, connection, sqlGenerationHelper, currentContext, modelRuntimeInitializer, logger, commandLogger, databaseProvider)
|
||||
{
|
||||
_shardingRuntimeContext = shardingRuntimeContext;
|
||||
|
||||
}
|
||||
#endif
|
||||
#if NET5_0 || NETSTANDARD2_1
|
||||
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<DbLoggerCategory.Migrations> logger, IDiagnosticsLogger<DbLoggerCategory.Database.Command> commandLogger, IDatabaseProvider databaseProvider) : base(migrationsAssembly, historyRepository, databaseCreator, migrationsSqlGenerator, rawSqlCommandBuilder, migrationCommandExecutor, connection, sqlGenerationHelper, currentContext, conventionSetBuilder, logger, commandLogger, databaseProvider)
|
||||
{
|
||||
_shardingRuntimeContext = shardingRuntimeContext;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if NETCOREAPP3_0 || NETSTANDARD2_0
|
||||
public ShardingMigrator(IShardingRuntimeContext shardingRuntimeContext, IMigrationsAssembly migrationsAssembly, IHistoryRepository historyRepository, IDatabaseCreator databaseCreator, IMigrationsSqlGenerator migrationsSqlGenerator, IRawSqlCommandBuilder rawSqlCommandBuilder, IMigrationCommandExecutor migrationCommandExecutor, IRelationalConnection connection, ISqlGenerationHelper sqlGenerationHelper, ICurrentDbContext currentContext, IDiagnosticsLogger<DbLoggerCategory.Migrations> logger, IDiagnosticsLogger<DbLoggerCategory.Database.Command> commandLogger, IDatabaseProvider databaseProvider) : base(migrationsAssembly, historyRepository, databaseCreator, migrationsSqlGenerator, rawSqlCommandBuilder, migrationCommandExecutor, connection, sqlGenerationHelper, currentContext, logger, commandLogger, databaseProvider)
|
||||
{
|
||||
_shardingRuntimeContext = shardingRuntimeContext;
|
||||
}
|
||||
|
||||
#endif
|
||||
#if NETCOREAPP2_0
|
||||
|
||||
public ShardingMigrator(IShardingRuntimeContext shardingRuntimeContext, IMigrationsAssembly migrationsAssembly, IHistoryRepository historyRepository, IDatabaseCreator databaseCreator, IMigrationsSqlGenerator migrationsSqlGenerator, IRawSqlCommandBuilder rawSqlCommandBuilder, IMigrationCommandExecutor migrationCommandExecutor, IRelationalConnection connection, ISqlGenerationHelper sqlGenerationHelper, IDiagnosticsLogger<DbLoggerCategory.Migrations> logger, IDatabaseProvider databaseProvider) : base(migrationsAssembly, historyRepository, databaseCreator, migrationsSqlGenerator, rawSqlCommandBuilder, migrationCommandExecutor, connection, sqlGenerationHelper, logger, databaseProvider)
|
||||
{
|
||||
_shardingRuntimeContext = shardingRuntimeContext;
|
||||
}
|
||||
|
||||
#endif
|
||||
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);
|
||||
|
||||
}
|
||||
#if NET6_0 || NET5_0 || NETSTANDARD2_1
|
||||
|
||||
public override string GenerateScript(string fromMigration = null, string toMigration = null,
|
||||
MigrationsSqlGenerationOptions options = MigrationsSqlGenerationOptions.Default)
|
||||
{
|
||||
return new ScriptMigrationGenerator(_shardingRuntimeContext, fromMigration, toMigration, options).GenerateScript();
|
||||
}
|
||||
#endif
|
||||
#if NETCOREAPP3_0 || NETSTANDARD2_0 || NETCOREAPP2_0
|
||||
public override string GenerateScript(string fromMigration = null, string toMigration = null, bool idempotent = false)
|
||||
{
|
||||
return new ScriptMigrationGenerator(_shardingRuntimeContext, fromMigration, toMigration, idempotent).GenerateScript();
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
|
@ -1,85 +0,0 @@
|
|||
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
|
||||
*/
|
||||
#if !NETCOREAPP2_0 && !NETSTANDARD2_0 && !NETCOREAPP3_0 && !NETSTANDARD2_1 && !NET5_0 && !NET6_0
|
||||
error
|
||||
#endif
|
||||
#if NET6_0
|
||||
|
||||
public class ShardingRelationalTransactionFactory<TShardingDbContext> : 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<DbLoggerCategory.Database.Transaction> logger, bool transactionOwned)
|
||||
{
|
||||
var shardingDbContext = connection.Context as IShardingDbContext;
|
||||
return new ShardingRelationalTransaction(shardingDbContext, connection, transaction, transactionId, logger, transactionOwned, this.Dependencies.SqlGenerationHelper);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if NETCOREAPP3_0 || NETSTANDARD2_0 || NET5_0 || NETSTANDARD2_1
|
||||
|
||||
public class ShardingRelationalTransactionFactory<TShardingDbContext> : 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<DbLoggerCategory.Database.Transaction> logger, bool transactionOwned)
|
||||
{
|
||||
var shardingDbContext = connection.Context as IShardingDbContext;
|
||||
return new ShardingRelationalTransaction(shardingDbContext, connection, transaction, transactionId, logger, transactionOwned);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if NETCOREAPP2_0
|
||||
|
||||
public class ShardingRelationalTransactionFactory<TShardingDbContext> : 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<DbLoggerCategory.Database.Transaction> 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
|
||||
}
|
|
@ -1,4 +1,6 @@
|
|||
using System;
|
||||
#if SHARDINGCORE2_6
|
||||
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
|
@ -17,7 +19,6 @@ using ShardingCore.Core;
|
|||
using ShardingCore.Core.EntityMetadatas;
|
||||
using ShardingCore.Core.RuntimeContexts;
|
||||
using ShardingCore.EFCores;
|
||||
using ShardingCore.EFCores.OptionsExtensions;
|
||||
using ShardingCore.Exceptions;
|
||||
using ShardingCore.Utils;
|
||||
|
||||
|
@ -413,4 +414,5 @@ namespace ShardingCore.Extensions
|
|||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,203 @@
|
|||
#if SHARDINGCORE7
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Internal;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Internal;
|
||||
using ShardingCore.Core.RuntimeContexts;
|
||||
using ShardingCore.EFCores;
|
||||
using ShardingCore.Exceptions;
|
||||
|
||||
namespace ShardingCore.Extensions
|
||||
{
|
||||
[ExcludeFromCodeCoverage]
|
||||
public static class DbContextExtension
|
||||
{
|
||||
/// <summary>
|
||||
/// 移除所有的分表关系的模型
|
||||
/// </summary>
|
||||
/// <param name="dbContext"></param>
|
||||
public static void RemoveDbContextRelationModelThatIsShardingTable(this DbContext dbContext)
|
||||
{
|
||||
|
||||
var contextModel = dbContext.GetService<IDesignTimeModel>().Model; ;
|
||||
var shardingRuntimeContext = dbContext.GetShardingRuntimeContext();
|
||||
var entityMetadataManager = shardingRuntimeContext.GetEntityMetadataManager();
|
||||
|
||||
var entityTypes = contextModel.GetEntityTypes();
|
||||
foreach (var entityType in entityTypes)
|
||||
{
|
||||
if (entityType.GetFieldValue("_data") is List<object> _data)
|
||||
{
|
||||
_data.Clear();
|
||||
}
|
||||
}
|
||||
var contextModelRelationalModel = contextModel.GetRelationalModel() as RelationalModel;
|
||||
var valueTuples =
|
||||
contextModelRelationalModel.Tables.Where(o =>o.Value.EntityTypeMappings.Any(m => entityMetadataManager.IsShardingTable(m.EntityType.ClrType))).Select(o => o.Key).ToList();
|
||||
for (int i = 0; i < valueTuples.Count; i++)
|
||||
{
|
||||
contextModelRelationalModel.Tables.Remove(valueTuples[i]);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 移除所有除了仅分库的
|
||||
/// </summary>
|
||||
/// <param name="dbContext"></param>
|
||||
public static void RemoveDbContextAllRelationModelWithoutShardingDataSourceOnly(this DbContext dbContext)
|
||||
{
|
||||
|
||||
var contextModel = dbContext.GetService<IDesignTimeModel>().Model; ;
|
||||
|
||||
var shardingRuntimeContext = dbContext.GetShardingRuntimeContext();
|
||||
var entityMetadataManager = shardingRuntimeContext.GetEntityMetadataManager();
|
||||
|
||||
var entityTypes = contextModel.GetEntityTypes();
|
||||
foreach (var entityType in entityTypes)
|
||||
{
|
||||
if (entityType.GetFieldValue("_data") is List<object> _data)
|
||||
{
|
||||
_data.Clear();
|
||||
}
|
||||
}
|
||||
var contextModelRelationalModel = contextModel.GetRelationalModel() as RelationalModel;
|
||||
var valueTuples =
|
||||
contextModelRelationalModel.Tables.Where(o => o.Value.EntityTypeMappings.Any(m => !entityMetadataManager.IsShardingDataSource(m.EntityType.ClrType) ||entityMetadataManager.TryGet(m.EntityType.ClrType)==null)).Select(o => o.Key).ToList();
|
||||
for (int i = 0; i < valueTuples.Count; i++)
|
||||
{
|
||||
contextModelRelationalModel.Tables.Remove(valueTuples[i]);
|
||||
}
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// 移除所有的表
|
||||
/// </summary>
|
||||
/// <param name="dbContext"></param>
|
||||
public static void RemoveDbContextAllRelationModel(this DbContext dbContext)
|
||||
{
|
||||
|
||||
var contextModel = dbContext.GetService<IDesignTimeModel>().Model; ;
|
||||
|
||||
var contextModelRelationalModel = contextModel.GetRelationalModel() as RelationalModel;
|
||||
contextModelRelationalModel.Tables.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 移除所有的除了我指定的那个类型
|
||||
/// </summary>
|
||||
/// <param name="dbContext"></param>
|
||||
/// <param name="shardingType"></param>
|
||||
public static void RemoveDbContextRelationModelSaveOnlyThatIsNamedType(this DbContext dbContext,
|
||||
Type shardingType)
|
||||
{
|
||||
var contextModel = dbContext.GetService<IDesignTimeModel>().Model;
|
||||
var entityTypes = contextModel.GetEntityTypes();
|
||||
foreach (var entityType in entityTypes)
|
||||
{
|
||||
if (entityType.GetFieldValue("_data") is List<object> _data)
|
||||
{
|
||||
_data.Clear();
|
||||
}
|
||||
}
|
||||
var contextModelRelationalModel = contextModel.GetRelationalModel() as RelationalModel;
|
||||
var valueTuples =
|
||||
contextModelRelationalModel.Tables
|
||||
.Where(o => o.Value.EntityTypeMappings.All(m => m.EntityType.ClrType != shardingType))
|
||||
.Select(o => o.Key).ToList();
|
||||
for (int i = 0; i < valueTuples.Count; i++)
|
||||
{
|
||||
contextModelRelationalModel.Tables.Remove(valueTuples[i]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void RemoveDbContextRelationModelSaveOnlyThatIsNamedType<T>(this DbContext dbContext)
|
||||
where T:class
|
||||
{
|
||||
RemoveDbContextRelationModelSaveOnlyThatIsNamedType(dbContext, typeof(T));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 移除模型缓存
|
||||
/// </summary>
|
||||
/// <param name="dbContext"></param>
|
||||
public static void RemoveModelCache(this DbContext dbContext)
|
||||
{
|
||||
var shardingModelSource = dbContext.GetService<IModelSource>() as IShardingModelSource;
|
||||
var modelCacheKeyFactory = shardingModelSource.GetModelCacheKeyFactory();
|
||||
object key1 = modelCacheKeyFactory.Create(dbContext,true);
|
||||
shardingModelSource.Remove(key1);
|
||||
object key2 = modelCacheKeyFactory.Create(dbContext,false);
|
||||
shardingModelSource.Remove(key2);
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取模型创建的锁
|
||||
/// </summary>
|
||||
/// <param name="dbContext"></param>
|
||||
/// <returns></returns>
|
||||
public static object GetModelCacheSyncObject(this DbContext dbContext)
|
||||
{
|
||||
IShardingModelSource shardingModelSource = dbContext.GetService<IModelSource>() as IShardingModelSource;
|
||||
return shardingModelSource.GetSyncObject();
|
||||
}
|
||||
|
||||
|
||||
public static IEnumerable<object> GetPrimaryKeyValues<TEntity>(TEntity entity,IKey primaryKey) where TEntity : class
|
||||
{
|
||||
return primaryKey.Properties.Select(o =>entity.GetPropertyValue(o.Name));
|
||||
}
|
||||
|
||||
public static TEntity GetAttachedEntity<TEntity>(this DbContext context, TEntity entity) where TEntity:class
|
||||
{
|
||||
if (entity == null) { throw new ArgumentNullException(nameof(entity)); }
|
||||
var entityPrimaryKey = context.Model.FindRuntimeEntityType(entity.GetType()).FindPrimaryKey();
|
||||
if (entityPrimaryKey == null)
|
||||
{
|
||||
return entity;
|
||||
}
|
||||
var primaryKeyValue = GetPrimaryKeyValues(entity, entityPrimaryKey).ToArray();
|
||||
if (primaryKeyValue.IsEmpty())
|
||||
return null;
|
||||
var dbContextDependencies = (IDbContextDependencies)typeof(DbContext).GetTypePropertyValue(context, "DbContextDependencies");
|
||||
var stateManager = dbContextDependencies.StateManager;
|
||||
|
||||
//var entityIKey = ShardingKeyUtil.GetEntityIKey(entity);
|
||||
var internalEntityEntry = stateManager.TryGetEntry(entityPrimaryKey, primaryKeyValue);
|
||||
|
||||
if (internalEntityEntry == null)
|
||||
return null;
|
||||
return (TEntity)internalEntityEntry.Entity;
|
||||
//sp.Restart();
|
||||
|
||||
//var entityEntries = context.ChangeTracker.Entries<TEntity>();
|
||||
//sp.Stop();
|
||||
//Console.WriteLine($"ChangeTracker.Entries:{sp.ElapsedMilliseconds}毫秒");
|
||||
//sp.Restart();
|
||||
//var entry = entityEntries.Where(e => e.State != EntityState.Detached && primaryKeyValue.SequenceEqual(ShardingKeyUtil.GetPrimaryKeyValues(e.Entity))).FirstOrDefault();
|
||||
//sp.Stop();
|
||||
//Console.WriteLine($"ChangeTracker.FirstOrDefault:{sp.ElapsedMilliseconds}毫秒");
|
||||
//return entry?.Entity;
|
||||
}
|
||||
|
||||
public static IShardingRuntimeContext GetShardingRuntimeContext(this DbContext dbContext)
|
||||
{
|
||||
var shardingRuntimeContext = dbContext.GetService<IShardingRuntimeContext>();
|
||||
|
||||
if (shardingRuntimeContext == null)
|
||||
{
|
||||
throw new ShardingCoreInvalidOperationException($"cant resolve:[{typeof(IShardingRuntimeContext)}],dbcontext:[{dbContext}]");
|
||||
}
|
||||
|
||||
return shardingRuntimeContext;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -11,7 +11,7 @@ using Microsoft.EntityFrameworkCore.Query.Internal;
|
|||
using ShardingCore.Core;
|
||||
using ShardingCore.Core.RuntimeContexts;
|
||||
using ShardingCore.Core.VirtualRoutes.TableRoutes.RouteTails.Abstractions;
|
||||
using ShardingCore.EFCores.OptionsExtensions;
|
||||
using ShardingCore.EFCores;
|
||||
using ShardingCore.Sharding;
|
||||
using ShardingCore.Sharding.Abstractions;
|
||||
|
||||
|
|
|
@ -1,18 +1,13 @@
|
|||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.ChangeTracking;
|
||||
using ShardingCore.Core.VirtualRoutes.TableRoutes.RouteTails.Abstractions;
|
||||
using ShardingCore.EFCores.OptionsExtensions;
|
||||
using ShardingCore.Extensions;
|
||||
using ShardingCore.Sharding.Abstractions;
|
||||
using ShardingCore.Sharding.ShardingDbContextExecutors;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using ShardingCore.Core.VirtualDatabase.VirtualDataSources;
|
||||
using ShardingCore.Exceptions;
|
||||
using ShardingCore.EFCores;
|
||||
|
||||
namespace ShardingCore.Sharding
|
||||
{
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
#if SHARDINGCORE2_6
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
@ -23,9 +24,6 @@ namespace ShardingCore.Sharding.Parsers.Visitors
|
|||
/// Author: xjm
|
||||
/// Created: 2022/5/1 21:43:12
|
||||
/// Email: 326308290@qq.com
|
||||
#if !NETCOREAPP2_0 && !NETSTANDARD2_0 && !NETCOREAPP3_0 && !NETSTANDARD2_1 && !NET5_0 && !NET6_0
|
||||
error
|
||||
#endif
|
||||
internal class ShardingQueryPrepareVisitor : ExpressionVisitor
|
||||
{
|
||||
private readonly IShardingDbContext _shardingDbContext;
|
||||
|
@ -232,3 +230,5 @@ namespace ShardingCore.Sharding.Parsers.Visitors
|
|||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,219 @@
|
|||
#if SHARDINGCORE7
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Query;
|
||||
using ShardingCore.Core;
|
||||
using ShardingCore.Core.TrackerManagers;
|
||||
using ShardingCore.Extensions;
|
||||
using ShardingCore.Extensions.ShardingQueryableExtensions;
|
||||
using ShardingCore.Sharding.Abstractions;
|
||||
using ShardingCore.Sharding.Visitors.ShardingExtractParameters;
|
||||
|
||||
namespace ShardingCore.Sharding.Parsers.Visitors
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// Author: xjm
|
||||
/// Created: 2022/5/1 21:43:12
|
||||
/// Email: 326308290@qq.com
|
||||
internal class ShardingQueryPrepareVisitor : ExpressionVisitor
|
||||
{
|
||||
private readonly IShardingDbContext _shardingDbContext;
|
||||
private bool isNotSupport;
|
||||
private ShardingQueryableUseConnectionModeOptions shardingQueryableUseConnectionModeOptions;
|
||||
private ShardingQueryableAsRouteOptions shardingQueryableAsRouteOptions;
|
||||
private ShardingQueryableReadWriteSeparationOptions shardingQueryableReadWriteSeparationOptions;
|
||||
private ShardingQueryableAsSequenceOptions shardingQueryableAsSequenceOptions;
|
||||
|
||||
|
||||
|
||||
private readonly ITrackerManager _trackerManager;
|
||||
private bool? isNoTracking;
|
||||
private bool isIgnoreFilter;
|
||||
private readonly Dictionary<Type, IQueryable> shardingEntities = new();
|
||||
|
||||
public ShardingQueryPrepareVisitor(IShardingDbContext shardingDbContext)
|
||||
{
|
||||
_shardingDbContext = shardingDbContext;
|
||||
_trackerManager =((DbContext)shardingDbContext).GetShardingRuntimeContext()
|
||||
.GetTrackerManager();
|
||||
}
|
||||
public ShardingPrepareResult GetShardingPrepareResult()
|
||||
{
|
||||
return new ShardingPrepareResult(isNotSupport,
|
||||
shardingQueryableAsRouteOptions,
|
||||
shardingQueryableUseConnectionModeOptions,
|
||||
shardingQueryableReadWriteSeparationOptions,
|
||||
shardingQueryableAsSequenceOptions,
|
||||
shardingEntities, isNoTracking, isIgnoreFilter);
|
||||
}
|
||||
protected override Expression VisitExtension(Expression node)
|
||||
{
|
||||
if (node is QueryRootExpression queryRootExpression)
|
||||
{
|
||||
TryAddShardingEntities(queryRootExpression.ElementType, null);
|
||||
}
|
||||
return base.VisitExtension(node);
|
||||
}
|
||||
private void TryAddShardingEntities(Type entityType, IQueryable queryable)
|
||||
{
|
||||
if (!shardingEntities.ContainsKey(entityType))
|
||||
{
|
||||
shardingEntities.Add(entityType, queryable);
|
||||
}
|
||||
}
|
||||
|
||||
protected override Expression VisitMember
|
||||
(MemberExpression memberExpression)
|
||||
{
|
||||
|
||||
//if (memberExpression.IsMemberQueryable()) //2x,3x 路由 单元测试 分表和不分表
|
||||
//{
|
||||
// Recurse down to see if we can simplify...
|
||||
var expression = Visit(memberExpression.Expression);
|
||||
|
||||
// If we've ended up with a constant, and it's a property or a field,
|
||||
// we can simplify ourselves to a constant
|
||||
if (expression is ConstantExpression)
|
||||
{
|
||||
object container = ((ConstantExpression)expression).Value;
|
||||
var member = memberExpression.Member;
|
||||
if (member is FieldInfo fieldInfo)
|
||||
{
|
||||
object value = fieldInfo.GetValue(container);
|
||||
if (value is IQueryable queryable)
|
||||
{
|
||||
TryAddShardingEntities(queryable.ElementType, queryable);
|
||||
}
|
||||
//return Expression.Constant(value);
|
||||
}
|
||||
if (member is PropertyInfo propertyInfo)
|
||||
{
|
||||
object value = propertyInfo.GetValue(container, null);
|
||||
if (value is IQueryable queryable)
|
||||
{
|
||||
TryAddShardingEntities(queryable.ElementType, queryable);
|
||||
}
|
||||
}
|
||||
}
|
||||
//}
|
||||
return base.VisitMember(memberExpression);
|
||||
}
|
||||
protected override Expression VisitMethodCall(MethodCallExpression node)
|
||||
{
|
||||
|
||||
switch (node.Method.Name)
|
||||
{
|
||||
case nameof(EntityFrameworkQueryableExtensions.AsNoTracking): isNoTracking = true; break;
|
||||
case nameof(EntityFrameworkQueryableExtensions.AsTracking): isNoTracking = false; break;
|
||||
case nameof(EntityFrameworkQueryableExtensions.IgnoreQueryFilters): isIgnoreFilter = true; break;
|
||||
// case nameof(EntityFrameworkQueryableExtensions.Include):
|
||||
// case nameof(EntityFrameworkQueryableExtensions.ThenInclude): DiscoverQueryEntities(node); break;
|
||||
default:
|
||||
{
|
||||
if (node.Method.ReturnType.IsMethodReturnTypeQueryableType()&&node.Method.ReturnType.IsGenericType)
|
||||
{
|
||||
DiscoverQueryEntities(node);
|
||||
}
|
||||
var customerExpression = DiscoverCustomerQueryEntities(node);
|
||||
if (customerExpression != null)
|
||||
{
|
||||
return Visit(customerExpression);
|
||||
}
|
||||
}
|
||||
; break;
|
||||
}
|
||||
|
||||
|
||||
return base.VisitMethodCall(node);
|
||||
}
|
||||
|
||||
private Expression DiscoverCustomerQueryEntities(MethodCallExpression node)
|
||||
{
|
||||
|
||||
if (node.Method.IsGenericMethod)
|
||||
{
|
||||
var genericMethodDefinition = node.Method.GetGenericMethodDefinition();
|
||||
|
||||
// find notsupport extention calls
|
||||
if (genericMethodDefinition == EntityFrameworkShardingQueryableExtension.NotSupportMethodInfo)
|
||||
{
|
||||
isNotSupport = true;
|
||||
// cut out extension expression
|
||||
return node.Arguments[0];
|
||||
}
|
||||
else if (genericMethodDefinition == EntityFrameworkShardingQueryableExtension.UseConnectionModeMethodInfo)
|
||||
{
|
||||
shardingQueryableUseConnectionModeOptions = node.Arguments
|
||||
.OfType<ConstantExpression>()
|
||||
.Where(o => o.Value is ShardingQueryableUseConnectionModeOptions)
|
||||
.Select(o => (ShardingQueryableUseConnectionModeOptions)o.Value)
|
||||
.Last();
|
||||
return node.Arguments[0];
|
||||
}
|
||||
else if (genericMethodDefinition == EntityFrameworkShardingQueryableExtension.AsRouteMethodInfo)
|
||||
{
|
||||
shardingQueryableAsRouteOptions = node.Arguments
|
||||
.OfType<ConstantExpression>()
|
||||
.Where(o => o.Value is ShardingQueryableAsRouteOptions)
|
||||
.Select(o => (ShardingQueryableAsRouteOptions)o.Value)
|
||||
.Last();
|
||||
return node.Arguments[0];
|
||||
}
|
||||
else if (genericMethodDefinition == EntityFrameworkShardingQueryableExtension.AsSequenceModeMethodInfo)
|
||||
{
|
||||
shardingQueryableAsSequenceOptions = node.Arguments
|
||||
.OfType<ConstantExpression>()
|
||||
.Where(o => o.Value is ShardingQueryableAsSequenceOptions)
|
||||
.Select(o => (ShardingQueryableAsSequenceOptions)o.Value)
|
||||
.Last();
|
||||
return node.Arguments[0];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void DiscoverQueryEntities(MethodCallExpression node)
|
||||
{
|
||||
var genericArguments = node.Type.GetGenericArguments();
|
||||
for (var i = 0; i < genericArguments.Length; i++)
|
||||
{
|
||||
var genericArgument = genericArguments[i];
|
||||
|
||||
if (typeof(IEnumerable).IsAssignableFrom(genericArgument))
|
||||
{
|
||||
var arguments = genericArgument.GetGenericArguments();
|
||||
foreach (var argument in arguments)
|
||||
{
|
||||
//if is db context model
|
||||
if (_trackerManager.IsDbContextModel(argument))
|
||||
{
|
||||
TryAddShardingEntities(argument, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!genericArgument.IsSimpleType())
|
||||
{
|
||||
//if is db context model
|
||||
if (_trackerManager.IsDbContextModel(genericArgument))
|
||||
{
|
||||
TryAddShardingEntities(genericArgument, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -1,3 +1,4 @@
|
|||
#if SHARDINGCORE2_6
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
|
@ -225,4 +226,6 @@ namespace ShardingCore.Core.Internal.Visitors
|
|||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,188 @@
|
|||
#if SHARDINGCORE7
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Internal;
|
||||
using Microsoft.EntityFrameworkCore.Query;
|
||||
using ShardingCore.Core.Internal.Visitors;
|
||||
using ShardingCore.Exceptions;
|
||||
using ShardingCore.Extensions;
|
||||
|
||||
namespace ShardingCore.Core.Internal.Visitors
|
||||
{
|
||||
/*
|
||||
* @Author: xjm
|
||||
* @Description:
|
||||
* @Date: Wednesday, 13 January 2021 16:32:27
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
|
||||
internal class DbContextInnerMemberReferenceReplaceQueryableVisitor : ShardingExpressionVisitor
|
||||
{
|
||||
private readonly DbContext _dbContext;
|
||||
protected bool RootIsVisit = false;
|
||||
|
||||
public DbContextInnerMemberReferenceReplaceQueryableVisitor(DbContext dbContext)
|
||||
{
|
||||
_dbContext = dbContext;
|
||||
}
|
||||
|
||||
// public override Expression Visit(Expression node)
|
||||
// {
|
||||
// Console.WriteLine("1");
|
||||
// return base.Visit(node);
|
||||
// }
|
||||
|
||||
protected override Expression VisitMember
|
||||
(MemberExpression memberExpression)
|
||||
{
|
||||
// Recurse down to see if we can simplify...
|
||||
if (memberExpression.IsMemberQueryable()) //2x,3x 路由 单元测试 分表和不分表
|
||||
{
|
||||
var expressionValue = GetExpressionValue(memberExpression);
|
||||
if (expressionValue is IQueryable queryable)
|
||||
{
|
||||
return ReplaceMemberExpression(queryable);
|
||||
}
|
||||
|
||||
if (expressionValue is DbContext dbContext)
|
||||
{
|
||||
return ReplaceMemberExpression(dbContext);
|
||||
}
|
||||
}
|
||||
|
||||
return base.VisitMember(memberExpression);
|
||||
}
|
||||
|
||||
private MemberExpression ReplaceMemberExpression(IQueryable queryable)
|
||||
{
|
||||
var dbContextReplaceQueryableVisitor = new DbContextReplaceQueryableVisitor(_dbContext);
|
||||
var newExpression = dbContextReplaceQueryableVisitor.Visit(queryable.Expression);
|
||||
var newQueryable = dbContextReplaceQueryableVisitor.Source.Provider.CreateQuery(newExpression);
|
||||
var tempVariableGenericType = typeof(TempVariable<>).GetGenericType0(queryable.ElementType);
|
||||
var tempVariable = Activator.CreateInstance(tempVariableGenericType, newQueryable);
|
||||
MemberExpression queryableMemberReplaceExpression =
|
||||
Expression.Property(ConstantExpression.Constant(tempVariable), nameof(TempVariable<object>.Queryable));
|
||||
return queryableMemberReplaceExpression;
|
||||
}
|
||||
|
||||
private MemberExpression ReplaceMemberExpression(DbContext dbContext)
|
||||
{
|
||||
var tempVariableGenericType = typeof(TempDbVariable<>).GetGenericType0(dbContext.GetType());
|
||||
var tempVariable = Activator.CreateInstance(tempVariableGenericType, _dbContext);
|
||||
MemberExpression dbContextMemberReplaceExpression =
|
||||
Expression.Property(ConstantExpression.Constant(tempVariable),
|
||||
nameof(TempDbVariable<object>.DbContext));
|
||||
return dbContextMemberReplaceExpression;
|
||||
}
|
||||
protected override Expression VisitMethodCall(MethodCallExpression node)
|
||||
{
|
||||
if (RootIsVisit&&node.Method.ReturnType.IsMethodReturnTypeQueryableType()&&node.Method.ReturnType.IsGenericType)
|
||||
{
|
||||
var notRoot = node.Arguments.IsEmpty();
|
||||
|
||||
if (notRoot)
|
||||
{
|
||||
var entityType = node.Method.ReturnType.GenericTypeArguments[0];
|
||||
|
||||
var whereCallExpression = ReplaceMethodCallExpression(node, entityType);
|
||||
return whereCallExpression;
|
||||
}
|
||||
}
|
||||
|
||||
return base.VisitMethodCall(node);
|
||||
}
|
||||
|
||||
private MethodCallExpression ReplaceMethodCallExpression(MethodCallExpression methodCallExpression,
|
||||
Type entityType)
|
||||
{
|
||||
MethodCallExpression whereCallExpression = Expression.Call(
|
||||
typeof(IShardingQueryableExtension),
|
||||
nameof(IShardingQueryableExtension.ReplaceDbContextQueryableWithType),
|
||||
new Type[] { entityType },
|
||||
methodCallExpression, Expression.Constant(_dbContext)
|
||||
);
|
||||
return whereCallExpression;
|
||||
}
|
||||
|
||||
internal sealed class TempVariable<T1>
|
||||
{
|
||||
public IQueryable<T1> Queryable { get; }
|
||||
|
||||
public TempVariable(IQueryable<T1> queryable)
|
||||
{
|
||||
Queryable = queryable;
|
||||
}
|
||||
|
||||
public IQueryable<T1> GetQueryable()
|
||||
{
|
||||
return Queryable;
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class TempDbVariable<T1>
|
||||
{
|
||||
public T1 DbContext { get; }
|
||||
|
||||
public TempDbVariable(T1 dbContext)
|
||||
{
|
||||
DbContext = dbContext;
|
||||
}
|
||||
}
|
||||
}
|
||||
internal class DbContextReplaceQueryableVisitor : DbContextInnerMemberReferenceReplaceQueryableVisitor
|
||||
{
|
||||
private readonly DbContext _dbContext;
|
||||
public IQueryable Source;
|
||||
|
||||
public DbContextReplaceQueryableVisitor(DbContext dbContext) : base(dbContext)
|
||||
{
|
||||
_dbContext = dbContext;
|
||||
}
|
||||
|
||||
protected override Expression VisitExtension(Expression node)
|
||||
{
|
||||
if (node is QueryRootExpression queryRootExpression)
|
||||
{
|
||||
var dbContextDependencies =
|
||||
typeof(DbContext).GetTypePropertyValue(_dbContext, "DbContextDependencies") as
|
||||
IDbContextDependencies;
|
||||
var targetIQ =
|
||||
(IQueryable)((IDbSetCache)_dbContext).GetOrAddSet(dbContextDependencies.SetSource,
|
||||
queryRootExpression.ElementType);
|
||||
|
||||
var newQueryable = targetIQ.Provider.CreateQuery(targetIQ.Expression);
|
||||
if (Source == null)
|
||||
Source = newQueryable;
|
||||
//如何替换ef5的set
|
||||
var replaceQueryRoot = new ReplaceSingleQueryRootExpressionVisitor();
|
||||
replaceQueryRoot.Visit(newQueryable.Expression);
|
||||
RootIsVisit = true;
|
||||
return base.VisitExtension(replaceQueryRoot.QueryRootExpression);
|
||||
}
|
||||
|
||||
return base.VisitExtension(node);
|
||||
}
|
||||
|
||||
internal sealed class ReplaceSingleQueryRootExpressionVisitor : ExpressionVisitor
|
||||
{
|
||||
public QueryRootExpression QueryRootExpression { get; set; }
|
||||
|
||||
protected override Expression VisitExtension(Expression node)
|
||||
{
|
||||
if (node is QueryRootExpression queryRootExpression)
|
||||
{
|
||||
if (QueryRootExpression != null)
|
||||
throw new ShardingCoreException("replace query root more than one query root");
|
||||
QueryRootExpression = queryRootExpression;
|
||||
}
|
||||
|
||||
return base.VisitExtension(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue