修改添加对EFCORE7的支持

This commit is contained in:
xuejiaming 2022-11-09 11:39:43 +08:00
parent 9a4306dd8d
commit 32d4d79a53
156 changed files with 10730 additions and 1051 deletions

View File

@ -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}

View File

@ -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>

View File

@ -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>

View File

@ -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

View File

@ -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>

View File

@ -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>

View File

@ -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)
{
}
}
}

View File

@ -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>

View File

@ -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>

View File

@ -16,7 +16,7 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\ShardingCore\ShardingCore.csproj" />
<ProjectReference Include="..\..\src2_6\ShardingCore.2_6\ShardingCore.2_6.csproj" />
</ItemGroup>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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;

View File

@ -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;

View File

@ -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>

View File

@ -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)
{
}
}
}

View File

@ -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>

View File

@ -1,4 +1,4 @@
#if NETCOREAPP2_0
#if NETCOREAPP2_0&&SHARDINGCORE2_6
using Microsoft.EntityFrameworkCore.Migrations;
using ShardingCore.Core.RuntimeContexts;

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -1,4 +1,4 @@
#if NETCOREAPP2_0
#if NETCOREAPP2_0&&SHARDINGCORE2_6
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -1,4 +1,4 @@
#if NET5_0 || NETSTANDARD2_1
#if (NET5_0 || NETSTANDARD2_1)&&SHARDINGCORE2_6
using Microsoft.EntityFrameworkCore.Migrations;
using ShardingCore.Core.RuntimeContexts;

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -1,4 +1,4 @@
#if NET6_0
#if NET6_0&&SHARDINGCORE2_6
using Microsoft.EntityFrameworkCore.Migrations;
using ShardingCore.Core.RuntimeContexts;

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -1,5 +1,5 @@

#if NET6_0
#if NET6_0&&SHARDINGCORE2_6
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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

View File

@ -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
}

View File

@ -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
}
}

View File

@ -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
}

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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
{

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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