优化简洁调用的代码将重写合并到statemanager

This commit is contained in:
xuejiaming 2022-12-22 22:47:25 +08:00
parent ca0608523e
commit 3875def0fa
43 changed files with 609 additions and 2914 deletions

View File

@ -26,7 +26,6 @@ namespace Sample.AutoCreateIfPresent
base.OnModelCreating(modelBuilder);
modelBuilder.ApplyConfiguration(new OrderByHourMap());
modelBuilder.ApplyConfiguration(new AreaDeviceMap());
Console.WriteLine(this.IsExecutor);
}
public IRouteTail RouteTail { get; set; }

View File

@ -23,7 +23,7 @@ public class DbSetDiscoverExpressionVisitor<TEntity>:ExpressionVisitor where TEn
var dbContextDependencies =
typeof(DbContext).GetTypePropertyValue(_dbContext, "DbContextDependencies") as IDbContextDependencies;
var targetIQ =
((IDbSetCache)_dbContext).GetOrAddSet(dbContextDependencies.SetSource, queryRootExpression.EntityType.ClrType);
((IDbSetCache)_dbContext).GetOrAddSet(dbContextDependencies.SetSource, queryRootExpression.ElementType);
DbSet = (DbSet<TEntity>)targetIQ;
}
return base.VisitExtension(node);

View File

@ -74,17 +74,17 @@ namespace Sample.MySql.Controllers
[HttpGet]
public async Task<IActionResult> Get()
{
var virtualDataSource = _shardingRuntimeContext.GetVirtualDataSource();
virtualDataSource.AddPhysicDataSource(new DefaultPhysicDataSource("2023", "xxxxxxxx", false));
var dataSourceRouteManager = _shardingRuntimeContext.GetDataSourceRouteManager();
var virtualDataSourceRoute = dataSourceRouteManager.GetRoute(typeof(SysUserMod));
virtualDataSourceRoute.AddDataSourceName("2023");
var dataSourceInitializer = _shardingRuntimeContext.GetDataSourceInitializer();
dataSourceInitializer.InitConfigure("2023",true,true);
using (var dbContextTransaction = _defaultTableDbContext.Database.BeginTransaction())
{
}
// var virtualDataSource = _shardingRuntimeContext.GetVirtualDataSource();
// virtualDataSource.AddPhysicDataSource(new DefaultPhysicDataSource("2023", "xxxxxxxx", false));
// var dataSourceRouteManager = _shardingRuntimeContext.GetDataSourceRouteManager();
// var virtualDataSourceRoute = dataSourceRouteManager.GetRoute(typeof(SysUserMod));
// virtualDataSourceRoute.AddDataSourceName("2023");
// var dataSourceInitializer = _shardingRuntimeContext.GetDataSourceInitializer();
// dataSourceInitializer.InitConfigure("2023",true,true);
// using (var dbContextTransaction = _defaultTableDbContext.Database.BeginTransaction())
// {
//
// }
var x2 = await (from ut in _defaultTableDbContext.Set<SysTest>()
join uu in _defaultTableDbContext.Set<SysUserLogByMonth>()

View File

@ -38,12 +38,13 @@ namespace Sample.MySql
});
}
var userModMonths = new List<SysUserLogByMonth>();
var begin = new DateTime(2021, 1, 01);
foreach (var id in ids)
{
userModMonths.Add(new SysUserLogByMonth()
{
Id = id.ToString(),
Time = DateTime.Now
Time = begin.AddHours(id*12)
});
}

View File

@ -40,10 +40,10 @@ namespace Sample.MySql.DbContexts
modelBuilder.ApplyConfiguration(new SysTestMap());
modelBuilder.ApplyConfiguration(new SysUserLogByMonthMap());
modelBuilder.Entity<SysUserLogByMonth>().HasData(new SysUserLogByMonth() { Id = "1", Time = DateTime.Now });
modelBuilder.Entity<SysTest>().HasData(new SysTest() { Id = "1", UserId = "123" });
modelBuilder.Entity<TestMod>().ToTable(nameof(TestMod));
modelBuilder.Entity<TestModItem>().ToTable(nameof(TestModItem));
// modelBuilder.Entity<SysUserLogByMonth>().HasData(new SysUserLogByMonth() { Id = "1", Time = DateTime.Now });
// modelBuilder.Entity<SysTest>().HasData(new SysTest() { Id = "1", UserId = "123" });
// modelBuilder.Entity<TestMod>().ToTable(nameof(TestMod));
// modelBuilder.Entity<TestModItem>().ToTable(nameof(TestModItem));
}

View File

@ -12,11 +12,11 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="6.0.2" />
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="7.0.0-alpha.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src6\ShardingCore6\ShardingCore6.csproj" />
<ProjectReference Include="..\..\src\ShardingCore\ShardingCore.csproj" />
</ItemGroup>

View File

@ -1,6 +1,7 @@
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Migrations.Operations;
using Microsoft.EntityFrameworkCore.Update;
using Pomelo.EntityFrameworkCore.MySql.Infrastructure.Internal;
using Pomelo.EntityFrameworkCore.MySql.Migrations;
using ShardingCore.Core.RuntimeContexts;
@ -12,7 +13,8 @@ namespace Sample.MySql
{
private readonly IShardingRuntimeContext _shardingRuntimeContext;
public ShardingMySqlMigrationsSqlGenerator(MigrationsSqlGeneratorDependencies dependencies, IRelationalAnnotationProvider annotationProvider, IMySqlOptions options,IShardingRuntimeContext shardingRuntimeContext) : base(dependencies, annotationProvider, options)
public ShardingMySqlMigrationsSqlGenerator(IShardingRuntimeContext shardingRuntimeContext,MigrationsSqlGeneratorDependencies dependencies, ICommandBatchPreparer commandBatchPreparer, IMySqlOptions options) : base(dependencies, commandBatchPreparer, options)
{
_shardingRuntimeContext = shardingRuntimeContext;
}

View File

@ -9,14 +9,14 @@ public class SysUserModVirtualDataSourceRoute:AbstractShardingOperatorVirtualDat
{
public override string ShardingKeyToDataSourceName(object shardingKey)
{
return $"{((string)shardingKey=="ds1"?"ds1":"ds2")}";
return $"{shardingKey}";
}
public override List<string> GetAllDataSourceNames()
{
return new List<string>()
{
"ds1", "ds2"
"ds0", "ds1", "ds2"
};
}

View File

@ -74,8 +74,8 @@ namespace Sample.MySql
.UseRouteConfig(o =>
{
o.AddShardingTableRoute<DynamicTableRoute>();
o.AddShardingTableRoute<SysUserLogByMonthRoute>();
// o.AddShardingTableRoute<SysUserModVirtualTableRoute>();
o.AddShardingTableRoute<SysUserLogByMonthRoute>();
o.AddShardingTableRoute<SysUserModVirtualTableRoute>();
o.AddShardingDataSourceRoute<SysUserModVirtualDataSourceRoute>();
o.AddShardingTableRoute<TestModRoute>();
o.AddShardingTableRoute<TestModItemRoute>();
@ -118,11 +118,11 @@ namespace Sample.MySql
//.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);
});
o.AddDefaultDataSource("ds0",
"server=127.0.0.1;port=3306;database=dbdbd02;userid=root;password=root;");
"server=127.0.0.1;port=3306;database=dbdbd0;userid=root;password=root;");
o.AddExtraDataSource(sp => new Dictionary<string, string>()
{
{ "ds1", "server=127.0.0.1;port=3306;database=dbdbd12;userid=root;password=root;" },
{ "ds2", "server=127.0.0.1;port=3306;database=dbdbd22;userid=root;password=root;" }
{ "ds1", "server=127.0.0.1;port=3306;database=dbdbd1;userid=root;password=root;" },
{ "ds2", "server=127.0.0.1;port=3306;database=dbdbd2;userid=root;password=root;" }
});
o.UseShardingMigrationConfigure(b =>
{

View File

@ -13,7 +13,7 @@ namespace ShardingCore.Core.QueryTrackers
{
public object Track(object entity, IShardingDbContext shardingDbContext)
{
var genericDbContext = shardingDbContext.CreateGenericDbContext(entity);
var genericDbContext = shardingDbContext.GetShardingExecutor().CreateGenericDbContext(entity);
var attachedEntity = genericDbContext.GetAttachedEntity(entity);
if (attachedEntity == null)
genericDbContext.Attach(entity);

View File

@ -91,7 +91,7 @@ namespace ShardingCore.EFCores
{
if (_dbContext is IShardingDbContext shardingDbContext)
{
var genericDbContext = shardingDbContext.CreateGenericDbContext(rootEntity);
var genericDbContext = shardingDbContext.GetShardingExecutor().CreateGenericDbContext(rootEntity);
genericDbContext.ChangeTracker.TrackGraph(rootEntity,callback);
// Do(c => c.TrackGraph(rootEntity,callback));
}
@ -101,7 +101,7 @@ namespace ShardingCore.EFCores
{
if (_dbContext is IShardingDbContext shardingDbContext)
{
var genericDbContext = shardingDbContext.CreateGenericDbContext(rootEntity);
var genericDbContext = shardingDbContext.GetShardingExecutor().CreateGenericDbContext(rootEntity);
genericDbContext.ChangeTracker.TrackGraph(rootEntity,state,callback);
// Do(c => c.TrackGraph(rootEntity,callback));
}

View File

@ -1,62 +0,0 @@
#if EFCORE2
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,27 +0,0 @@
#if EFCORE2
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Internal;
namespace ShardingCore.EFCores
{
/*
* @Author: xjm
* @Description:
* @Date: 2021/8/20 17:05:36
* @Ver: 1.0
* @Email: 326308290@qq.com
*/
public class ShardingInternalDbQuery<TQuery> : InternalDbQuery<TQuery> where TQuery : class
{
public ShardingInternalDbQuery(DbContext context) : base(context)
{
}
}
}
#endif

View File

@ -1,427 +0,0 @@
#if EFCORE2
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,112 @@
#if EFCORE2
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking.Internal;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Internal;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Storage;
using ShardingCore.Sharding.Abstractions;
namespace ShardingCore.EFCores
{
public class ShardingStateManager:StateManager
{
private readonly DbContext _currentDbContext;
private readonly IShardingDbContext _currentShardingDbContext;
public ShardingStateManager(StateManagerDependencies dependencies) : base(dependencies)
{
_currentDbContext=dependencies.CurrentContext.Context;
_currentShardingDbContext = (IShardingDbContext)_currentDbContext;
}
public override InternalEntityEntry GetOrCreateEntry(object entity)
{
var genericDbContext = _currentShardingDbContext.GetShardingExecutor().CreateGenericDbContext(entity);
var dbContextDependencies = genericDbContext.GetService<IDbContextDependencies>();
var stateManager = dbContextDependencies.StateManager;
return stateManager.GetOrCreateEntry(entity);
}
public override InternalEntityEntry GetOrCreateEntry(object entity, IEntityType entityType)
{
var genericDbContext = _currentShardingDbContext.GetShardingExecutor().CreateGenericDbContext(entity);
var dbContextDependencies = genericDbContext.GetService<IDbContextDependencies>();
var stateManager = dbContextDependencies.StateManager;
return stateManager.GetOrCreateEntry(entity,entityType);
}
public override InternalEntityEntry StartTrackingFromQuery(IEntityType baseEntityType, object entity, in ValueBuffer valueBuffer,
ISet<IForeignKey> handledForeignKeys)
{
var genericDbContext = _currentShardingDbContext.GetShardingExecutor().CreateGenericDbContext(entity);
var dbContextDependencies = genericDbContext.GetService<IDbContextDependencies>();
var stateManager = dbContextDependencies.StateManager;
return stateManager.StartTrackingFromQuery(baseEntityType, entity, in valueBuffer, handledForeignKeys);
}
public override InternalEntityEntry TryGetEntry(object entity, bool throwOnNonUniqueness = true)
{
var genericDbContext = _currentShardingDbContext.GetShardingExecutor().CreateGenericDbContext(entity);
var dbContextDependencies = genericDbContext.GetService<IDbContextDependencies>();
var stateManager = dbContextDependencies.StateManager;
return stateManager.TryGetEntry(entity, throwOnNonUniqueness);
}
public override InternalEntityEntry TryGetEntry(object entity, IEntityType entityType)
{
var genericDbContext = _currentShardingDbContext.GetShardingExecutor().CreateGenericDbContext(entity);
var dbContextDependencies = genericDbContext.GetService<IDbContextDependencies>();
var stateManager = dbContextDependencies.StateManager;
return stateManager.TryGetEntry(entity, entityType);
}
public override int SaveChanges(bool acceptAllChangesOnSuccess)
{
//ApplyShardingConcepts();
int i = 0;
//如果是内部开的事务就内部自己消化
if (_currentDbContext.Database.AutoTransactionsEnabled&&_currentDbContext.Database.CurrentTransaction==null&&_currentShardingDbContext.GetShardingExecutor().IsMultiDbContext)
{
using (var tran = _currentDbContext.Database.BeginTransaction())
{
i = _currentShardingDbContext.GetShardingExecutor().SaveChanges(acceptAllChangesOnSuccess);
tran.Commit();
}
}
else
{
i = _currentShardingDbContext.GetShardingExecutor().SaveChanges(acceptAllChangesOnSuccess);
}
return i;
}
public override async Task<int> SaveChangesAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = new CancellationToken())
{
//ApplyShardingConcepts();
int i = 0;
//如果是内部开的事务就内部自己消化
if (_currentDbContext.Database.AutoTransactionsEnabled && _currentDbContext.Database.CurrentTransaction==null && _currentShardingDbContext.GetShardingExecutor().IsMultiDbContext)
{
using (var tran = await _currentDbContext.Database.BeginTransactionAsync(cancellationToken))
{
i = await _currentShardingDbContext.GetShardingExecutor().SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken);
tran.Commit();
}
}
else
{
i = await _currentShardingDbContext.GetShardingExecutor().SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken);
}
return i;
}
}
}
#endif

View File

@ -92,7 +92,7 @@ namespace ShardingCore.EFCores
{
if (_dbContext is IShardingDbContext shardingDbContext)
{
var genericDbContext = shardingDbContext.CreateGenericDbContext(rootEntity);
var genericDbContext = shardingDbContext.GetShardingExecutor().CreateGenericDbContext(rootEntity);
genericDbContext.ChangeTracker.TrackGraph(rootEntity,callback);
// Do(c => c.TrackGraph(rootEntity,callback));
}
@ -102,7 +102,7 @@ namespace ShardingCore.EFCores
{
if (_dbContext is IShardingDbContext shardingDbContext)
{
var genericDbContext = shardingDbContext.CreateGenericDbContext(rootEntity);
var genericDbContext = shardingDbContext.GetShardingExecutor().CreateGenericDbContext(rootEntity);
genericDbContext.ChangeTracker.TrackGraph(rootEntity,state,callback);
// Do(c => c.TrackGraph(rootEntity,callback));
}

View File

@ -1,48 +0,0 @@
#if EFCORE3
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

@ -1,436 +0,0 @@
#if EFCORE3
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,111 @@
#if EFCORE3
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking.Internal;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Internal;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Storage;
using ShardingCore.Sharding.Abstractions;
namespace ShardingCore.EFCores
{
public class ShardingStateManager:StateManager
{
private readonly DbContext _currentDbContext;
private readonly IShardingDbContext _currentShardingDbContext;
public ShardingStateManager(StateManagerDependencies dependencies) : base(dependencies)
{
_currentDbContext=dependencies.CurrentContext.Context;
_currentShardingDbContext = (IShardingDbContext)_currentDbContext;
}
public override InternalEntityEntry GetOrCreateEntry(object entity)
{
var genericDbContext = _currentShardingDbContext.GetShardingExecutor().CreateGenericDbContext(entity);
var dbContextDependencies = genericDbContext.GetService<IDbContextDependencies>();
var stateManager = dbContextDependencies.StateManager;
return stateManager.GetOrCreateEntry(entity);
}
public override InternalEntityEntry GetOrCreateEntry(object entity, IEntityType entityType)
{
var genericDbContext = _currentShardingDbContext.GetShardingExecutor().CreateGenericDbContext(entity);
var dbContextDependencies = genericDbContext.GetService<IDbContextDependencies>();
var stateManager = dbContextDependencies.StateManager;
return stateManager.GetOrCreateEntry(entity,entityType);
}
public override InternalEntityEntry StartTrackingFromQuery(IEntityType baseEntityType, object entity, in ValueBuffer valueBuffer)
{
var genericDbContext = _currentShardingDbContext.GetShardingExecutor().CreateGenericDbContext(entity);
var dbContextDependencies = genericDbContext.GetService<IDbContextDependencies>();
var stateManager = dbContextDependencies.StateManager;
return stateManager.StartTrackingFromQuery(baseEntityType, entity, in valueBuffer);
}
public override InternalEntityEntry TryGetEntry(object entity, bool throwOnNonUniqueness = true)
{
var genericDbContext = _currentShardingDbContext.GetShardingExecutor().CreateGenericDbContext(entity);
var dbContextDependencies = genericDbContext.GetService<IDbContextDependencies>();
var stateManager = dbContextDependencies.StateManager;
return stateManager.TryGetEntry(entity, throwOnNonUniqueness);
}
public override InternalEntityEntry TryGetEntry(object entity, IEntityType entityType, bool throwOnTypeMismatch = true)
{
var genericDbContext = _currentShardingDbContext.GetShardingExecutor().CreateGenericDbContext(entity);
var dbContextDependencies = genericDbContext.GetService<IDbContextDependencies>();
var stateManager = dbContextDependencies.StateManager;
return stateManager.TryGetEntry(entity, entityType, throwOnTypeMismatch);
}
public override int SaveChanges(bool acceptAllChangesOnSuccess)
{
//ApplyShardingConcepts();
int i = 0;
//如果是内部开的事务就内部自己消化
if (_currentDbContext.Database.AutoTransactionsEnabled&&_currentDbContext.Database.CurrentTransaction==null&&_currentShardingDbContext.GetShardingExecutor().IsMultiDbContext)
{
using (var tran = _currentDbContext.Database.BeginTransaction())
{
i = _currentShardingDbContext.GetShardingExecutor().SaveChanges(acceptAllChangesOnSuccess);
tran.Commit();
}
}
else
{
i = _currentShardingDbContext.GetShardingExecutor().SaveChanges(acceptAllChangesOnSuccess);
}
return i;
}
public override async Task<int> SaveChangesAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = new CancellationToken())
{
//ApplyShardingConcepts();
int i = 0;
//如果是内部开的事务就内部自己消化
if (_currentDbContext.Database.AutoTransactionsEnabled && _currentDbContext.Database.CurrentTransaction==null && _currentShardingDbContext.GetShardingExecutor().IsMultiDbContext)
{
using (var tran = await _currentDbContext.Database.BeginTransactionAsync(cancellationToken))
{
i = await _currentShardingDbContext.GetShardingExecutor().SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken);
await tran.CommitAsync(cancellationToken);
}
}
else
{
i = await _currentShardingDbContext.GetShardingExecutor().SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken);
}
return i;
}
}
}
#endif

View File

@ -91,7 +91,7 @@ namespace ShardingCore.EFCores
{
if (_dbContext is IShardingDbContext shardingDbContext)
{
var genericDbContext = shardingDbContext.CreateGenericDbContext(rootEntity);
var genericDbContext = shardingDbContext.GetShardingExecutor().CreateGenericDbContext(rootEntity);
genericDbContext.ChangeTracker.TrackGraph(rootEntity,callback);
// Do(c => c.TrackGraph(rootEntity,callback));
}
@ -101,7 +101,7 @@ namespace ShardingCore.EFCores
{
if (_dbContext is IShardingDbContext shardingDbContext)
{
var genericDbContext = shardingDbContext.CreateGenericDbContext(rootEntity);
var genericDbContext = shardingDbContext.GetShardingExecutor().CreateGenericDbContext(rootEntity);
genericDbContext.ChangeTracker.TrackGraph(rootEntity,state,callback);
// Do(c => c.TrackGraph(rootEntity,callback));
}

View File

@ -1,57 +0,0 @@
#if EFCORE5
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,439 +0,0 @@
#if EFCORE5
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,111 @@
#if EFCORE5
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking.Internal;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Internal;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Storage;
using ShardingCore.Sharding.Abstractions;
namespace ShardingCore.EFCores
{
public class ShardingStateManager:StateManager
{
private readonly DbContext _currentDbContext;
private readonly IShardingDbContext _currentShardingDbContext;
public ShardingStateManager(StateManagerDependencies dependencies) : base(dependencies)
{
_currentDbContext=dependencies.CurrentContext.Context;
_currentShardingDbContext = (IShardingDbContext)_currentDbContext;
}
public override InternalEntityEntry GetOrCreateEntry(object entity)
{
var genericDbContext = _currentShardingDbContext.GetShardingExecutor().CreateGenericDbContext(entity);
var dbContextDependencies = genericDbContext.GetService<IDbContextDependencies>();
var stateManager = dbContextDependencies.StateManager;
return stateManager.GetOrCreateEntry(entity);
}
public override InternalEntityEntry GetOrCreateEntry(object entity, IEntityType entityType)
{
var genericDbContext = _currentShardingDbContext.GetShardingExecutor().CreateGenericDbContext(entity);
var dbContextDependencies = genericDbContext.GetService<IDbContextDependencies>();
var stateManager = dbContextDependencies.StateManager;
return stateManager.GetOrCreateEntry(entity,entityType);
}
public override InternalEntityEntry StartTrackingFromQuery(IEntityType baseEntityType, object entity, in ValueBuffer valueBuffer)
{
var genericDbContext = _currentShardingDbContext.GetShardingExecutor().CreateGenericDbContext(entity);
var dbContextDependencies = genericDbContext.GetService<IDbContextDependencies>();
var stateManager = dbContextDependencies.StateManager;
return stateManager.StartTrackingFromQuery(baseEntityType, entity, in valueBuffer);
}
public override InternalEntityEntry TryGetEntry(object entity, bool throwOnNonUniqueness = true)
{
var genericDbContext = _currentShardingDbContext.GetShardingExecutor().CreateGenericDbContext(entity);
var dbContextDependencies = genericDbContext.GetService<IDbContextDependencies>();
var stateManager = dbContextDependencies.StateManager;
return stateManager.TryGetEntry(entity, throwOnNonUniqueness);
}
public override InternalEntityEntry TryGetEntry(object entity, IEntityType entityType, bool throwOnTypeMismatch = true)
{
var genericDbContext = _currentShardingDbContext.GetShardingExecutor().CreateGenericDbContext(entity);
var dbContextDependencies = genericDbContext.GetService<IDbContextDependencies>();
var stateManager = dbContextDependencies.StateManager;
return stateManager.TryGetEntry(entity, entityType, throwOnTypeMismatch);
}
public override int SaveChanges(bool acceptAllChangesOnSuccess)
{
//ApplyShardingConcepts();
int i = 0;
//如果是内部开的事务就内部自己消化
if (_currentDbContext.Database.AutoTransactionsEnabled&&_currentDbContext.Database.CurrentTransaction==null&&_currentShardingDbContext.GetShardingExecutor().IsMultiDbContext)
{
using (var tran = _currentDbContext.Database.BeginTransaction())
{
i = _currentShardingDbContext.GetShardingExecutor().SaveChanges(acceptAllChangesOnSuccess);
tran.Commit();
}
}
else
{
i = _currentShardingDbContext.GetShardingExecutor().SaveChanges(acceptAllChangesOnSuccess);
}
return i;
}
public override async Task<int> SaveChangesAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = new CancellationToken())
{
//ApplyShardingConcepts();
int i = 0;
//如果是内部开的事务就内部自己消化
if (_currentDbContext.Database.AutoTransactionsEnabled && _currentDbContext.Database.CurrentTransaction==null && _currentShardingDbContext.GetShardingExecutor().IsMultiDbContext)
{
using (var tran = await _currentDbContext.Database.BeginTransactionAsync(cancellationToken))
{
i = await _currentShardingDbContext.GetShardingExecutor().SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken);
await tran.CommitAsync(cancellationToken);
}
}
else
{
i = await _currentShardingDbContext.GetShardingExecutor().SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken);
}
return i;
}
}
}
#endif

View File

@ -91,7 +91,7 @@ namespace ShardingCore.EFCores
{
if (_dbContext is IShardingDbContext shardingDbContext)
{
var genericDbContext = shardingDbContext.CreateGenericDbContext(rootEntity);
var genericDbContext = shardingDbContext.GetShardingExecutor().CreateGenericDbContext(rootEntity);
genericDbContext.ChangeTracker.TrackGraph(rootEntity,callback);
// Do(c => c.TrackGraph(rootEntity,callback));
}
@ -101,7 +101,7 @@ namespace ShardingCore.EFCores
{
if (_dbContext is IShardingDbContext shardingDbContext)
{
var genericDbContext = shardingDbContext.CreateGenericDbContext(rootEntity);
var genericDbContext = shardingDbContext.GetShardingExecutor().CreateGenericDbContext(rootEntity);
genericDbContext.ChangeTracker.TrackGraph(rootEntity,state,callback);
// Do(c => c.TrackGraph(rootEntity,callback));
}

View File

@ -1,57 +0,0 @@
#if EFCORE6
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,436 +0,0 @@
#if EFCORE6
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,111 @@
#if EFCORE6
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking.Internal;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Internal;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Storage;
using ShardingCore.Sharding.Abstractions;
namespace ShardingCore.EFCores
{
public class ShardingStateManager:StateManager
{
private readonly DbContext _currentDbContext;
private readonly IShardingDbContext _currentShardingDbContext;
public ShardingStateManager(StateManagerDependencies dependencies) : base(dependencies)
{
_currentDbContext=dependencies.CurrentContext.Context;
_currentShardingDbContext = (IShardingDbContext)_currentDbContext;
}
public override InternalEntityEntry GetOrCreateEntry(object entity)
{
var genericDbContext = _currentShardingDbContext.GetShardingExecutor().CreateGenericDbContext(entity);
var dbContextDependencies = genericDbContext.GetService<IDbContextDependencies>();
var stateManager = dbContextDependencies.StateManager;
return stateManager.GetOrCreateEntry(entity);
}
public override InternalEntityEntry GetOrCreateEntry(object entity, IEntityType entityType)
{
var genericDbContext = _currentShardingDbContext.GetShardingExecutor().CreateGenericDbContext(entity);
var dbContextDependencies = genericDbContext.GetService<IDbContextDependencies>();
var stateManager = dbContextDependencies.StateManager;
return stateManager.GetOrCreateEntry(entity,entityType);
}
public override InternalEntityEntry StartTrackingFromQuery(IEntityType baseEntityType, object entity, in ValueBuffer valueBuffer)
{
var genericDbContext = _currentShardingDbContext.GetShardingExecutor().CreateGenericDbContext(entity);
var dbContextDependencies = genericDbContext.GetService<IDbContextDependencies>();
var stateManager = dbContextDependencies.StateManager;
return stateManager.StartTrackingFromQuery(baseEntityType, entity, in valueBuffer);
}
public override InternalEntityEntry TryGetEntry(object entity, bool throwOnNonUniqueness = true)
{
var genericDbContext = _currentShardingDbContext.GetShardingExecutor().CreateGenericDbContext(entity);
var dbContextDependencies = genericDbContext.GetService<IDbContextDependencies>();
var stateManager = dbContextDependencies.StateManager;
return stateManager.TryGetEntry(entity, throwOnNonUniqueness);
}
public override InternalEntityEntry TryGetEntry(object entity, IEntityType entityType, bool throwOnTypeMismatch = true)
{
var genericDbContext = _currentShardingDbContext.GetShardingExecutor().CreateGenericDbContext(entity);
var dbContextDependencies = genericDbContext.GetService<IDbContextDependencies>();
var stateManager = dbContextDependencies.StateManager;
return stateManager.TryGetEntry(entity, entityType, throwOnTypeMismatch);
}
public override int SaveChanges(bool acceptAllChangesOnSuccess)
{
//ApplyShardingConcepts();
int i = 0;
//如果是内部开的事务就内部自己消化
if (_currentDbContext.Database.AutoTransactionsEnabled&&_currentDbContext.Database.CurrentTransaction==null&&_currentShardingDbContext.GetShardingExecutor().IsMultiDbContext)
{
using (var tran = _currentDbContext.Database.BeginTransaction())
{
i = _currentShardingDbContext.GetShardingExecutor().SaveChanges(acceptAllChangesOnSuccess);
tran.Commit();
}
}
else
{
i = _currentShardingDbContext.GetShardingExecutor().SaveChanges(acceptAllChangesOnSuccess);
}
return i;
}
public override async Task<int> SaveChangesAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = new CancellationToken())
{
//ApplyShardingConcepts();
int i = 0;
//如果是内部开的事务就内部自己消化
if (_currentDbContext.Database.AutoTransactionsEnabled && _currentDbContext.Database.CurrentTransaction==null && _currentShardingDbContext.GetShardingExecutor().IsMultiDbContext)
{
using (var tran = await _currentDbContext.Database.BeginTransactionAsync(cancellationToken))
{
i = await _currentShardingDbContext.GetShardingExecutor().SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken);
await tran.CommitAsync(cancellationToken);
}
}
else
{
i = await _currentShardingDbContext.GetShardingExecutor().SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken);
}
return i;
}
}
}
#endif

View File

@ -91,7 +91,7 @@ namespace ShardingCore.EFCores
{
if (_dbContext is IShardingDbContext shardingDbContext)
{
var genericDbContext = shardingDbContext.CreateGenericDbContext(rootEntity);
var genericDbContext = shardingDbContext.GetShardingExecutor().CreateGenericDbContext(rootEntity);
genericDbContext.ChangeTracker.TrackGraph(rootEntity,callback);
// Do(c => c.TrackGraph(rootEntity,callback));
}
@ -101,7 +101,7 @@ namespace ShardingCore.EFCores
{
if (_dbContext is IShardingDbContext shardingDbContext)
{
var genericDbContext = shardingDbContext.CreateGenericDbContext(rootEntity);
var genericDbContext = shardingDbContext.GetShardingExecutor().CreateGenericDbContext(rootEntity);
genericDbContext.ChangeTracker.TrackGraph(rootEntity,state,callback);
// Do(c => c.TrackGraph(rootEntity,callback));
}

View File

@ -1,57 +0,0 @@
#if EFCORE7
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,435 +0,0 @@
#if EFCORE7
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

@ -1,24 +1,32 @@
#if EFCORE7
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking.Internal;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Internal;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Storage;
using ShardingCore.Sharding.Abstractions;
namespace ShardingCore.EFCores
{
public class ShardingStateManager:StateManager
{
private readonly DbContext _currentDbContext;
private readonly IShardingDbContext _currentShardingDbContext;
public ShardingStateManager(StateManagerDependencies dependencies) : base(dependencies)
{
_currentShardingDbContext = (IShardingDbContext)dependencies.CurrentContext;
_currentDbContext=dependencies.CurrentContext.Context;
_currentShardingDbContext = (IShardingDbContext)_currentDbContext;
}
public override InternalEntityEntry GetOrCreateEntry(object entity)
{
var genericDbContext = _currentShardingDbContext.CreateGenericDbContext(entity);
var genericDbContext = _currentShardingDbContext.GetShardingExecutor().CreateGenericDbContext(entity);
var dbContextDependencies = genericDbContext.GetService<IDbContextDependencies>();
var stateManager = dbContextDependencies.StateManager;
return stateManager.GetOrCreateEntry(entity);
@ -26,10 +34,78 @@ namespace ShardingCore.EFCores
public override InternalEntityEntry GetOrCreateEntry(object entity, IEntityType entityType)
{
var genericDbContext = _currentShardingDbContext.CreateGenericDbContext(entity);
var genericDbContext = _currentShardingDbContext.GetShardingExecutor().CreateGenericDbContext(entity);
var dbContextDependencies = genericDbContext.GetService<IDbContextDependencies>();
var stateManager = dbContextDependencies.StateManager;
return stateManager.GetOrCreateEntry(entity,entityType);
}
public override InternalEntityEntry StartTrackingFromQuery(IEntityType baseEntityType, object entity, in ValueBuffer valueBuffer)
{
var genericDbContext = _currentShardingDbContext.GetShardingExecutor().CreateGenericDbContext(entity);
var dbContextDependencies = genericDbContext.GetService<IDbContextDependencies>();
var stateManager = dbContextDependencies.StateManager;
return stateManager.StartTrackingFromQuery(baseEntityType, entity, in valueBuffer);
}
public override InternalEntityEntry TryGetEntry(object entity, bool throwOnNonUniqueness = true)
{
var genericDbContext = _currentShardingDbContext.GetShardingExecutor().CreateGenericDbContext(entity);
var dbContextDependencies = genericDbContext.GetService<IDbContextDependencies>();
var stateManager = dbContextDependencies.StateManager;
return stateManager.TryGetEntry(entity, throwOnNonUniqueness);
}
public override InternalEntityEntry TryGetEntry(object entity, IEntityType entityType, bool throwOnTypeMismatch = true)
{
var genericDbContext = _currentShardingDbContext.GetShardingExecutor().CreateGenericDbContext(entity);
var dbContextDependencies = genericDbContext.GetService<IDbContextDependencies>();
var stateManager = dbContextDependencies.StateManager;
return stateManager.TryGetEntry(entity, entityType, throwOnTypeMismatch);
}
public override int SaveChanges(bool acceptAllChangesOnSuccess)
{
//ApplyShardingConcepts();
int i = 0;
//如果是内部开的事务就内部自己消化
if (_currentDbContext.Database.AutoTransactionsEnabled&&_currentDbContext.Database.CurrentTransaction==null&&_currentShardingDbContext.GetShardingExecutor().IsMultiDbContext)
{
using (var tran = _currentDbContext.Database.BeginTransaction())
{
i = _currentShardingDbContext.GetShardingExecutor().SaveChanges(acceptAllChangesOnSuccess);
tran.Commit();
}
}
else
{
i = _currentShardingDbContext.GetShardingExecutor().SaveChanges(acceptAllChangesOnSuccess);
}
return i;
}
public override async Task<int> SaveChangesAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = new CancellationToken())
{
//ApplyShardingConcepts();
int i = 0;
//如果是内部开的事务就内部自己消化
if (_currentDbContext.Database.AutoTransactionsEnabled && _currentDbContext.Database.CurrentTransaction==null && _currentShardingDbContext.GetShardingExecutor().IsMultiDbContext)
{
using (var tran = await _currentDbContext.Database.BeginTransactionAsync(cancellationToken))
{
i = await _currentShardingDbContext.GetShardingExecutor().SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken);
await tran.CommitAsync(cancellationToken);
}
}
else
{
i = await _currentShardingDbContext.GetShardingExecutor().SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken);
}
return i;
}
}
}
}
#endif

View File

@ -146,7 +146,7 @@ namespace ShardingCore.Extensions
var shardingRuntimeContext = dbContext.GetShardingRuntimeContext();
var entityMetadataManager = shardingRuntimeContext.GetEntityMetadataManager();
#if EFCORE6
#if EFCORE6 || EFCORE7
var entityTypes = contextModel.GetEntityTypes();
foreach (var entityType in entityTypes)
{
@ -156,8 +156,17 @@ namespace ShardingCore.Extensions
}
}
var contextModelRelationalModel = contextModel.GetRelationalModel() as RelationalModel;
foreach (var keyValuePair in contextModelRelationalModel.Tables)
{
foreach (var valueEntityTypeMapping in keyValuePair.Value.EntityTypeMappings)
{
var x = !entityMetadataManager.IsOnlyShardingDataSource(valueEntityTypeMapping.EntityType.ClrType);
Console.WriteLine(valueEntityTypeMapping.EntityType.ClrType);
Console.WriteLine(x);
}
}
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();
contextModelRelationalModel.Tables.Where(o => o.Value.EntityTypeMappings.Any(m => !entityMetadataManager.IsOnlyShardingDataSource(m.EntityType.ClrType)) ).Select(o => o.Key).ToList();
for (int i = 0; i < valueTuples.Count; i++)
{
contextModelRelationalModel.Tables.Remove(valueTuples[i]);
@ -174,7 +183,7 @@ namespace ShardingCore.Extensions
}
var contextModelRelationalModel = contextModel.RelationalModel 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();
contextModelRelationalModel.Tables.Where(o => o.Value.EntityTypeMappings.Any(m => !entityMetadataManager.IsOnlyShardingDataSource(m.EntityType.ClrType))).Select(o => o.Key).ToList();
for (int i = 0; i < valueTuples.Count; i++)
{
contextModelRelationalModel.Tables.Remove(valueTuples[i]);
@ -191,7 +200,7 @@ namespace ShardingCore.Extensions
_data.Clear();
}
}
var list = entityTypes.Where(o => !entityMetadataManager.IsShardingDataSource(o.Value.ClrType) || entityMetadataManager.TryGet(o.Value.ClrType) == null).Select(o => o.Key).ToList();
var list = entityTypes.Where(o => !entityMetadataManager.IsOnlyShardingDataSource(o.Value.ClrType)).Select(o => o.Key).ToList();
for (int i = 0; i < list.Count; i++)
{
entityTypes.Remove(list[i]);
@ -216,7 +225,7 @@ namespace ShardingCore.Extensions
var contextModel = dbContext.Model as Model;
#endif
#if EFCORE6
#if EFCORE6 || EFCORE7
var contextModelRelationalModel = contextModel.GetRelationalModel() as RelationalModel;
contextModelRelationalModel.Tables.Clear();
#endif

View File

@ -39,7 +39,7 @@ namespace ShardingCore.Extensions
/// <returns></returns>
public static DbContext GetShareDbContext(this IShardingDbContext shardingDbContext,string dataSourceName,IRouteTail routeTail)
{
return shardingDbContext.GetDbContext(dataSourceName, CreateDbContextStrategyEnum.ShareConnection, routeTail);
return shardingDbContext.GetShardingExecutor().CreateDbContext(CreateDbContextStrategyEnum.ShareConnection,dataSourceName, routeTail);
}
/// <summary>
@ -51,7 +51,7 @@ namespace ShardingCore.Extensions
/// <returns></returns>
public static DbContext GetIndependentWriteDbContext(this IShardingDbContext shardingDbContext,string dataSourceName,IRouteTail routeTail)
{
return shardingDbContext.GetDbContext(dataSourceName, CreateDbContextStrategyEnum.IndependentConnectionWrite, routeTail);
return shardingDbContext.GetShardingExecutor().CreateDbContext(CreateDbContextStrategyEnum.IndependentConnectionWrite,dataSourceName, routeTail);
}
/// <summary>
/// 获取独立生命周期的读连接字符串的db context
@ -62,7 +62,7 @@ namespace ShardingCore.Extensions
/// <returns></returns>
public static DbContext GetIndependentQueryDbContext(this IShardingDbContext shardingDbContext,string dataSourceName,IRouteTail routeTail)
{
return shardingDbContext.GetDbContext(dataSourceName, CreateDbContextStrategyEnum.IndependentConnectionQuery, routeTail);
return shardingDbContext.GetShardingExecutor().CreateDbContext(CreateDbContextStrategyEnum.IndependentConnectionQuery,dataSourceName, routeTail);
}
}
}

View File

@ -108,7 +108,7 @@ namespace ShardingCore.Extensions
new Dictionary<DbContext, IEnumerable<TEntity>>()
{
{
shardingDbContext.CreateGenericDbContext(entitiesArray[0]),
shardingDbContext.GetShardingExecutor().CreateGenericDbContext(entitiesArray[0]),
entitiesArray
}
}

View File

@ -33,381 +33,28 @@ namespace ShardingCore.Sharding
{
ShardingDbContextExecutor = new ShardingDbContextExecutor(this);
}
IsExecutor = wrapOptionsExtension == null;
}
/// <summary>
/// 是否是真正的执行者
/// </summary>
public bool IsExecutor { get; }
public DbContext GetDbContext(string dataSourceName, CreateDbContextStrategyEnum strategy, IRouteTail routeTail)
{
return ShardingDbContextExecutor.CreateDbContext(strategy, dataSourceName, routeTail);
}
/// <summary>
/// 根据对象创建通用的dbcontext
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <param name="entity"></param>
/// <returns></returns>
public DbContext CreateGenericDbContext<TEntity>(TEntity entity) where TEntity : class
{
return ShardingDbContextExecutor.CreateGenericDbContext(entity);
}
public IShardingDbContextExecutor GetShardingExecutor()
{
return ShardingDbContextExecutor;
}
public override EntityEntry Add(object entity)
{
if (IsExecutor)
base.Add(entity);
return CreateGenericDbContext(entity).Add(entity);
}
public override EntityEntry<TEntity> Add<TEntity>(TEntity entity)
{
if (IsExecutor)
return base.Add(entity);
return CreateGenericDbContext(entity).Add(entity);
}
#if !EFCORE2
public override ValueTask<EntityEntry<TEntity>> AddAsync<TEntity>(TEntity entity, CancellationToken cancellationToken = new CancellationToken())
{
if (IsExecutor)
return base.AddAsync(entity, cancellationToken);
return CreateGenericDbContext(entity).AddAsync(entity, cancellationToken);
}
public override ValueTask<EntityEntry> AddAsync(object entity, CancellationToken cancellationToken = new CancellationToken())
{
if (IsExecutor)
return base.AddAsync(entity, cancellationToken);
return CreateGenericDbContext(entity).AddAsync(entity, cancellationToken);
}
#endif
#if EFCORE2
public override Task<EntityEntry<TEntity>> AddAsync<TEntity>(TEntity entity, CancellationToken cancellationToken = new CancellationToken())
{
if (IsExecutor)
return base.AddAsync(entity, cancellationToken);
return CreateGenericDbContext(entity).AddAsync(entity, cancellationToken);
}
public override Task<EntityEntry> AddAsync(object entity, CancellationToken cancellationToken = new CancellationToken())
{
if (IsExecutor)
return base.AddAsync(entity, cancellationToken);
return CreateGenericDbContext(entity).AddAsync(entity, cancellationToken);
}
#endif
private Dictionary<DbContext, IEnumerable<TEntity>> AggregateToDic<TEntity>(IEnumerable<TEntity> entities) where TEntity:class
{
return entities.Select(o =>
{
var dbContext = CreateGenericDbContext(o);
return new
{
DbContext = dbContext,
Entity = o
};
}).GroupBy(g => g.DbContext).ToDictionary(o => o.Key, o => o.Select(g => g.Entity));
}
public override void AddRange(params object[] entities)
{
if (IsExecutor)
{
base.AddRange(entities);
return;
}
var aggregateToDic = AggregateToDic(entities);
foreach (var aggregateKv in aggregateToDic)
{
aggregateKv.Key.AddRange(aggregateKv.Value);
}
}
public override void AddRange(IEnumerable<object> entities)
{
if (IsExecutor)
{
base.AddRange(entities);
return;
}
var aggregateToDic = AggregateToDic(entities);
foreach (var aggregateKv in aggregateToDic)
{
aggregateKv.Key.AddRange(aggregateKv.Value);
}
}
public override async Task AddRangeAsync(params object[] entities)
{
if (IsExecutor)
{
await base.AddRangeAsync(entities);
return;
}
var aggregateToDic = AggregateToDic(entities);
foreach (var aggregateKv in aggregateToDic)
{
await aggregateKv.Key.AddRangeAsync(aggregateKv.Value);
}
}
public override async Task AddRangeAsync(IEnumerable<object> entities, CancellationToken cancellationToken = new CancellationToken())
{
if (IsExecutor)
{
await base.AddRangeAsync(entities, cancellationToken);
return;
}
var aggregateToDic = AggregateToDic(entities);
foreach (var aggregateKv in aggregateToDic)
{
await aggregateKv.Key.AddRangeAsync(aggregateKv.Value,cancellationToken);
}
}
public override EntityEntry<TEntity> Attach<TEntity>(TEntity entity)
{
if (IsExecutor)
return base.Attach(entity);
return CreateGenericDbContext(entity).Attach(entity);
}
public override EntityEntry Attach(object entity)
{
if (IsExecutor)
return base.Attach(entity);
return CreateGenericDbContext(entity).Attach(entity);
}
public override void AttachRange(params object[] entities)
{
if (IsExecutor)
{
base.AttachRange(entities);
return;
}
var aggregateToDic = AggregateToDic(entities);
foreach (var aggregateKv in aggregateToDic)
{
aggregateKv.Key.AttachRange(aggregateKv.Value);
}
}
public override void AttachRange(IEnumerable<object> entities)
{
if (IsExecutor)
{
base.AttachRange(entities);
return;
}
var aggregateToDic = AggregateToDic(entities);
foreach (var aggregateKv in aggregateToDic)
{
aggregateKv.Key.AttachRange(aggregateKv.Value);
}
}
//public override DatabaseFacade Database => _dbContextCaches.Any()
// ? _dbContextCaches.First().Value.Database
// : GetDbContext(true, string.Empty).Database;
public override EntityEntry<TEntity> Entry<TEntity>(TEntity entity)
{
if (IsExecutor)
return base.Entry(entity);
return CreateGenericDbContext(entity).Entry(entity);
}
public override EntityEntry Entry(object entity)
{
if (IsExecutor)
return base.Entry(entity);
return CreateGenericDbContext(entity).Entry(entity);
}
public override EntityEntry<TEntity> Update<TEntity>(TEntity entity)
{
if (IsExecutor)
return base.Update(entity);
return CreateGenericDbContext(entity).Update(entity);
}
public override EntityEntry Update(object entity)
{
if (IsExecutor)
return base.Update(entity);
return CreateGenericDbContext(entity).Update(entity);
}
public override void UpdateRange(params object[] entities)
{
if (IsExecutor)
{
base.UpdateRange(entities);
return;
}
var aggregateToDic = AggregateToDic(entities);
foreach (var aggregateKv in aggregateToDic)
{
aggregateKv.Key.UpdateRange(aggregateKv.Value);
}
}
public override void UpdateRange(IEnumerable<object> entities)
{
if (IsExecutor)
{
base.UpdateRange(entities);
return;
}
var aggregateToDic = AggregateToDic(entities);
foreach (var aggregateKv in aggregateToDic)
{
aggregateKv.Key.UpdateRange(aggregateKv.Value);
}
}
public override EntityEntry<TEntity> Remove<TEntity>(TEntity entity)
{
if (IsExecutor)
return base.Remove(entity);
return CreateGenericDbContext(entity).Remove(entity);
}
public override EntityEntry Remove(object entity)
{
if (IsExecutor)
return base.Remove(entity);
return CreateGenericDbContext(entity).Remove(entity);
}
public override void RemoveRange(params object[] entities)
{
if (IsExecutor)
{
base.RemoveRange(entities);
return;
}
var aggregateToDic = AggregateToDic(entities);
foreach (var aggregateKv in aggregateToDic)
{
aggregateKv.Key.RemoveRange(aggregateKv.Value);
}
}
public override void RemoveRange(IEnumerable<object> entities)
{
if (IsExecutor)
{
base.RemoveRange(entities);
return;
}
var aggregateToDic = AggregateToDic(entities);
foreach (var aggregateKv in aggregateToDic)
{
aggregateKv.Key.RemoveRange(aggregateKv.Value);
}
}
public override int SaveChanges(bool acceptAllChangesOnSuccess)
{
if (IsExecutor)
return base.SaveChanges(acceptAllChangesOnSuccess);
//ApplyShardingConcepts();
int i = 0;
//如果是内部开的事务就内部自己消化
if (Database.AutoTransactionsEnabled&&Database.CurrentTransaction==null&&ShardingDbContextExecutor.IsMultiDbContext)
{
using (var tran = Database.BeginTransaction())
{
i = ShardingDbContextExecutor.SaveChanges(acceptAllChangesOnSuccess);
tran.Commit();
}
}
else
{
i = ShardingDbContextExecutor.SaveChanges(acceptAllChangesOnSuccess);
}
return i;
}
public override async Task<int> SaveChangesAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = new CancellationToken())
{
if (IsExecutor)
return await base.SaveChangesAsync(acceptAllChangesOnSuccess,cancellationToken);
//ApplyShardingConcepts();
int i = 0;
//如果是内部开的事务就内部自己消化
if (Database.AutoTransactionsEnabled && Database.CurrentTransaction==null && ShardingDbContextExecutor.IsMultiDbContext)
{
using (var tran = await Database.BeginTransactionAsync(cancellationToken))
{
i = await ShardingDbContextExecutor.SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken);
#if EFCORE2
tran.Commit();
#endif
#if !EFCORE2
await tran.CommitAsync(cancellationToken);
#endif
}
}
else
{
i = await ShardingDbContextExecutor.SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken);
}
return i;
}
public override void Dispose()
{
if (IsExecutor)
{
base.Dispose();
}
else
{
ShardingDbContextExecutor.Dispose();
base.Dispose();
}
ShardingDbContextExecutor?.Dispose();
base.Dispose();
}
#if !EFCORE2
public override async ValueTask DisposeAsync()
{
if (IsExecutor)
{
await base.DisposeAsync();
}
else
if (ShardingDbContextExecutor!=null)
{
await ShardingDbContextExecutor.DisposeAsync();
await base.DisposeAsync();
}
await base.DisposeAsync();
}
#endif
}

View File

@ -13,23 +13,6 @@ namespace ShardingCore.Sharding.Abstractions
*/
public interface IShardingDbContext
{
/// <summary>
/// create DbContext
/// </summary>
/// <param name="dataSourceName">data source</param>
/// <param name="strategy">生成db connection的策略,主要区别在于是否和主db connection一直或者是否需要缓存其connection还有是否是独立声明周期的区别</param>
/// <param name="routeTail"></param>
/// <returns></returns>
DbContext GetDbContext(string dataSourceName, CreateDbContextStrategyEnum strategy, IRouteTail routeTail);
/// <summary>
/// 创建通用的db context
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="entity"></param>
/// <returns></returns>
DbContext CreateGenericDbContext<T>(T entity) where T : class;
IShardingDbContextExecutor GetShardingExecutor();

View File

@ -52,5 +52,7 @@ namespace ShardingCore.Sharding.Abstractions
int SaveChanges(bool acceptAllChangesOnSuccess);
DbContext GetShellDbContext();
}
}

View File

@ -190,6 +190,11 @@ namespace ShardingCore.Sharding.ShardingDbContextExecutors
return i;
}
public DbContext GetShellDbContext()
{
return _shardingDbContext;
}
public void NotifyShardingTransaction()
{
foreach (var dbContextCache in _dbContextCaches)
@ -355,5 +360,7 @@ namespace ShardingCore.Sharding.ShardingDbContextExecutors
}
}
}
}
}

View File

@ -191,7 +191,7 @@ namespace ShardingCore.Sharding.ShardingExecutors
var strategy = !IsParallelQuery()
? CreateDbContextStrategyEnum.ShareConnection
: CreateDbContextStrategyEnum.IndependentConnectionQuery;
var dbContext = GetShardingDbContext().GetDbContext(sqlRouteUnit.DataSourceName,strategy , routeTailFactory.Create(sqlRouteUnit.TableRouteResult));
var dbContext = GetShardingDbContext().GetShardingExecutor().CreateDbContext(strategy,sqlRouteUnit.DataSourceName, routeTailFactory.Create(sqlRouteUnit.TableRouteResult));
_queryCompilerExecutor = new QueryCompilerExecutor(dbContext, GetQueryExpression());
}
}

View File

@ -175,7 +175,7 @@ namespace ShardingCore.Sharding.ShardingExecutors
var strategy = !IsParallelQuery()
? CreateDbContextStrategyEnum.ShareConnection
: CreateDbContextStrategyEnum.IndependentConnectionQuery;
var dbContext = _shardingDbContext.GetDbContext(virtualDataSource.DefaultDataSourceName, strategy, routeTailFactory.Create(string.Empty));
var dbContext = _shardingDbContext.GetShardingExecutor().CreateDbContext(strategy,virtualDataSource.DefaultDataSourceName, routeTailFactory.Create(string.Empty));
_queryCompilerExecutor = new QueryCompilerExecutor(dbContext, _queryExpression);
}
}

View File

@ -128,7 +128,7 @@ namespace ShardingCore.Sharding
{
var routeTail = _routeTailFactory.Create(sqlRouteUnit.TableRouteResult);
var dbContext = GetShardingDbContext().GetDbContext(sqlRouteUnit.DataSourceName, CreateDbContextStrategyEnum.IndependentConnectionQuery, routeTail);
var dbContext = GetShardingDbContext().GetShardingExecutor().CreateDbContext(CreateDbContextStrategyEnum.IndependentConnectionQuery,sqlRouteUnit.DataSourceName, routeTail);
_parallelDbContexts.TryAdd(dbContext, null);
return dbContext;

View File

@ -214,11 +214,13 @@ namespace ShardingCore
this DbContextOptionsBuilder optionsBuilder, IShardingRuntimeContext shardingRuntimeContext)
{
return optionsBuilder.UseShardingWrapMark().UseShardingOptions(shardingRuntimeContext)
.ReplaceService<IDbSetSource, ShardingDbSetSource>()
// .ReplaceService<IDbSetSource, ShardingDbSetSource>()
.ReplaceService<IQueryCompiler, ShardingQueryCompiler>()
.ReplaceService<IChangeTrackerFactory, ShardingChangeTrackerFactory>()
.ReplaceService<IDbContextTransactionManager,
ShardingRelationalTransactionManager>()
.ReplaceService<IStateManager,
ShardingStateManager>()
.ReplaceService<IRelationalTransactionFactory,
ShardingRelationalTransactionFactory>();
}

View File

@ -27,6 +27,9 @@
<Compile Include="..\..\src\ShardingCore\**\*.cs" />
<Compile Remove="..\..\src\ShardingCore\obj\**" />
<Compile Remove="..\..\src\ShardingCore\bin\**" />
<Compile Update="..\..\src\ShardingCore\EFCores\EFCore6x\ShardingStateManager.cs">
<Link>EFCores\EFCore6x\ShardingStateManager.cs</Link>
</Compile>
</ItemGroup>