优化简洁调用的代码将重写合并到statemanager
This commit is contained in:
parent
ca0608523e
commit
3875def0fa
|
@ -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; }
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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>()
|
||||
|
|
|
@ -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)
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -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 =>
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -108,7 +108,7 @@ namespace ShardingCore.Extensions
|
|||
new Dictionary<DbContext, IEnumerable<TEntity>>()
|
||||
{
|
||||
{
|
||||
shardingDbContext.CreateGenericDbContext(entitiesArray[0]),
|
||||
shardingDbContext.GetShardingExecutor().CreateGenericDbContext(entitiesArray[0]),
|
||||
entitiesArray
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
||||
|
|
|
@ -52,5 +52,7 @@ namespace ShardingCore.Sharding.Abstractions
|
|||
|
||||
int SaveChanges(bool acceptAllChangesOnSuccess);
|
||||
|
||||
DbContext GetShellDbContext();
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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>();
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue