完成分表分库插件的第一个版本
This commit is contained in:
parent
9530e1bb85
commit
ce80b12158
|
@ -0,0 +1,12 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Sample.SqlServer.DbContexts
|
||||
{
|
||||
public class DefaultDbContext: DbContext
|
||||
{
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
|
|
|
@ -7,6 +7,7 @@ using Microsoft.AspNetCore.Hosting;
|
|||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Sample.SqlServer.DbContexts;
|
||||
using Sample.SqlServer.Shardings;
|
||||
using ShardingCore.SqlServer;
|
||||
|
||||
|
@ -21,14 +22,12 @@ namespace Sample.SqlServer
|
|||
services.AddControllers();
|
||||
services.AddShardingSqlServer(o =>
|
||||
{
|
||||
o.ConnectionString = "";
|
||||
o.AddSharding<SysUserModVirtualRoute>();
|
||||
o.UseShardingCoreConfig((provider, config) =>
|
||||
o.AddShardingDbContext<DefaultDbContext>("conn1","123", dbConfig =>
|
||||
{
|
||||
//如果是development就判断并且新建数据库如果不存在的话
|
||||
config.EnsureCreated = provider.GetService<IHostEnvironment>().IsDevelopment();
|
||||
config.CreateShardingTableOnStart = true;
|
||||
dbConfig.AddShardingTableRoute<SysUserModVirtualRoute>();
|
||||
});
|
||||
//o.AddDataSourceVirtualRoute<>();
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -14,35 +14,35 @@ namespace Samples.AutoByDate.SqlServer.Jobs
|
|||
* @Date: Tuesday, 02 February 2021 17:24:17
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
public class AutoCreateTableByDay : IJob
|
||||
{
|
||||
/// <summary>
|
||||
/// 每天中午12点执行,启动的时候执行以下
|
||||
/// </summary>
|
||||
/// <param name="virtualTableManager"></param>
|
||||
/// <param name="tableCreator"></param>
|
||||
[JobRun(Name = "定时创建分表组件",Cron = "0 0 12 * * ?",RunOnceOnStart = true)]
|
||||
//public class AutoCreateTableByDay : IJob
|
||||
//{
|
||||
// /// <summary>
|
||||
// /// 每天中午12点执行,启动的时候执行以下
|
||||
// /// </summary>
|
||||
// /// <param name="virtualTableManager"></param>
|
||||
// /// <param name="tableCreator"></param>
|
||||
// [JobRun(Name = "定时创建分表组件",Cron = "0 0 12 * * ?",RunOnceOnStart = true)]
|
||||
|
||||
public void AutoCreateTable(IVirtualTableManager virtualTableManager, IShardingTableCreator tableCreator)
|
||||
{
|
||||
var allVirtualTables = virtualTableManager.GetAllVirtualTables();
|
||||
foreach (var virtualTable in allVirtualTables)
|
||||
{
|
||||
if (virtualTable.EntityType == typeof(SysUserLogByDay))
|
||||
{
|
||||
var now = DateTime.Now.Date.AddDays(1);
|
||||
var tail = virtualTable.GetVirtualRoute().ShardingKeyToTail(now);
|
||||
try
|
||||
{
|
||||
tableCreator.CreateTable<SysUserLogByDay>(tail);
|
||||
virtualTableManager.AddPhysicTable(virtualTable, new DefaultPhysicTable(virtualTable, tail));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
//ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// public void AutoCreateTable(IVirtualTableManager virtualTableManager, IShardingTableCreator tableCreator)
|
||||
// {
|
||||
// var allVirtualTables = virtualTableManager.GetAllVirtualTables();
|
||||
// foreach (var virtualTable in allVirtualTables)
|
||||
// {
|
||||
// if (virtualTable.EntityType == typeof(SysUserLogByDay))
|
||||
// {
|
||||
// var now = DateTime.Now.Date.AddDays(1);
|
||||
// var tail = virtualTable.GetVirtualRoute().ShardingKeyToTail(now);
|
||||
// try
|
||||
// {
|
||||
// tableCreator.CreateTable<SysUserLogByDay>(tail);
|
||||
// virtualTableManager.AddPhysicTable(virtualTable, new DefaultPhysicTable(virtualTable, tail));
|
||||
// }
|
||||
// catch (Exception e)
|
||||
// {
|
||||
// //ignore
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
}
|
|
@ -31,17 +31,17 @@ namespace Samples.AutoByDate.SqlServer
|
|||
{
|
||||
services.AddControllers();
|
||||
services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new OpenApiInfo {Title = "Samples.AutoByDate.SqlServer", Version = "v1"}); });
|
||||
services.AddShardingSqlServer(o =>
|
||||
{
|
||||
o.ConnectionString = "";
|
||||
o.AddSharding<SysUserLogByDayVirtualRoute>();
|
||||
o.UseShardingCoreConfig((provider, config) =>
|
||||
{
|
||||
//如果是development就判断并且新建数据库如果不存在的话
|
||||
config.EnsureCreated = provider.GetService<IHostEnvironment>().IsDevelopment();
|
||||
config.CreateShardingTableOnStart = true;
|
||||
});
|
||||
});
|
||||
//services.AddShardingSqlServer(o =>
|
||||
//{
|
||||
// o.ConnectionString = "";
|
||||
// o.AddSharding<SysUserLogByDayVirtualRoute>();
|
||||
// o.UseShardingCoreConfig((provider, config) =>
|
||||
// {
|
||||
// //如果是development就判断并且新建数据库如果不存在的话
|
||||
// config.EnsureCreated = provider.GetService<IHostEnvironment>().IsDevelopment();
|
||||
// config.CreateShardingTableOnStart = true;
|
||||
// });
|
||||
//});
|
||||
services.AddChronusJob();
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ using Microsoft.EntityFrameworkCore;
|
|||
using Microsoft.Extensions.DependencyInjection;
|
||||
using ShardingCore.Core.ShardingAccessors;
|
||||
using ShardingCore.Core.VirtualRoutes;
|
||||
using ShardingCore.Core.VirtualRoutes.TableRoutes;
|
||||
using ShardingCore.Core.VirtualTables;
|
||||
using ShardingCore.DbContexts;
|
||||
using ShardingCore.DbContexts.VirtualDbContexts;
|
||||
|
@ -40,26 +41,10 @@ namespace ShardingCore.MySql
|
|||
|
||||
services.AddScoped<IDbContextOptionsProvider, MySqlDbContextOptionsProvider>();
|
||||
services.AddSingleton<IShardingParallelDbContextFactory, ShardingMySqlParallelDbContextFactory>();
|
||||
if (options.HasSharding)
|
||||
{
|
||||
foreach (var shardingRoute in options.ShardingRoutes)
|
||||
{
|
||||
var genericVirtualRoute = shardingRoute.GetInterfaces().FirstOrDefault(it => it.IsInterface && it.IsGenericType && it.GetGenericTypeDefinition() == typeof(IVirtualRoute<>)
|
||||
&& it.GetGenericArguments().Any());
|
||||
if (genericVirtualRoute == null)
|
||||
throw new ArgumentException("add sharding route type error not assignable from IVirtualRoute<>.");
|
||||
var shardingEntity=genericVirtualRoute.GetGenericArguments()[0];
|
||||
if(!shardingEntity.IsShardingEntity())
|
||||
throw new ArgumentException("add sharding route type error generic arguments first not assignable from IShardingEntity.");
|
||||
Type genericType = typeof(IVirtualRoute<>);
|
||||
Type interfaceType = genericType.MakeGenericType(shardingEntity);
|
||||
services.AddSingleton(interfaceType, shardingRoute);
|
||||
}
|
||||
}
|
||||
|
||||
services.AddSingleton(sp =>
|
||||
{
|
||||
var shardingCoreConfig = new ShardingCoreConfig();
|
||||
options.ShardingCoreConfigConfigure?.Invoke(sp,shardingCoreConfig);
|
||||
return shardingCoreConfig;
|
||||
});
|
||||
services.AddSingleton<IShardingBootstrapper,ShardingBootstrapper>();
|
||||
|
|
|
@ -64,7 +64,7 @@ namespace ShardingCore.MySql.EFCores
|
|||
if (shardingAccessor?.ShardingContext != null)
|
||||
{
|
||||
var virtualTableManager = ShardingContainer.Services.GetService<IVirtualTableManager>();
|
||||
var virtualTable = virtualTableManager.GetAllVirtualTables().FirstOrDefault(o => o.GetOriginalTableName() == tableExpression.Name);
|
||||
var virtualTable = virtualTableManager.GetAllVirtualTables(shardingAccessor.ShardingContext.ConnectKey).FirstOrDefault(o => o.GetOriginalTableName() == tableExpression.Name);
|
||||
if(virtualTable!=null)
|
||||
{
|
||||
var tails = shardingAccessor.ShardingContext.GetContextQueryTails(virtualTable);
|
||||
|
@ -74,7 +74,7 @@ namespace ShardingCore.MySql.EFCores
|
|||
|
||||
if (tails.IsEmpty())
|
||||
{
|
||||
var firstTail = virtualTableManager.GetVirtualTable(tableExpression.Name).GetAllPhysicTables()[0].Tail;
|
||||
var firstTail = virtualTableManager.GetVirtualTable(shardingAccessor.ShardingContext.ConnectKey,tableExpression.Name).GetAllPhysicTables()[0].Tail;
|
||||
newTableName = $"( select * from {sqlGenerationHelper.DelimitIdentifier($"{tableExpression.Name}{tailPrefix}{firstTail}", tableExpression.Schema)} where 1=2 )";
|
||||
}
|
||||
else if (tails.Count == 1)
|
||||
|
@ -173,7 +173,7 @@ namespace ShardingCore.MySql.EFCores
|
|||
if (shardingAccessor?.ShardingContext != null)
|
||||
{
|
||||
var virtualTableManager = ShardingContainer.Services.GetService<IVirtualTableManager>();
|
||||
var virtualTable = virtualTableManager.GetAllVirtualTables().FirstOrDefault(o => o.GetOriginalTableName() == tableExpression.Table);
|
||||
var virtualTable = virtualTableManager.GetAllVirtualTables(shardingAccessor.ShardingContext.ConnectKey).FirstOrDefault(o => o.GetOriginalTableName() == tableExpression.Table);
|
||||
if(virtualTable!=null)
|
||||
{
|
||||
var tails = shardingAccessor.ShardingContext.GetContextQueryTails(virtualTable);
|
||||
|
@ -183,7 +183,7 @@ namespace ShardingCore.MySql.EFCores
|
|||
|
||||
if (tails.IsEmpty())
|
||||
{
|
||||
var firstTail = virtualTableManager.GetVirtualTable(tableExpression.Table).GetAllPhysicTables()[0].Tail;
|
||||
var firstTail = virtualTableManager.GetVirtualTable(shardingAccessor.ShardingContext.ConnectKey,tableExpression.Table).GetAllPhysicTables()[0].Tail;
|
||||
newTableName = $"( select * from {sqlGenerationHelper.DelimitIdentifier($"{tableExpression.Table}{tailPrefix}{firstTail}", tableExpression.Schema)} where 1=2 )";
|
||||
}
|
||||
else if (tails.Count == 1)
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
using System.Collections.Generic;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Query.Internal;
|
||||
|
@ -10,7 +11,9 @@ using MySql.Data.MySqlClient;
|
|||
using MySqlConnector;
|
||||
#endif
|
||||
using ShardingCore.DbContexts.VirtualDbContexts;
|
||||
using ShardingCore.DbContexts.VirtualDbContexts.ShareDbContextOptionsProviders;
|
||||
using ShardingCore.EFCores;
|
||||
using ShardingCore.Extensions;
|
||||
|
||||
namespace ShardingCore.MySql
|
||||
{
|
||||
|
@ -22,34 +25,46 @@ namespace ShardingCore.MySql
|
|||
*/
|
||||
public class MySqlDbContextOptionsProvider:IDbContextOptionsProvider
|
||||
{
|
||||
private DbContextOptions _dbContextOptions;
|
||||
private MySqlConnection _connection;
|
||||
private readonly MySqlOptions _mySqlOptions;
|
||||
private readonly ILoggerFactory _loggerFactory;
|
||||
private readonly IShardingCoreOptions _shardingCoreOptions;
|
||||
|
||||
public MySqlDbContextOptionsProvider(MySqlOptions mySqlOptions,ILoggerFactory loggerFactory)
|
||||
private readonly Dictionary<string, ShareDbContextWrapItem> _contextWrapItems =
|
||||
new Dictionary<string, ShareDbContextWrapItem>();
|
||||
|
||||
public MySqlDbContextOptionsProvider(MySqlOptions mySqlOptions,ILoggerFactory loggerFactory,IShardingCoreOptions shardingCoreOptions)
|
||||
{
|
||||
_connection=new MySqlConnection(mySqlOptions.ConnectionString);
|
||||
_dbContextOptions = new DbContextOptionsBuilder()
|
||||
_mySqlOptions = mySqlOptions;
|
||||
_loggerFactory = loggerFactory;
|
||||
_shardingCoreOptions = shardingCoreOptions;
|
||||
}
|
||||
public DbContextOptions GetDbContextOptions(string connectKey)
|
||||
{
|
||||
if (!_contextWrapItems.ContainsKey(connectKey))
|
||||
{
|
||||
var connectionString = _shardingCoreOptions.GetShardingConfig(connectKey).ConnectionString;
|
||||
var connection = new MySqlConnection(connectionString);
|
||||
var dbContextOptions= new DbContextOptionsBuilder()
|
||||
#if EFCORE5
|
||||
.UseMySql(_connection,mySqlOptions.ServerVersion,mySqlOptions.MySqlOptionsAction)
|
||||
.UseMySql(connection, _mySqlOptions.ServerVersion, _mySqlOptions.MySqlOptionsAction)
|
||||
#endif
|
||||
#if !EFCORE5
|
||||
.UseMySql(_connection,mySqlOptions.MySqlOptionsAction)
|
||||
.UseMySql(connection, _mySqlOptions.MySqlOptionsAction)
|
||||
#endif
|
||||
.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking)
|
||||
.UseLoggerFactory(loggerFactory)
|
||||
.ReplaceService<IQueryCompiler, ShardingQueryCompiler>()
|
||||
.ReplaceService<IModelCacheKeyFactory, ShardingModelCacheKeyFactory>()
|
||||
.UseShardingSqlServerQuerySqlGenerator()
|
||||
.Options;
|
||||
}
|
||||
public DbContextOptions GetDbContextOptions()
|
||||
{
|
||||
return _dbContextOptions;
|
||||
.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking)
|
||||
.UseLoggerFactory(_loggerFactory)
|
||||
.ReplaceService<IQueryCompiler, ShardingQueryCompiler>()
|
||||
.ReplaceService<IModelCacheKeyFactory, ShardingModelCacheKeyFactory>()
|
||||
.UseShardingSqlServerQuerySqlGenerator()
|
||||
.Options;
|
||||
_contextWrapItems.Add(connectKey,new ShareDbContextWrapItem(connection, dbContextOptions));
|
||||
}
|
||||
return _contextWrapItems[connectKey].ContextOptions;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_connection?.Dispose();
|
||||
_contextWrapItems.ForEach(o=>o.Value.Connection?.Dispose());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,8 +1,15 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using ShardingCore.Core.VirtualRoutes;
|
||||
using ShardingCore.Core.VirtualRoutes.DataSourceRoutes;
|
||||
using ShardingCore.Core.VirtualRoutes.TableRoutes;
|
||||
using ShardingCore.DbContexts.ShardingDbContexts;
|
||||
using ShardingCore.Exceptions;
|
||||
using ShardingCore.Extensions;
|
||||
|
||||
namespace ShardingCore.MySql
|
||||
|
@ -15,29 +22,118 @@ namespace ShardingCore.MySql
|
|||
*/
|
||||
public class MySqlOptions
|
||||
{
|
||||
public LinkedList<Type> ShardingRoutes=new LinkedList<Type>();
|
||||
public string ConnectionString { get; set; }
|
||||
#if EFCORE5
|
||||
public MySqlServerVersion ServerVersion { get; set; }
|
||||
#endif
|
||||
|
||||
public Action<MySqlDbContextOptionsBuilder> MySqlOptionsAction { get; set; }
|
||||
|
||||
public void AddSharding<TRoute>()where TRoute:IVirtualRoute
|
||||
{
|
||||
ShardingRoutes.AddLast(typeof(TRoute));
|
||||
}
|
||||
|
||||
public bool HasSharding => ShardingRoutes.IsNotEmpty();
|
||||
public Action<IServiceProvider, ShardingCoreConfig> ShardingCoreConfigConfigure { get; private set; }
|
||||
|
||||
|
||||
public void SetMySqlOptions(Action<MySqlDbContextOptionsBuilder> action)
|
||||
{
|
||||
MySqlOptionsAction = action;
|
||||
}
|
||||
public void CreateIfNotExists(Action<IServiceProvider, ShardingCoreConfig> action)
|
||||
private readonly IDictionary<string, ShardingConfigEntry> _shardingConfigs = new Dictionary<string, ShardingConfigEntry>();
|
||||
|
||||
public void AddShardingDbContext<TContext>(string connectKey, string connectString, Action<ShardingDbConfigOptions> func) where TContext : DbContext
|
||||
{
|
||||
ShardingCoreConfigConfigure = action;
|
||||
if (_shardingConfigs.ContainsKey(connectKey))
|
||||
{
|
||||
throw new ArgumentException($"same connect key:[{connectKey}]");
|
||||
}
|
||||
|
||||
CheckContextConstructors<TContext>();
|
||||
var creator = CreateActivator<TContext>();
|
||||
var config = new ShardingConfigEntry(connectKey, connectString, creator, typeof(TContext), func);
|
||||
_shardingConfigs.Add(connectKey, config);
|
||||
}
|
||||
private static void CheckContextConstructors<TContext>()
|
||||
where TContext : DbContext
|
||||
{
|
||||
var contextType = typeof(TContext);
|
||||
var declaredConstructors = contextType.GetTypeInfo().DeclaredConstructors.ToList();
|
||||
if (!contextType.IsShardingDbContext())
|
||||
{
|
||||
throw new ArgumentException($"dbcontext : {contextType} is assignable from {typeof(AbstractShardingDbContext)} ");
|
||||
}
|
||||
if (declaredConstructors.Count != 1)
|
||||
{
|
||||
throw new ArgumentException($"dbcontext : {contextType} declared constructor count more {contextType}");
|
||||
}
|
||||
if (declaredConstructors[0].GetParameters().Length != 1)
|
||||
{
|
||||
throw new ArgumentException($"dbcontext : {contextType} declared constructor parameters more ");
|
||||
}
|
||||
if (declaredConstructors[0].GetParameters()[0].ParameterType != typeof(ShardingDbContextOptions))
|
||||
{
|
||||
throw new ArgumentException($"dbcontext : {contextType} is assignable from {typeof(AbstractShardingDbContext)} declared constructor parameters should use {typeof(ShardingDbContextOptions)} ");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static Func<ShardingDbContextOptions, DbContext> CreateActivator<TContext>() where TContext : DbContext
|
||||
{
|
||||
var constructors
|
||||
= typeof(TContext).GetTypeInfo().DeclaredConstructors
|
||||
.Where(c => !c.IsStatic && c.IsPublic)
|
||||
.ToArray();
|
||||
|
||||
var parameters = constructors[0].GetParameters();
|
||||
var parameterType = parameters[0].ParameterType;
|
||||
|
||||
var po = Expression.Parameter(parameterType, "o");
|
||||
var new1 = Expression.New(constructors[0], po);
|
||||
var inner = Expression.Lambda(new1, po);
|
||||
|
||||
var args = Expression.Parameter(typeof(ShardingDbContextOptions), "args");
|
||||
var body = Expression.Invoke(inner, Expression.Convert(args, po.Type));
|
||||
var outer = Expression.Lambda<Func<ShardingDbContextOptions, TContext>>(body, args);
|
||||
var func = outer.Compile();
|
||||
return func;
|
||||
}
|
||||
|
||||
public void AddShardingDbContext<T>(string connectKey, string connectString) where T : DbContext
|
||||
{
|
||||
AddShardingDbContext<T>(connectKey, connectString, null);
|
||||
}
|
||||
|
||||
|
||||
private readonly Dictionary<Type, Type> _virtualRoutes = new Dictionary<Type, Type>();
|
||||
public void AddDataSourceVirtualRoute<TRoute>() where TRoute : IDataSourceVirtualRoute
|
||||
{
|
||||
var virtualRouteType = typeof(TRoute);
|
||||
//获取类型
|
||||
var shardingEntityType = virtualRouteType.GetGenericArguments()[0];
|
||||
if (shardingEntityType == null)
|
||||
throw new ArgumentException("add sharding table route type error not assignable from IDataSourceVirtualRoute<>");
|
||||
if (!_virtualRoutes.ContainsKey(shardingEntityType))
|
||||
{
|
||||
_virtualRoutes.Add(shardingEntityType, virtualRouteType);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public ISet<ShardingConfigEntry> GetShardingConfigs()
|
||||
{
|
||||
return _shardingConfigs.Select(o => o.Value).ToHashSet();
|
||||
}
|
||||
|
||||
public ShardingConfigEntry GetShardingConfig(string connectKey)
|
||||
{
|
||||
if (!_shardingConfigs.ContainsKey(connectKey))
|
||||
throw new ShardingConfigNotFoundException(connectKey);
|
||||
return _shardingConfigs[connectKey];
|
||||
}
|
||||
|
||||
public ISet<Type> GetVirtualRoutes()
|
||||
{
|
||||
return _virtualRoutes.Select(o => o.Value).ToHashSet();
|
||||
}
|
||||
|
||||
public Type GetVirtualRoute(Type entityType)
|
||||
{
|
||||
if (!_virtualRoutes.ContainsKey(entityType))
|
||||
throw new ArgumentException("not found IDataSourceVirtualRoute");
|
||||
return _virtualRoutes[entityType];
|
||||
}
|
||||
}
|
||||
}
|
|
@ -18,30 +18,35 @@ namespace ShardingCore.MySql
|
|||
public class ShardingMySqlParallelDbContextFactory : IShardingParallelDbContextFactory
|
||||
{
|
||||
private readonly IVirtualTableManager _virtualTableManager;
|
||||
private readonly IShardingDbContextFactory _shardingDbContextFactory;
|
||||
private readonly IShardingCoreOptions _shardingCoreOptions;
|
||||
private readonly MySqlOptions _mySqlOptions;
|
||||
|
||||
public ShardingMySqlParallelDbContextFactory(IVirtualTableManager virtualTableManager, MySqlOptions mySqlOptions)
|
||||
public ShardingMySqlParallelDbContextFactory(IVirtualTableManager virtualTableManager,IShardingDbContextFactory shardingDbContextFactory,IShardingCoreOptions shardingCoreOptions, MySqlOptions mySqlOptions)
|
||||
{
|
||||
_virtualTableManager = virtualTableManager;
|
||||
_shardingDbContextFactory = shardingDbContextFactory;
|
||||
_shardingCoreOptions = shardingCoreOptions;
|
||||
_mySqlOptions = mySqlOptions;
|
||||
}
|
||||
|
||||
public ShardingDbContext Create(string tail)
|
||||
public DbContext Create(string connectKey, string tail)
|
||||
{
|
||||
var virtualTableConfigs = _virtualTableManager.GetAllVirtualTables().GetVirtualTableDbContextConfigs();
|
||||
var shardingDbContextOptions = new ShardingDbContextOptions(CreateOptions(), tail, virtualTableConfigs);
|
||||
return new ShardingDbContext(shardingDbContextOptions);
|
||||
var shardingConfigEntry = _shardingCoreOptions.GetShardingConfig(connectKey);
|
||||
var virtualTableConfigs = _virtualTableManager.GetAllVirtualTables(connectKey).GetVirtualTableDbContextConfigs();
|
||||
var shardingDbContextOptions = new ShardingDbContextOptions(CreateOptions(shardingConfigEntry.ConnectionString), tail, virtualTableConfigs);
|
||||
return _shardingDbContextFactory.Create(connectKey, shardingDbContextOptions);
|
||||
}
|
||||
|
||||
private DbContextOptions CreateOptions()
|
||||
private DbContextOptions CreateOptions(string connectionString)
|
||||
{
|
||||
return new DbContextOptionsBuilder()
|
||||
#if EFCORE5
|
||||
.UseMySql(_mySqlOptions.ConnectionString,_mySqlOptions.ServerVersion,_mySqlOptions.MySqlOptionsAction)
|
||||
.UseMySql(connectionString,_mySqlOptions.ServerVersion,_mySqlOptions.MySqlOptionsAction)
|
||||
#endif
|
||||
#if !EFCORE5
|
||||
|
||||
.UseMySql(_mySqlOptions.ConnectionString,_mySqlOptions.MySqlOptionsAction)
|
||||
.UseMySql(connectionString, _mySqlOptions.MySqlOptionsAction)
|
||||
#endif
|
||||
.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking)
|
||||
.ReplaceService<IQueryCompiler, ShardingQueryCompiler>()
|
||||
|
|
|
@ -5,6 +5,7 @@ using Microsoft.EntityFrameworkCore.Query;
|
|||
using Microsoft.Extensions.DependencyInjection;
|
||||
using ShardingCore.Core.ShardingAccessors;
|
||||
using ShardingCore.Core.VirtualRoutes;
|
||||
using ShardingCore.Core.VirtualRoutes.TableRoutes;
|
||||
using ShardingCore.Core.VirtualTables;
|
||||
using ShardingCore.DbContexts;
|
||||
using ShardingCore.DbContexts.VirtualDbContexts;
|
||||
|
@ -33,31 +34,15 @@ namespace ShardingCore.SqlServer
|
|||
|
||||
var options = new SqlServerOptions();
|
||||
configure(options);
|
||||
services.AddSingleton(options);
|
||||
services.AddSingleton<IShardingCoreOptions, SqlServerOptions>(sp=> options);
|
||||
services.AddShardingCore();
|
||||
|
||||
services.AddScoped<IDbContextOptionsProvider, SqlServerDbContextOptionsProvider>();
|
||||
services.AddSingleton<IShardingParallelDbContextFactory, ShardingSqlServerParallelDbContextFactory>();
|
||||
if (options.HasSharding)
|
||||
{
|
||||
foreach (var shardingRoute in options.ShardingRoutes)
|
||||
{
|
||||
var genericVirtualRoute = shardingRoute.GetInterfaces().FirstOrDefault(it => it.IsInterface && it.IsGenericType && it.GetGenericTypeDefinition() == typeof(IVirtualRoute<>)
|
||||
&& it.GetGenericArguments().Any());
|
||||
if (genericVirtualRoute == null)
|
||||
throw new ArgumentException("add sharding route type error not assignable from IVirtualRoute<>.");
|
||||
var shardingEntity=genericVirtualRoute.GetGenericArguments()[0];
|
||||
if(!shardingEntity.IsShardingEntity())
|
||||
throw new ArgumentException("add sharding route type error generic arguments first not assignable from IShardingEntity.");
|
||||
Type genericType = typeof(IVirtualRoute<>);
|
||||
Type interfaceType = genericType.MakeGenericType(shardingEntity);
|
||||
services.AddSingleton(interfaceType, shardingRoute);
|
||||
}
|
||||
}
|
||||
|
||||
services.AddSingleton(sp =>
|
||||
{
|
||||
var shardingCoreConfig = new ShardingCoreConfig();
|
||||
options.ShardingCoreConfigConfigure?.Invoke(sp,shardingCoreConfig);
|
||||
return shardingCoreConfig;
|
||||
});
|
||||
services.AddSingleton<IShardingBootstrapper,ShardingBootstrapper>();
|
||||
|
|
|
@ -55,7 +55,7 @@ namespace ShardingCore.SqlServer.EFCores
|
|||
if (shardingAccessor?.ShardingContext != null)
|
||||
{
|
||||
var virtualTableManager = ShardingContainer.Services.GetService<IVirtualTableManager>();
|
||||
var virtualTable = virtualTableManager.GetAllVirtualTables().FirstOrDefault(o => o.GetOriginalTableName() == tableExpression.Name);
|
||||
var virtualTable = virtualTableManager.GetAllVirtualTables(shardingAccessor.ShardingContext.ConnectKey).FirstOrDefault(o => o.GetOriginalTableName() == tableExpression.Name);
|
||||
if(virtualTable!=null)
|
||||
{
|
||||
var tails = shardingAccessor.ShardingContext.GetContextQueryTails(virtualTable);
|
||||
|
@ -65,7 +65,7 @@ namespace ShardingCore.SqlServer.EFCores
|
|||
|
||||
if (tails.IsEmpty())
|
||||
{
|
||||
var firstTail = virtualTableManager.GetVirtualTable(tableExpression.Name).GetAllPhysicTables()[0].Tail;
|
||||
var firstTail = virtualTableManager.GetVirtualTable(shardingAccessor.ShardingContext.ConnectKey,tableExpression.Name).GetAllPhysicTables()[0].Tail;
|
||||
newTableName = $"( select * from {sqlGenerationHelper.DelimitIdentifier($"{tableExpression.Name}{tailPrefix}{firstTail}", tableExpression.Schema)} where 1=2 )";
|
||||
}
|
||||
else if (tails.Count == 1)
|
||||
|
@ -174,7 +174,7 @@ namespace ShardingCore.SqlServer.EFCores
|
|||
if (shardingAccessor?.ShardingContext != null)
|
||||
{
|
||||
var virtualTableManager = ShardingContainer.Services.GetService<IVirtualTableManager>();
|
||||
var virtualTable = virtualTableManager.GetAllVirtualTables().FirstOrDefault(o => o.GetOriginalTableName() == tableExpression.Table);
|
||||
var virtualTable = virtualTableManager.GetAllVirtualTables(shardingAccessor.ShardingContext.ConnectKey).FirstOrDefault(o => o.GetOriginalTableName() == tableExpression.Table);
|
||||
if(virtualTable!=null)
|
||||
{
|
||||
var tails = shardingAccessor.ShardingContext.GetContextQueryTails(virtualTable);
|
||||
|
@ -184,7 +184,7 @@ namespace ShardingCore.SqlServer.EFCores
|
|||
|
||||
if (tails.IsEmpty())
|
||||
{
|
||||
var firstTail = virtualTableManager.GetVirtualTable(tableExpression.Table).GetAllPhysicTables()[0].Tail;
|
||||
var firstTail = virtualTableManager.GetVirtualTable(shardingAccessor.ShardingContext.ConnectKey,tableExpression.Table).GetAllPhysicTables()[0].Tail;
|
||||
newTableName = $"( select * from {sqlGenerationHelper.DelimitIdentifier($"{tableExpression.Table}{tailPrefix}{firstTail}", tableExpression.Schema)} where 1=2 )";
|
||||
}
|
||||
else if (tails.Count == 1)
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Query.Internal;
|
||||
|
@ -18,25 +22,28 @@ namespace ShardingCore.SqlServer
|
|||
public class ShardingSqlServerParallelDbContextFactory : IShardingParallelDbContextFactory
|
||||
{
|
||||
private readonly IVirtualTableManager _virtualTableManager;
|
||||
private readonly SqlServerOptions _sqlServerOptions;
|
||||
private readonly IShardingDbContextFactory _shardingDbContextFactory;
|
||||
private readonly IShardingCoreOptions _shardingCoreOptions;
|
||||
|
||||
public ShardingSqlServerParallelDbContextFactory(IVirtualTableManager virtualTableManager, SqlServerOptions sqlServerOptions)
|
||||
public ShardingSqlServerParallelDbContextFactory(IVirtualTableManager virtualTableManager,IShardingCoreOptions shardingCoreOptions, IShardingDbContextFactory shardingDbContextFactory)
|
||||
{
|
||||
_virtualTableManager = virtualTableManager;
|
||||
_sqlServerOptions = sqlServerOptions;
|
||||
_shardingDbContextFactory = shardingDbContextFactory;
|
||||
_shardingCoreOptions = shardingCoreOptions;
|
||||
}
|
||||
|
||||
public ShardingDbContext Create(string tail)
|
||||
public DbContext Create(string connectKey,string tail)
|
||||
{
|
||||
var virtualTableConfigs = _virtualTableManager.GetAllVirtualTables().GetVirtualTableDbContextConfigs();
|
||||
var shardingDbContextOptions = new ShardingDbContextOptions(CreateOptions(), tail, virtualTableConfigs);
|
||||
return new ShardingDbContext(shardingDbContextOptions);
|
||||
var shardingConfigEntry = _shardingCoreOptions.GetShardingConfig(connectKey);
|
||||
var virtualTableConfigs = _virtualTableManager.GetAllVirtualTables(connectKey).GetVirtualTableDbContextConfigs();
|
||||
var shardingDbContextOptions = new ShardingDbContextOptions(CreateOptions(shardingConfigEntry.ConnectionString), tail, virtualTableConfigs);
|
||||
return _shardingDbContextFactory.Create(connectKey, shardingDbContextOptions);
|
||||
}
|
||||
|
||||
private DbContextOptions CreateOptions()
|
||||
private DbContextOptions CreateOptions(string connectString)
|
||||
{
|
||||
return new DbContextOptionsBuilder()
|
||||
.UseSqlServer(_sqlServerOptions.ConnectionString)
|
||||
.UseSqlServer(connectString)
|
||||
.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking)
|
||||
.ReplaceService<IQueryCompiler, ShardingQueryCompiler>()
|
||||
.ReplaceService<IModelCacheKeyFactory, ShardingModelCacheKeyFactory>()
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
using System.Collections.Generic;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Query.Internal;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using ShardingCore.DbContexts.VirtualDbContexts;
|
||||
using ShardingCore.DbContexts.VirtualDbContexts.ShareDbContextOptionsProviders;
|
||||
using ShardingCore.EFCores;
|
||||
using ShardingCore.Extensions;
|
||||
#if EFCORE2
|
||||
using System.Data.SqlClient;
|
||||
#endif
|
||||
|
@ -21,29 +24,39 @@ namespace ShardingCore.SqlServer
|
|||
*/
|
||||
public class SqlServerDbContextOptionsProvider:IDbContextOptionsProvider
|
||||
{
|
||||
private DbContextOptions _dbContextOptions;
|
||||
private SqlConnection _connection;
|
||||
private readonly ILoggerFactory _loggerFactory;
|
||||
private readonly IShardingCoreOptions _shardingCoreOptions;
|
||||
|
||||
public SqlServerDbContextOptionsProvider(SqlServerOptions sqlServerOptions,ILoggerFactory loggerFactory)
|
||||
private readonly Dictionary<string, ShareDbContextWrapItem> _contextWrapItems =
|
||||
new Dictionary<string, ShareDbContextWrapItem>();
|
||||
|
||||
public SqlServerDbContextOptionsProvider(ILoggerFactory loggerFactory,IShardingCoreOptions shardingCoreOptions)
|
||||
{
|
||||
_connection=new SqlConnection(sqlServerOptions.ConnectionString);
|
||||
_dbContextOptions = new DbContextOptionsBuilder()
|
||||
.UseSqlServer(_connection)
|
||||
.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking)
|
||||
.UseLoggerFactory(loggerFactory)
|
||||
.ReplaceService<IQueryCompiler, ShardingQueryCompiler>()
|
||||
.ReplaceService<IModelCacheKeyFactory, ShardingModelCacheKeyFactory>()
|
||||
.UseShardingSqlServerQuerySqlGenerator()
|
||||
.Options;
|
||||
_loggerFactory = loggerFactory;
|
||||
_shardingCoreOptions = shardingCoreOptions;
|
||||
}
|
||||
public DbContextOptions GetDbContextOptions()
|
||||
public DbContextOptions GetDbContextOptions(string connectKey)
|
||||
{
|
||||
return _dbContextOptions;
|
||||
if (_contextWrapItems.ContainsKey(connectKey))
|
||||
{
|
||||
var connectionString = _shardingCoreOptions.GetShardingConfig(connectKey).ConnectionString;
|
||||
var connection = new SqlConnection(connectionString);
|
||||
var dbContextOptions = new DbContextOptionsBuilder()
|
||||
.UseSqlServer(connection)
|
||||
.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking)
|
||||
.UseLoggerFactory(_loggerFactory)
|
||||
.ReplaceService<IQueryCompiler, ShardingQueryCompiler>()
|
||||
.ReplaceService<IModelCacheKeyFactory, ShardingModelCacheKeyFactory>()
|
||||
.UseShardingSqlServerQuerySqlGenerator()
|
||||
.Options;
|
||||
_contextWrapItems.Add(connectKey, new ShareDbContextWrapItem(connection, dbContextOptions));
|
||||
}
|
||||
return _contextWrapItems[connectKey].ContextOptions;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_connection?.Dispose();
|
||||
_contextWrapItems.ForEach(o => o.Value.Connection?.Dispose());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,17 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Diagnostics;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using ShardingCore.Core;
|
||||
using ShardingCore.Core.VirtualRoutes;
|
||||
using ShardingCore.Core.VirtualRoutes.DataSourceRoutes;
|
||||
using ShardingCore.Core.VirtualRoutes.TableRoutes;
|
||||
using ShardingCore.DbContexts.ShardingDbContexts;
|
||||
using ShardingCore.Exceptions;
|
||||
using ShardingCore.Extensions;
|
||||
|
||||
namespace ShardingCore.SqlServer
|
||||
|
@ -11,21 +22,110 @@ namespace ShardingCore.SqlServer
|
|||
* @Date: 2020年4月7日 8:34:04
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
public class SqlServerOptions
|
||||
public class SqlServerOptions: IShardingCoreOptions
|
||||
{
|
||||
public LinkedList<Type> ShardingRoutes=new LinkedList<Type>();
|
||||
public string ConnectionString { get; set; }
|
||||
private readonly IDictionary<string,ShardingConfigEntry> _shardingConfigs = new Dictionary<string, ShardingConfigEntry>();
|
||||
|
||||
public void AddSharding<TRoute>()where TRoute:IVirtualRoute
|
||||
public void AddShardingDbContext<TContext>(string connectKey,string connectString,Action<ShardingDbConfigOptions> func) where TContext : DbContext
|
||||
{
|
||||
ShardingRoutes.AddLast(typeof(TRoute));
|
||||
if (_shardingConfigs.ContainsKey(connectKey))
|
||||
{
|
||||
throw new ArgumentException($"same connect key:[{connectKey}]");
|
||||
}
|
||||
|
||||
CheckContextConstructors<TContext>();
|
||||
var creator = CreateActivator<TContext>();
|
||||
var config = new ShardingConfigEntry(connectKey, connectString, creator, typeof(TContext), func);
|
||||
_shardingConfigs.Add(connectKey, config);
|
||||
}
|
||||
private static void CheckContextConstructors<TContext>()
|
||||
where TContext : DbContext
|
||||
{
|
||||
var contextType = typeof(TContext);
|
||||
var declaredConstructors = contextType.GetTypeInfo().DeclaredConstructors.ToList();
|
||||
if (!contextType.IsShardingDbContext())
|
||||
{
|
||||
throw new ArgumentException($"dbcontext : {contextType} is assignable from {typeof(AbstractShardingDbContext)} ");
|
||||
}
|
||||
if (declaredConstructors.Count != 1)
|
||||
{
|
||||
throw new ArgumentException($"dbcontext : {contextType} declared constructor count more {contextType}");
|
||||
}
|
||||
if (declaredConstructors[0].GetParameters().Length != 1)
|
||||
{
|
||||
throw new ArgumentException($"dbcontext : {contextType} declared constructor parameters more ");
|
||||
}
|
||||
if (declaredConstructors[0].GetParameters()[0].ParameterType != typeof(ShardingDbContextOptions))
|
||||
{
|
||||
throw new ArgumentException($"dbcontext : {contextType} is assignable from {typeof(AbstractShardingDbContext)} declared constructor parameters should use {typeof(ShardingDbContextOptions)} ");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public bool HasSharding => ShardingRoutes.IsNotEmpty();
|
||||
public Action<IServiceProvider, ShardingCoreConfig> ShardingCoreConfigConfigure { get; private set; }
|
||||
public void UseShardingCoreConfig(Action<IServiceProvider, ShardingCoreConfig> function)
|
||||
private static Func<ShardingDbContextOptions, DbContext> CreateActivator<TContext>() where TContext:DbContext
|
||||
{
|
||||
ShardingCoreConfigConfigure = function;
|
||||
var constructors
|
||||
= typeof(TContext).GetTypeInfo().DeclaredConstructors
|
||||
.Where(c => !c.IsStatic && c.IsPublic)
|
||||
.ToArray();
|
||||
|
||||
var parameters = constructors[0].GetParameters();
|
||||
var parameterType=parameters[0].ParameterType;
|
||||
|
||||
var po = Expression.Parameter(parameterType, "o");
|
||||
var new1 = Expression.New(constructors[0], po);
|
||||
var inner = Expression.Lambda(new1, po);
|
||||
|
||||
var args = Expression.Parameter(typeof(ShardingDbContextOptions), "args");
|
||||
var body = Expression.Invoke(inner, Expression.Convert(args, po.Type));
|
||||
var outer = Expression.Lambda<Func<ShardingDbContextOptions, TContext>>(body, args);
|
||||
var func = outer.Compile();
|
||||
return func;
|
||||
}
|
||||
|
||||
public void AddShardingDbContext<T>(string connectKey, string connectString) where T : DbContext
|
||||
{
|
||||
AddShardingDbContext<T>(connectKey, connectString,null);
|
||||
}
|
||||
|
||||
|
||||
private readonly Dictionary<Type,Type> _virtualRoutes = new Dictionary<Type, Type>();
|
||||
public void AddDataSourceVirtualRoute<TRoute>() where TRoute : IDataSourceVirtualRoute
|
||||
{
|
||||
var virtualRouteType = typeof(TRoute);
|
||||
//获取类型
|
||||
var shardingEntityType = virtualRouteType.GetGenericArguments()[0];
|
||||
if (shardingEntityType == null)
|
||||
throw new ArgumentException("add sharding table route type error not assignable from IDataSourceVirtualRoute<>");
|
||||
if (!_virtualRoutes.ContainsKey(shardingEntityType))
|
||||
{
|
||||
_virtualRoutes.Add(shardingEntityType,virtualRouteType);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public ISet<ShardingConfigEntry> GetShardingConfigs()
|
||||
{
|
||||
return _shardingConfigs.Select(o=>o.Value).ToHashSet();
|
||||
}
|
||||
|
||||
public ShardingConfigEntry GetShardingConfig(string connectKey)
|
||||
{
|
||||
if (!_shardingConfigs.ContainsKey(connectKey))
|
||||
throw new ShardingConfigNotFoundException(connectKey);
|
||||
return _shardingConfigs[connectKey];
|
||||
}
|
||||
|
||||
public ISet<Type> GetVirtualRoutes()
|
||||
{
|
||||
return _virtualRoutes.Select(o=>o.Value).ToHashSet();
|
||||
}
|
||||
|
||||
public Type GetVirtualRoute(Type entityType)
|
||||
{
|
||||
if (!_virtualRoutes.ContainsKey(entityType))
|
||||
throw new ArgumentException("not found IDataSourceVirtualRoute");
|
||||
return _virtualRoutes[entityType];
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace ShardingCore.Core.DataSourceAccessors
|
||||
{
|
||||
/*
|
||||
* @Author: xjm
|
||||
* @Description:
|
||||
* @Date: 2021/3/1 16:32:30
|
||||
* @Ver: 1.0
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
/// <summary>
|
||||
/// 创建数据库数据
|
||||
/// </summary>
|
||||
public class DataSourceAccessor: IDataSourceAccessor
|
||||
{
|
||||
public DbContext CreateDbContext()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace ShardingCore.Core.DataSourceAccessors
|
||||
{
|
||||
/*
|
||||
* @Author: xjm
|
||||
* @Description:
|
||||
* @Date: 2021/3/1 16:11:10
|
||||
* @Ver: 1.0
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
/// <summary>
|
||||
/// 数据访问器上下文
|
||||
/// </summary>
|
||||
public class DataSourceAccessorContext<T>
|
||||
{
|
||||
private readonly IQueryable<T> _queryable;
|
||||
|
||||
public DataSourceAccessorContext(IQueryable<T> queryable)
|
||||
{
|
||||
_queryable = queryable;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using ShardingCore.Core.Internal.RoutingRuleEngines;
|
||||
|
||||
namespace ShardingCore.Core.DataSourceAccessors
|
||||
{
|
||||
/*
|
||||
* @Author: xjm
|
||||
* @Description:
|
||||
* @Date: 2021/3/1 16:27:03
|
||||
* @Ver: 1.0
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
public class DataSourceRouteResult
|
||||
{
|
||||
public DataSourceRouteResult()
|
||||
{
|
||||
|
||||
}
|
||||
public IEnumerable<RouteResult> TableRouteResults { get; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace ShardingCore.Core.DataSourceAccessors
|
||||
{
|
||||
/*
|
||||
* @Author: xjm
|
||||
* @Description:
|
||||
* @Date: 2021/3/1 16:23:13
|
||||
* @Ver: 1.0
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
/// <summary>
|
||||
/// 分库数据路由规则引擎
|
||||
/// </summary>
|
||||
public interface IDataSourceRouteRuleEngine
|
||||
{
|
||||
|
||||
}
|
||||
}
|
|
@ -13,8 +13,8 @@ namespace ShardingCore.Core.Internal.RoutingRuleEngines
|
|||
public interface IRoutingRuleEngineFactory
|
||||
{
|
||||
IRouteRuleEngine CreateEngine();
|
||||
RouteRuleContext<T> CreateContext<T>(IQueryable<T> queryable);
|
||||
IEnumerable<RouteResult> Route<T>(IQueryable<T> queryable);
|
||||
IEnumerable<RouteResult> Route<T>(IQueryable<T> queryable,RouteRuleContext<T> ruleContext);
|
||||
RouteRuleContext<T> CreateContext<T>(string connectKey,IQueryable<T> queryable);
|
||||
IEnumerable<RouteResult> Route<T>(string connectKey, IQueryable<T> queryable);
|
||||
IEnumerable<RouteResult> Route<T>(string connectKey, IQueryable<T> queryable,RouteRuleContext<T> ruleContext);
|
||||
}
|
||||
}
|
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||
using System.Linq;
|
||||
using ShardingCore.Core.PhysicTables;
|
||||
using ShardingCore.Core.VirtualRoutes;
|
||||
using ShardingCore.Core.VirtualRoutes.TableRoutes;
|
||||
using ShardingCore.Core.VirtualTables;
|
||||
using ShardingCore.Extensions;
|
||||
#if !EFCORE5
|
||||
|
@ -30,29 +31,14 @@ namespace ShardingCore.Core.Internal.RoutingRuleEngines
|
|||
{
|
||||
Dictionary<IVirtualTable, ISet<IPhysicTable>> routeMaps = new Dictionary<IVirtualTable, ISet<IPhysicTable>>();
|
||||
var queryEntities = routeRuleContext.Queryable.ParseQueryableRoute();
|
||||
//先添加手动路由到当前上下文,之后将不再手动路由里面的自动路由添加到当前上下文
|
||||
foreach (var kv in routeRuleContext.ManualTails)
|
||||
|
||||
|
||||
var shardingEntities = queryEntities.Where(o => o.IsShardingTable());
|
||||
foreach (var shardingEntity in shardingEntities)
|
||||
{
|
||||
var virtualTable = kv.Key;
|
||||
var addTails = kv.Value;
|
||||
var physicTables = virtualTable.GetAllPhysicTables().Where(o=>addTails.Contains(o.Tail));
|
||||
if (!routeMaps.ContainsKey(virtualTable))
|
||||
{
|
||||
routeMaps.Add(virtualTable,physicTables.ToHashSet());
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var physicTable in physicTables)
|
||||
{
|
||||
routeMaps[virtualTable].Add(physicTable);
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach (var kv in routeRuleContext.ManualPredicate)
|
||||
{
|
||||
var virtualTable = kv.Key;
|
||||
var predicate = kv.Value;
|
||||
var physicTables = virtualTable.RouteTo(new RouteConfig(null, null, null, predicate));
|
||||
var virtualTable = _virtualTableManager.GetVirtualTable(routeRuleContext.ConnectKey,shardingEntity);
|
||||
|
||||
var physicTables = virtualTable.RouteTo(new TableRouteConfig(routeRuleContext.Queryable));
|
||||
if (!routeMaps.ContainsKey(virtualTable))
|
||||
{
|
||||
routeMaps.Add(virtualTable, physicTables.ToHashSet());
|
||||
|
@ -65,28 +51,63 @@ namespace ShardingCore.Core.Internal.RoutingRuleEngines
|
|||
}
|
||||
}
|
||||
}
|
||||
////先添加手动路由到当前上下文,之后将不再手动路由里面的自动路由添加到当前上下文
|
||||
//foreach (var kv in routeRuleContext.ManualTails)
|
||||
//{
|
||||
// var virtualTable = kv.Key;
|
||||
// var addTails = kv.Value;
|
||||
// var physicTables = virtualTable.GetAllPhysicTables().Where(o=>addTails.Contains(o.Tail));
|
||||
// if (!routeMaps.ContainsKey(virtualTable))
|
||||
// {
|
||||
// routeMaps.Add(virtualTable,physicTables.ToHashSet());
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// foreach (var physicTable in physicTables)
|
||||
// {
|
||||
// routeMaps[virtualTable].Add(physicTable);
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
//foreach (var kv in routeRuleContext.ManualPredicate)
|
||||
//{
|
||||
// var virtualTable = kv.Key;
|
||||
// var predicate = kv.Value;
|
||||
// var physicTables = virtualTable.RouteTo(new TableRouteConfig(null, null, null, predicate));
|
||||
// if (!routeMaps.ContainsKey(virtualTable))
|
||||
// {
|
||||
// routeMaps.Add(virtualTable, physicTables.ToHashSet());
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// foreach (var physicTable in physicTables)
|
||||
// {
|
||||
// routeMaps[virtualTable].Add(physicTable);
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
if (routeRuleContext.AutoParseRoute)
|
||||
{
|
||||
var shardingEntities = queryEntities.Where(o => o.IsShardingEntity());
|
||||
foreach (var shardingEntity in shardingEntities)
|
||||
{
|
||||
var virtualTable = _virtualTableManager.GetVirtualTable(shardingEntity);
|
||||
//if (routeRuleContext.AutoParseRoute)
|
||||
//{
|
||||
// var shardingEntities = queryEntities.Where(o => o.IsShardingTable());
|
||||
// foreach (var shardingEntity in shardingEntities)
|
||||
// {
|
||||
// var virtualTable = _virtualTableManager.GetVirtualTable(shardingEntity);
|
||||
|
||||
var physicTables = virtualTable.RouteTo(new RouteConfig(routeRuleContext.Queryable));
|
||||
if (!routeMaps.ContainsKey(virtualTable))
|
||||
{
|
||||
routeMaps.Add(virtualTable, physicTables.ToHashSet());
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var physicTable in physicTables)
|
||||
{
|
||||
routeMaps[virtualTable].Add(physicTable);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// var physicTables = virtualTable.RouteTo(new TableRouteConfig(routeRuleContext.Queryable));
|
||||
// if (!routeMaps.ContainsKey(virtualTable))
|
||||
// {
|
||||
// routeMaps.Add(virtualTable, physicTables.ToHashSet());
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// foreach (var physicTable in physicTables)
|
||||
// {
|
||||
// routeMaps[virtualTable].Add(physicTable);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
return routeMaps.Select(o => o.Value).Cartesian().Select(o=>new RouteResult(o));
|
||||
}
|
||||
|
|
|
@ -1,36 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace ShardingCore.Core.Internal.RoutingRuleEngines
|
||||
{
|
||||
/*
|
||||
* @Author: xjm
|
||||
* @Description:
|
||||
* @Date: Thursday, 28 January 2021 10:53:55
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
public class RouteRuleConfig
|
||||
{
|
||||
private bool _autoParseRoute = true;
|
||||
|
||||
public bool GetAutoParseRoute()
|
||||
{
|
||||
return _autoParseRoute;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 启用自动路由
|
||||
/// </summary>
|
||||
public void EnableAutoRouteParse()
|
||||
{
|
||||
_autoParseRoute = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 禁用自动路由
|
||||
/// </summary>
|
||||
public void DisableAutoRouteParse()
|
||||
{
|
||||
_autoParseRoute = false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -16,84 +16,86 @@ namespace ShardingCore.Core.Internal.RoutingRuleEngines
|
|||
{
|
||||
private readonly IVirtualTableManager _virtualTableManager;
|
||||
|
||||
public RouteRuleContext(IQueryable<T> queryable, IVirtualTableManager virtualTableManager)
|
||||
public RouteRuleContext(string connectKey,IQueryable<T> queryable, IVirtualTableManager virtualTableManager)
|
||||
{
|
||||
ConnectKey = connectKey;
|
||||
Queryable = queryable;
|
||||
_virtualTableManager = virtualTableManager;
|
||||
}
|
||||
|
||||
public string ConnectKey { get; }
|
||||
public IQueryable<T> Queryable { get; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public readonly Dictionary<IVirtualTable, Expression> ManualPredicate = new Dictionary<IVirtualTable, Expression>();
|
||||
public readonly Dictionary<IVirtualTable, ISet<string>> ManualTails = new Dictionary<IVirtualTable, ISet<string>>();
|
||||
///// <summary>
|
||||
/////
|
||||
///// </summary>
|
||||
//public readonly Dictionary<IVirtualTable, Expression> ManualPredicate = new Dictionary<IVirtualTable, Expression>();
|
||||
//public readonly Dictionary<IVirtualTable, ISet<string>> ManualTails = new Dictionary<IVirtualTable, ISet<string>>();
|
||||
|
||||
public bool AutoParseRoute = true;
|
||||
//public bool AutoParseRoute = true;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 启用自动路由
|
||||
/// </summary>
|
||||
public void EnableAutoRouteParse()
|
||||
{
|
||||
AutoParseRoute = true;
|
||||
}
|
||||
///// <summary>
|
||||
///// 启用自动路由
|
||||
///// </summary>
|
||||
//public void EnableAutoRouteParse()
|
||||
//{
|
||||
// AutoParseRoute = true;
|
||||
//}
|
||||
|
||||
/// <summary>
|
||||
/// 禁用自动路由
|
||||
/// </summary>
|
||||
public void DisableAutoRouteParse()
|
||||
{
|
||||
AutoParseRoute = false;
|
||||
}
|
||||
///// <summary>
|
||||
///// 禁用自动路由
|
||||
///// </summary>
|
||||
//public void DisableAutoRouteParse()
|
||||
//{
|
||||
// AutoParseRoute = false;
|
||||
//}
|
||||
|
||||
/// <summary>
|
||||
/// 添加手动路由
|
||||
/// </summary>
|
||||
/// <param name="predicate"></param>
|
||||
/// <typeparam name="TShardingEntity"></typeparam>
|
||||
public void AddRoute<TShardingEntity>(Expression<Func<TShardingEntity, bool>> predicate) where TShardingEntity : class, IShardingEntity
|
||||
{
|
||||
var virtualTable = _virtualTableManager.GetVirtualTable<TShardingEntity>();
|
||||
if (!ManualPredicate.ContainsKey(virtualTable))
|
||||
{
|
||||
ShardingCore.Extensions.ExpressionExtension.And((Expression<Func<TShardingEntity, bool>>) ManualPredicate[virtualTable], predicate);
|
||||
}
|
||||
else
|
||||
{
|
||||
ManualPredicate.Add(virtualTable, predicate);
|
||||
}
|
||||
}
|
||||
public void AddRoute(Type shardingEntityType,string tail)
|
||||
{
|
||||
var virtualTable = _virtualTableManager.GetVirtualTable(shardingEntityType);
|
||||
AddRoute(virtualTable, tail);
|
||||
}
|
||||
///// <summary>
|
||||
///// 添加手动路由
|
||||
///// </summary>
|
||||
///// <param name="predicate"></param>
|
||||
///// <typeparam name="TShardingEntity"></typeparam>
|
||||
//public void AddRoute<TShardingEntity>(Expression<Func<TShardingEntity, bool>> predicate) where TShardingEntity : class, IShardingEntity
|
||||
//{
|
||||
// var virtualTable = _virtualTableManager.GetVirtualTable<TShardingEntity>();
|
||||
// if (!ManualPredicate.ContainsKey(virtualTable))
|
||||
// {
|
||||
// ShardingCore.Extensions.ExpressionExtension.And((Expression<Func<TShardingEntity, bool>>) ManualPredicate[virtualTable], predicate);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// ManualPredicate.Add(virtualTable, predicate);
|
||||
// }
|
||||
//}
|
||||
//public void AddRoute(Type shardingEntityType,string tail)
|
||||
//{
|
||||
// var virtualTable = _virtualTableManager.GetVirtualTable(shardingEntityType);
|
||||
// AddRoute(virtualTable, tail);
|
||||
//}
|
||||
|
||||
public void AddRoute<TShardingEntity>(string tail) where TShardingEntity : class, IShardingEntity
|
||||
{
|
||||
AddRoute(typeof(TShardingEntity), tail);
|
||||
}
|
||||
//public void AddRoute<TShardingEntity>(string tail) where TShardingEntity : class, IShardingEntity
|
||||
//{
|
||||
// AddRoute(typeof(TShardingEntity), tail);
|
||||
//}
|
||||
|
||||
public void AddRoute(IVirtualTable virtualTable, string tail)
|
||||
{
|
||||
if (ManualTails.ContainsKey(virtualTable))
|
||||
{
|
||||
var tails = ManualTails[virtualTable];
|
||||
if (!tails.Contains(tail))
|
||||
{
|
||||
tails.Add(tail);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ManualTails.Add(virtualTable, new HashSet<string>()
|
||||
{
|
||||
tail
|
||||
});
|
||||
}
|
||||
}
|
||||
//public void AddRoute(IVirtualTable virtualTable, string tail)
|
||||
//{
|
||||
// if (ManualTails.ContainsKey(virtualTable))
|
||||
// {
|
||||
// var tails = ManualTails[virtualTable];
|
||||
// if (!tails.Contains(tail))
|
||||
// {
|
||||
// tails.Add(tail);
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// ManualTails.Add(virtualTable, new HashSet<string>()
|
||||
// {
|
||||
// tail
|
||||
// });
|
||||
// }
|
||||
//}
|
||||
}
|
||||
}
|
|
@ -27,19 +27,19 @@ namespace ShardingCore.Core.Internal.RoutingRuleEngines
|
|||
return _routeRuleEngine;
|
||||
}
|
||||
|
||||
public RouteRuleContext<T> CreateContext<T>(IQueryable<T> queryable)
|
||||
public RouteRuleContext<T> CreateContext<T>(string connectKey, IQueryable<T> queryable)
|
||||
{
|
||||
return new RouteRuleContext<T>(queryable, _virtualTableManager);
|
||||
return new RouteRuleContext<T>(connectKey,queryable, _virtualTableManager);
|
||||
}
|
||||
|
||||
public IEnumerable<RouteResult> Route<T>(IQueryable<T> queryable)
|
||||
public IEnumerable<RouteResult> Route<T>(string connectKey, IQueryable<T> queryable)
|
||||
{
|
||||
var engine = CreateEngine();
|
||||
var ruleContext = CreateContext<T>(queryable);
|
||||
var ruleContext = CreateContext<T>(connectKey,queryable);
|
||||
return engine.Route(ruleContext);
|
||||
}
|
||||
|
||||
public IEnumerable<RouteResult> Route<T>(IQueryable<T> queryable, RouteRuleContext<T> ruleContext)
|
||||
public IEnumerable<RouteResult> Route<T>(string connectKey, IQueryable<T> queryable, RouteRuleContext<T> ruleContext)
|
||||
{
|
||||
var engine = CreateEngine();
|
||||
return engine.Route(ruleContext);
|
||||
|
|
|
@ -28,11 +28,11 @@ namespace ShardingCore.Core.Internal.StreamMerge.GenericMerges
|
|||
return new GenericInMemoryMergeEngine<T>(mergeContext);
|
||||
}
|
||||
|
||||
private async Task<TResult> EFCoreExecute<TResult>(IQueryable<T> newQueryable,RouteResult routeResult,Func<IQueryable, Task<TResult>> efQuery)
|
||||
private async Task<TResult> EFCoreExecute<TResult>(string connectKey,IQueryable<T> newQueryable,RouteResult routeResult,Func<IQueryable, Task<TResult>> efQuery)
|
||||
{
|
||||
using (var scope = _mergeContext.CreateScope())
|
||||
{
|
||||
scope.ShardingAccessor.ShardingContext = ShardingContext.Create(routeResult);
|
||||
scope.ShardingAccessor.ShardingContext = ShardingContext.Create(connectKey,routeResult);
|
||||
return await efQuery(newQueryable);
|
||||
}
|
||||
}
|
||||
|
@ -41,27 +41,32 @@ namespace ShardingCore.Core.Internal.StreamMerge.GenericMerges
|
|||
if (_mergeContext.Skip.HasValue || _mergeContext.Take.HasValue)
|
||||
throw new InvalidOperationException("aggregate not support skip take");
|
||||
//从各个分表获取数据
|
||||
List<DbContext> parallelDbContexts = new List<DbContext>(_mergeContext.RouteResults.Count());
|
||||
ICollection<DbContext> parallelDbContexts = new LinkedList<DbContext>();
|
||||
try
|
||||
{
|
||||
var enumeratorTasks = _mergeContext.RouteResults.Select(routeResult =>
|
||||
|
||||
var enumeratorTasks = _mergeContext.GetDataSourceRoutingResult().IntersectConfigs.SelectMany(connectKey =>
|
||||
{
|
||||
return Task.Run(async () =>
|
||||
return _mergeContext.GetRouteResults(connectKey).Select(routeResult =>
|
||||
{
|
||||
var shardingDbContext = _mergeContext.CreateDbContext();
|
||||
parallelDbContexts.Add(shardingDbContext);
|
||||
var newQueryable = (IQueryable<T>) _mergeContext.GetReWriteQueryable().ReplaceDbContextQueryable(shardingDbContext);
|
||||
|
||||
return await EFCoreExecute(newQueryable,routeResult,efQuery);
|
||||
return Task.Run(async () =>
|
||||
{
|
||||
var shardingDbContext = _mergeContext.CreateDbContext(connectKey);
|
||||
parallelDbContexts.Add(shardingDbContext);
|
||||
var newQueryable = (IQueryable<T>)_mergeContext.GetReWriteQueryable()
|
||||
.ReplaceDbContextQueryable(shardingDbContext);
|
||||
|
||||
return await EFCoreExecute(connectKey,newQueryable, routeResult, efQuery);
|
||||
});
|
||||
});
|
||||
}).ToArray();
|
||||
|
||||
return (await Task.WhenAll(enumeratorTasks)).ToList();
|
||||
}
|
||||
finally
|
||||
{
|
||||
parallelDbContexts.ForEach(o => o.Dispose());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -24,12 +24,12 @@ namespace ShardingCore.Core.Internal.StreamMerge.GenericMerges
|
|||
internal class GenericStreamMergeEngine<T> : IStreamMergeEngine<T>
|
||||
{
|
||||
private readonly StreamMergeContext<T> _mergeContext;
|
||||
private readonly List<DbContext> _parallelDbContexts;
|
||||
private readonly ICollection<DbContext> _parallelDbContexts;
|
||||
|
||||
public GenericStreamMergeEngine(StreamMergeContext<T> mergeContext)
|
||||
{
|
||||
_mergeContext = mergeContext;
|
||||
_parallelDbContexts = new List<DbContext>(mergeContext.RouteResults.Count());
|
||||
_parallelDbContexts = new LinkedList<DbContext>();
|
||||
}
|
||||
|
||||
public static GenericStreamMergeEngine<T> Create<T>(StreamMergeContext<T> mergeContext)
|
||||
|
@ -37,11 +37,11 @@ namespace ShardingCore.Core.Internal.StreamMerge.GenericMerges
|
|||
return new GenericStreamMergeEngine<T>(mergeContext);
|
||||
}
|
||||
|
||||
private async Task<IAsyncEnumerator<T>> GetAsyncEnumerator(IQueryable<T> newQueryable, RouteResult routeResult)
|
||||
private async Task<IAsyncEnumerator<T>> GetAsyncEnumerator(string connectKey,IQueryable<T> newQueryable, RouteResult routeResult)
|
||||
{
|
||||
using (var scope = _mergeContext.CreateScope())
|
||||
{
|
||||
scope.ShardingAccessor.ShardingContext = ShardingContext.Create(routeResult);
|
||||
scope.ShardingAccessor.ShardingContext = ShardingContext.Create(connectKey,routeResult);
|
||||
#if !EFCORE2
|
||||
var enumator = newQueryable.AsAsyncEnumerable().GetAsyncEnumerator();
|
||||
await enumator.MoveNextAsync();
|
||||
|
@ -56,18 +56,23 @@ namespace ShardingCore.Core.Internal.StreamMerge.GenericMerges
|
|||
|
||||
public async Task<IStreamMergeAsyncEnumerator<T>> GetStreamEnumerator()
|
||||
{
|
||||
var enumeratorTasks = _mergeContext.RouteResults.Select(routeResult =>
|
||||
var enumeratorTasks = _mergeContext.GetDataSourceRoutingResult().IntersectConfigs.SelectMany(connectKey =>
|
||||
{
|
||||
return Task.Run(async () =>
|
||||
return _mergeContext.GetRouteResults(connectKey).Select(routeResult =>
|
||||
{
|
||||
var shardingDbContext = _mergeContext.CreateDbContext();
|
||||
_parallelDbContexts.Add(shardingDbContext);
|
||||
var newQueryable = (IQueryable<T>) _mergeContext.GetReWriteQueryable().ReplaceDbContextQueryable(shardingDbContext);
|
||||
return Task.Run(async () =>
|
||||
{
|
||||
var shardingDbContext = _mergeContext.CreateDbContext(connectKey);
|
||||
_parallelDbContexts.Add(shardingDbContext);
|
||||
var newQueryable = (IQueryable<T>) _mergeContext.GetReWriteQueryable()
|
||||
.ReplaceDbContextQueryable(shardingDbContext);
|
||||
|
||||
var asyncEnumerator = await GetAsyncEnumerator(newQueryable, routeResult);
|
||||
return new StreamMergeAsyncEnumerator<T>(asyncEnumerator);
|
||||
var asyncEnumerator = await GetAsyncEnumerator(connectKey,newQueryable, routeResult);
|
||||
return new StreamMergeAsyncEnumerator<T>(asyncEnumerator);
|
||||
});
|
||||
});
|
||||
}).ToArray();
|
||||
|
||||
var streamEnumerators = await Task.WhenAll(enumeratorTasks);
|
||||
if (_mergeContext.HasSkipTake())
|
||||
return new NoPaginationStreamMergeEnumerator<T>(_mergeContext,streamEnumerators );
|
||||
|
|
|
@ -2,6 +2,7 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using ShardingCore.Core.Internal.RoutingRuleEngines;
|
||||
using ShardingCore.Core.VirtualRoutes.DataSourceRoutes.RoutingRuleEngine;
|
||||
|
||||
namespace ShardingCore.Core.Internal.StreamMerge
|
||||
{
|
||||
|
@ -13,8 +14,8 @@ namespace ShardingCore.Core.Internal.StreamMerge
|
|||
*/
|
||||
internal interface IStreamMergeContextFactory
|
||||
{
|
||||
StreamMergeContext<T> Create<T>(IQueryable<T> queryable, IEnumerable<RouteResult> routeResults);
|
||||
//StreamMergeContext<T> Create<T>(IQueryable<T> queryable, DataSourceRoutingResult dataSourceRoutingResult);
|
||||
StreamMergeContext<T> Create<T>(IQueryable<T> queryable);
|
||||
StreamMergeContext<T> Create<T>(IQueryable<T> queryable, RouteRuleContext<T> ruleContext);
|
||||
StreamMergeContext<T> Create<T>(IQueryable<T> queryable, DataSourceRoutingRuleContext<T> ruleContext);
|
||||
}
|
||||
}
|
|
@ -7,6 +7,7 @@ using ShardingCore.Core.Internal.Visitors;
|
|||
using ShardingCore.Core.Internal.Visitors.GroupBys;
|
||||
using ShardingCore.Core.Internal.Visitors.Selects;
|
||||
using ShardingCore.Core.ShardingAccessors;
|
||||
using ShardingCore.Core.VirtualRoutes.DataSourceRoutes.RoutingRuleEngine;
|
||||
using ShardingCore.DbContexts;
|
||||
using ShardingCore.Extensions;
|
||||
|
||||
|
@ -23,8 +24,12 @@ namespace ShardingCore.Core.Internal.StreamMerge
|
|||
private readonly IShardingParallelDbContextFactory _shardingParallelDbContextFactory;
|
||||
private readonly IShardingScopeFactory _shardingScopeFactory;
|
||||
private readonly IQueryable<T> _source;
|
||||
private readonly IDataSourceRoutingRuleEngineFactory _dataSourceRoutingRuleEngineFactory;
|
||||
private readonly IRoutingRuleEngineFactory _tableRoutingRuleEngineFactory;
|
||||
|
||||
private readonly IQueryable<T> _reWriteSource;
|
||||
public IEnumerable<RouteResult> RouteResults { get; }
|
||||
//public IEnumerable<RouteResult> RouteResults { get; }
|
||||
//public DataSourceRoutingResult RoutingResult { get; }
|
||||
public int? Skip { get; private set; }
|
||||
public int? Take { get; private set; }
|
||||
public IEnumerable<PropertyOrder> Orders { get; private set; }
|
||||
|
@ -32,13 +37,14 @@ namespace ShardingCore.Core.Internal.StreamMerge
|
|||
public SelectContext SelectContext { get; private set; }
|
||||
public GroupByContext GroupByContext { get; private set; }
|
||||
|
||||
public StreamMergeContext(IQueryable<T> source,IEnumerable<RouteResult> routeResults,
|
||||
public StreamMergeContext(IQueryable<T> source, IDataSourceRoutingRuleEngineFactory dataSourceRoutingRuleEngineFactory,IRoutingRuleEngineFactory tableRoutingRuleEngineFactory,
|
||||
IShardingParallelDbContextFactory shardingParallelDbContextFactory,IShardingScopeFactory shardingScopeFactory)
|
||||
{
|
||||
_shardingParallelDbContextFactory = shardingParallelDbContextFactory;
|
||||
_shardingScopeFactory = shardingScopeFactory;
|
||||
_source = source;
|
||||
RouteResults = routeResults;
|
||||
_dataSourceRoutingRuleEngineFactory = dataSourceRoutingRuleEngineFactory;
|
||||
_tableRoutingRuleEngineFactory = tableRoutingRuleEngineFactory;
|
||||
var reWriteResult = new ReWriteEngine<T>(source).ReWrite();
|
||||
Skip = reWriteResult.Skip;
|
||||
Take = reWriteResult.Take;
|
||||
|
@ -47,10 +53,34 @@ namespace ShardingCore.Core.Internal.StreamMerge
|
|||
GroupByContext = reWriteResult.GroupByContext;
|
||||
_reWriteSource = reWriteResult.ReWriteQueryable;
|
||||
}
|
||||
//public StreamMergeContext(IQueryable<T> source,IEnumerable<RouteResult> routeResults,
|
||||
// IShardingParallelDbContextFactory shardingParallelDbContextFactory,IShardingScopeFactory shardingScopeFactory)
|
||||
//{
|
||||
// _shardingParallelDbContextFactory = shardingParallelDbContextFactory;
|
||||
// _shardingScopeFactory = shardingScopeFactory;
|
||||
// _source = source;
|
||||
// RouteResults = routeResults;
|
||||
// var reWriteResult = new ReWriteEngine<T>(source).ReWrite();
|
||||
// Skip = reWriteResult.Skip;
|
||||
// Take = reWriteResult.Take;
|
||||
// Orders = reWriteResult.Orders ?? Enumerable.Empty<PropertyOrder>();
|
||||
// SelectContext = reWriteResult.SelectContext;
|
||||
// GroupByContext = reWriteResult.GroupByContext;
|
||||
// _reWriteSource = reWriteResult.ReWriteQueryable;
|
||||
//}
|
||||
|
||||
public DbContext CreateDbContext()
|
||||
public DbContext CreateDbContext(string connectKey)
|
||||
{
|
||||
return _shardingParallelDbContextFactory.Create(string.Empty);
|
||||
return _shardingParallelDbContextFactory.Create(connectKey, string.Empty);
|
||||
}
|
||||
|
||||
public DataSourceRoutingResult GetDataSourceRoutingResult()
|
||||
{
|
||||
return _dataSourceRoutingRuleEngineFactory.Route(_source);
|
||||
}
|
||||
public IEnumerable<RouteResult> GetRouteResults(string connectKey)
|
||||
{
|
||||
return _tableRoutingRuleEngineFactory.Route(connectKey,_source);
|
||||
}
|
||||
|
||||
public ShardingScope CreateScope()
|
||||
|
|
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||
using System.Linq;
|
||||
using ShardingCore.Core.Internal.RoutingRuleEngines;
|
||||
using ShardingCore.Core.ShardingAccessors;
|
||||
using ShardingCore.Core.VirtualRoutes.DataSourceRoutes.RoutingRuleEngine;
|
||||
using ShardingCore.DbContexts;
|
||||
|
||||
namespace ShardingCore.Core.Internal.StreamMerge
|
||||
|
@ -18,24 +19,35 @@ namespace ShardingCore.Core.Internal.StreamMerge
|
|||
private readonly IShardingParallelDbContextFactory _shardingParallelDbContextFactory;
|
||||
private readonly IShardingScopeFactory _shardingScopeFactory;
|
||||
private readonly IRoutingRuleEngineFactory _routingRuleEngineFactory;
|
||||
private readonly IDataSourceRoutingRuleEngineFactory _dataSourceRoutingRuleEngineFactory;
|
||||
|
||||
public StreamMergeContextFactory(IShardingParallelDbContextFactory shardingParallelDbContextFactory,IShardingScopeFactory shardingScopeFactory,IRoutingRuleEngineFactory routingRuleEngineFactory)
|
||||
public StreamMergeContextFactory(IShardingParallelDbContextFactory shardingParallelDbContextFactory,
|
||||
IShardingScopeFactory shardingScopeFactory,
|
||||
IRoutingRuleEngineFactory routingRuleEngineFactory,
|
||||
IDataSourceRoutingRuleEngineFactory dataSourceRoutingRuleEngineFactory)
|
||||
{
|
||||
_shardingParallelDbContextFactory = shardingParallelDbContextFactory;
|
||||
_shardingScopeFactory = shardingScopeFactory;
|
||||
_routingRuleEngineFactory = routingRuleEngineFactory;
|
||||
_dataSourceRoutingRuleEngineFactory = dataSourceRoutingRuleEngineFactory;
|
||||
}
|
||||
public StreamMergeContext<T> Create<T>(IQueryable<T> queryable, IEnumerable<RouteResult> routeResults)
|
||||
{
|
||||
return new StreamMergeContext<T>(queryable, routeResults, _shardingParallelDbContextFactory, _shardingScopeFactory);
|
||||
}
|
||||
//public StreamMergeContext<T> Create<T>(IQueryable<T> queryable, IEnumerable<RouteResult> routeResults)
|
||||
//{
|
||||
// return new StreamMergeContext<T>(queryable, routeResults, _shardingParallelDbContextFactory, _shardingScopeFactory);
|
||||
//}
|
||||
//public StreamMergeContext<T> Create<T>(IQueryable<T> queryable, DataSourceRoutingResult dataSourceRoutingResult)
|
||||
//{
|
||||
// return new StreamMergeContext<T>(queryable, dataSourceRoutingResult, _shardingParallelDbContextFactory, _shardingScopeFactory);
|
||||
//}
|
||||
public StreamMergeContext<T> Create<T>(IQueryable<T> queryable)
|
||||
{
|
||||
return new StreamMergeContext<T>(queryable, _routingRuleEngineFactory.Route(queryable), _shardingParallelDbContextFactory, _shardingScopeFactory);
|
||||
//return new StreamMergeContext<T>(queryable, _routingRuleEngineFactory.Route(queryable), _shardingParallelDbContextFactory, _shardingScopeFactory);
|
||||
return new StreamMergeContext<T>(queryable, _dataSourceRoutingRuleEngineFactory, _routingRuleEngineFactory, _shardingParallelDbContextFactory, _shardingScopeFactory);
|
||||
}
|
||||
public StreamMergeContext<T> Create<T>(IQueryable<T> queryable,RouteRuleContext<T> ruleContext)
|
||||
public StreamMergeContext<T> Create<T>(IQueryable<T> queryable,DataSourceRoutingRuleContext<T> ruleContext)
|
||||
{
|
||||
return new StreamMergeContext<T>(queryable, _routingRuleEngineFactory.Route(queryable,ruleContext), _shardingParallelDbContextFactory, _shardingScopeFactory);
|
||||
return new StreamMergeContext<T>(queryable, _dataSourceRoutingRuleEngineFactory, _routingRuleEngineFactory, _shardingParallelDbContextFactory, _shardingScopeFactory);
|
||||
//return new StreamMergeContext<T>(queryable, _routingRuleEngineFactory.Route(queryable,ruleContext), _shardingParallelDbContextFactory, _shardingScopeFactory);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,7 +2,6 @@ using System;
|
|||
using System.Collections;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using ShardingCore.Core.PhysicDataSources;
|
||||
using ShardingCore.Core.VirtualRoutes;
|
||||
using ShardingCore.Exceptions;
|
||||
using ShardingCore.Extensions;
|
||||
|
@ -19,17 +18,17 @@ namespace ShardingCore.Core.Internal.Visitors
|
|||
{
|
||||
private readonly ShardingEntityBaseType _shardingEntityBaseType;
|
||||
private readonly Func<object, TKey> _shardingKeyConvert;
|
||||
private readonly Func<TKey, ShardingOperatorEnum, Expression<Func<IPhysicDataSource, bool>>> _keyToDataSourceWithFilter;
|
||||
private Expression<Func<IPhysicDataSource, bool>> _where = x => true;
|
||||
private readonly Func<TKey, ShardingOperatorEnum, Expression<Func<string, bool>>> _keyToDataSourceWithFilter;
|
||||
private Expression<Func<string, bool>> _where = x => true;
|
||||
|
||||
public QueryableRouteShardingDataSourceDiscoverVisitor(ShardingEntityBaseType shardingEntityBaseType, Func<object, TKey> shardingKeyConvert, Func<TKey, ShardingOperatorEnum, Expression<Func<IPhysicDataSource, bool>>> keyToDataSourceWithFilter)
|
||||
public QueryableRouteShardingDataSourceDiscoverVisitor(ShardingEntityBaseType shardingEntityBaseType, Func<object, TKey> shardingKeyConvert, Func<TKey, ShardingOperatorEnum, Expression<Func<string, bool>>> keyToDataSourceWithFilter)
|
||||
{
|
||||
_shardingEntityBaseType = shardingEntityBaseType;
|
||||
_shardingKeyConvert = shardingKeyConvert;
|
||||
_keyToDataSourceWithFilter = keyToDataSourceWithFilter;
|
||||
}
|
||||
|
||||
public Func<IPhysicDataSource, bool> GetDataSourceFilter()
|
||||
public Func<string, bool> GetDataSourceFilter()
|
||||
{
|
||||
return _where.Compile();
|
||||
}
|
||||
|
@ -104,7 +103,7 @@ namespace ShardingCore.Core.Internal.Visitors
|
|||
}
|
||||
|
||||
|
||||
private Expression<Func<IPhysicDataSource, bool>> Resolve(Expression expression)
|
||||
private Expression<Func<string, bool>> Resolve(Expression expression)
|
||||
{
|
||||
if (expression is LambdaExpression)
|
||||
{
|
||||
|
@ -135,7 +134,7 @@ namespace ShardingCore.Core.Internal.Visitors
|
|||
return o => true;
|
||||
}
|
||||
|
||||
private Expression<Func<IPhysicDataSource, bool>> ResolveInFunc(MethodCallExpression methodCallExpression, bool @in)
|
||||
private Expression<Func<string, bool>> ResolveInFunc(MethodCallExpression methodCallExpression, bool @in)
|
||||
{
|
||||
if (methodCallExpression.IsEnumerableContains(methodCallExpression.Method.Name) && IsMethodWrapShardingKey(methodCallExpression))
|
||||
{
|
||||
|
@ -163,7 +162,7 @@ namespace ShardingCore.Core.Internal.Visitors
|
|||
if (arrayObject != null)
|
||||
{
|
||||
var enumerable = (IEnumerable) arrayObject;
|
||||
Expression<Func<IPhysicDataSource, bool>> contains = x => false;
|
||||
Expression<Func<string, bool>> contains = x => false;
|
||||
if (!@in)
|
||||
contains = x => true;
|
||||
foreach (var item in enumerable)
|
||||
|
@ -183,10 +182,10 @@ namespace ShardingCore.Core.Internal.Visitors
|
|||
return x => true;
|
||||
}
|
||||
|
||||
private Expression<Func<IPhysicDataSource, bool>> ParseGetWhere(BinaryExpression binaryExpression)
|
||||
private Expression<Func<string, bool>> ParseGetWhere(BinaryExpression binaryExpression)
|
||||
{
|
||||
Expression<Func<IPhysicDataSource, bool>> left = x => true;
|
||||
Expression<Func<IPhysicDataSource, bool>> right = x => true;
|
||||
Expression<Func<string, bool>> left = x => true;
|
||||
Expression<Func<string, bool>> right = x => true;
|
||||
|
||||
//递归获取
|
||||
if (binaryExpression.Left is BinaryExpression)
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using Microsoft.EntityFrameworkCore.Query;
|
||||
using ShardingCore.Extensions;
|
||||
|
|
|
@ -28,7 +28,7 @@ namespace ShardingCore.Core.Internal.Visitors
|
|||
}
|
||||
protected override Expression VisitConstant(ConstantExpression node)
|
||||
{
|
||||
if (node.Value is IQueryable queryable&&queryable.ElementType.IsShardingEntity())
|
||||
if (node.Value is IQueryable queryable&&queryable.ElementType.IsShardingTable())
|
||||
{
|
||||
_shardingEntities.Add(queryable.ElementType);
|
||||
}
|
||||
|
@ -54,7 +54,7 @@ namespace ShardingCore.Core.Internal.Visitors
|
|||
|
||||
protected override Expression VisitExtension(Expression node)
|
||||
{
|
||||
if (node is QueryRootExpression queryRootExpression&&queryRootExpression.EntityType.ClrType.IsShardingEntity())
|
||||
if (node is QueryRootExpression queryRootExpression&&queryRootExpression.EntityType.ClrType.IsShardingTable())
|
||||
{
|
||||
_shardingEntities.Add(queryRootExpression.EntityType.ClrType);
|
||||
}
|
||||
|
|
|
@ -1,58 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using ShardingCore.Core.Internal;
|
||||
|
||||
namespace ShardingCore.Core.PhysicDataSources
|
||||
{
|
||||
/*
|
||||
* @Author: xjm
|
||||
* @Description:
|
||||
* @Date: Friday, 05 February 2021 13:05:28
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
/// <summary>
|
||||
/// 物理表接口
|
||||
/// </summary>
|
||||
public interface IPhysicDataSource
|
||||
{
|
||||
/// <summary>
|
||||
/// 连接字符串
|
||||
/// </summary>
|
||||
string GetConnectionString();
|
||||
|
||||
/// <summary>
|
||||
/// 数据源类型
|
||||
/// </summary>
|
||||
DataSourceEnum GetDataSourceType();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 添加分库实体
|
||||
/// </summary>
|
||||
/// <param name="entityBaseType"></param>
|
||||
void AddEntity(ShardingEntityBaseType entityBaseType);
|
||||
|
||||
/// <summary>
|
||||
/// 添加分库实体
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
void AddEntity<T>() where T : class, IShardingDataSource;
|
||||
|
||||
/// <summary>
|
||||
/// 添加分库实体
|
||||
/// </summary>
|
||||
/// <param name="shardingEntity"></param>
|
||||
void AddEntity(Type shardingEntity);
|
||||
/// <summary>
|
||||
/// 是否有对应的实体
|
||||
/// </summary>
|
||||
/// <param name="shardingEntity"></param>
|
||||
/// <returns></returns>
|
||||
bool HasEntity(Type shardingEntity);
|
||||
/// <summary>
|
||||
/// 是否有对应的实体
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
bool HasEntity<T>() where T : class, IShardingDataSource;
|
||||
}
|
||||
}
|
|
@ -1,74 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using ShardingCore.Core.Internal;
|
||||
using ShardingCore.Extensions;
|
||||
using ShardingCore.Utils;
|
||||
|
||||
namespace ShardingCore.Core.PhysicDataSources
|
||||
{
|
||||
/*
|
||||
* @Author: xjm
|
||||
* @Description:
|
||||
* @Date: Friday, 05 February 2021 13:47:49
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
public class PhysicDataSource:IPhysicDataSource
|
||||
{
|
||||
public string ConnectionString { get; }
|
||||
private readonly DataSourceEnum _dataSourceType;
|
||||
private readonly Dictionary<Type,ShardingEntityBaseType> _entities;
|
||||
private readonly string _connectionString;
|
||||
|
||||
public PhysicDataSource(string connectionString,DataSourceEnum dataSourceType)
|
||||
{
|
||||
_connectionString = connectionString;
|
||||
_dataSourceType = dataSourceType;
|
||||
_entities = new Dictionary<Type, ShardingEntityBaseType>();
|
||||
}
|
||||
|
||||
public string GetConnectionString()
|
||||
{
|
||||
return _connectionString;
|
||||
}
|
||||
|
||||
public DataSourceEnum GetDataSourceType()
|
||||
{
|
||||
return _dataSourceType;
|
||||
}
|
||||
|
||||
public void AddEntity(ShardingEntityBaseType entityBaseType)
|
||||
{
|
||||
if(!_entities.ContainsKey(entityBaseType.EntityType))
|
||||
_entities.Add(entityBaseType.EntityType,entityBaseType);
|
||||
}
|
||||
|
||||
public void AddEntity<T>() where T : class, IShardingDataSource
|
||||
{
|
||||
var entityType = typeof(T);
|
||||
AddEntity(entityType);
|
||||
}
|
||||
|
||||
public void AddEntity(Type shardingEntity)
|
||||
{
|
||||
if (!shardingEntity.IsShardingDataSource())
|
||||
throw new InvalidOperationException($"entity:[{shardingEntity}] should from {nameof(IShardingDataSource)}");
|
||||
var entityBaseType = ShardingUtil.Parse(shardingEntity);
|
||||
AddEntity(entityBaseType);
|
||||
}
|
||||
|
||||
public bool HasEntity(Type shardingEntity)
|
||||
{
|
||||
if (!shardingEntity.IsShardingDataSource())
|
||||
return false;
|
||||
return _entities.ContainsKey(shardingEntity);
|
||||
}
|
||||
|
||||
public bool HasEntity<T>() where T : class, IShardingDataSource
|
||||
{
|
||||
return HasEntity(typeof(T));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -13,8 +13,11 @@ namespace ShardingCore.Core.ShardingAccessors
|
|||
*/
|
||||
public class ShardingContext
|
||||
{
|
||||
private ShardingContext(RouteResult routeResult)
|
||||
public string ConnectKey { get; }
|
||||
|
||||
private ShardingContext(string connectKey,RouteResult routeResult)
|
||||
{
|
||||
ConnectKey = connectKey;
|
||||
foreach (var physicTable in routeResult.ReplaceTables)
|
||||
{
|
||||
_shardingTables.Add(physicTable.VirtualTable, new List<string>(1){physicTable.Tail});
|
||||
|
@ -41,9 +44,9 @@ namespace ShardingCore.Core.ShardingAccessors
|
|||
/// 创建一个分表上下文
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static ShardingContext Create(RouteResult routeResult)
|
||||
public static ShardingContext Create(string connectKey, RouteResult routeResult)
|
||||
{
|
||||
return new ShardingContext(routeResult);
|
||||
return new ShardingContext(connectKey,routeResult);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
//using System;
|
||||
//using System.Collections.Generic;
|
||||
//using System.Text;
|
||||
|
||||
//namespace ShardingCore.Core
|
||||
//{
|
||||
// /*
|
||||
// * @Author: xjm
|
||||
// * @Description:
|
||||
// * @Date: 2021/3/2 15:06:18
|
||||
// * @Ver: 1.0
|
||||
// * @Email: 326308290@qq.com
|
||||
// */
|
||||
// public class ShardingDataSourceConfig
|
||||
// {
|
||||
// public ShardingDataSourceConfig(string connectKey, string connectionString)
|
||||
// {
|
||||
// ConnectKey = connectKey;
|
||||
// ConnectionString = connectionString;
|
||||
// Entities = new HashSet<Type>();
|
||||
// }
|
||||
|
||||
// /// <summary>
|
||||
// /// 连接标识
|
||||
// /// </summary>
|
||||
// public string ConnectKey { get; }
|
||||
|
||||
// /// <summary>
|
||||
// /// 连接字符串
|
||||
// /// </summary>
|
||||
// public string ConnectionString { get; }
|
||||
|
||||
// public ISet<Type> Entities { get; }
|
||||
|
||||
// public override int GetHashCode()
|
||||
// {
|
||||
// return this.ConnectKey.GetHashCode() ^ 31;
|
||||
// }
|
||||
|
||||
// public override bool Equals(object obj)
|
||||
// {
|
||||
// if (!(obj is ShardingDataSourceConfig))
|
||||
// return false;
|
||||
|
||||
// if (ReferenceEquals(this, obj))
|
||||
// return true;
|
||||
|
||||
// ShardingDataSourceConfig item = (ShardingDataSourceConfig)obj;
|
||||
|
||||
// return item.ConnectKey == this.ConnectKey;
|
||||
// }
|
||||
// }
|
||||
//}
|
|
@ -12,7 +12,7 @@ namespace ShardingCore.Core
|
|||
/// 数据源分库规则字段
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]
|
||||
public class ShardingDataSourceKeyAttribute
|
||||
public class ShardingDataSourceKeyAttribute: Attribute
|
||||
{
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace ShardingCore.Core.ShardingDataSources
|
||||
|
@ -32,5 +33,6 @@ namespace ShardingCore.Core.ShardingDataSources
|
|||
bool IsShardingDataSource();
|
||||
|
||||
public IEnumerable<ShardingDataSourceDbEntry> FilterDataSources(ISet<Type> queryEntities);
|
||||
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using ShardingCore.Core.VirtualRoutes.DataSourceRoutes;
|
||||
|
||||
namespace ShardingCore.Core.ShardingDataSources
|
||||
{
|
||||
|
@ -20,7 +21,7 @@ namespace ShardingCore.Core.ShardingDataSources
|
|||
/// </summary>
|
||||
/// <param name="entityType"></param>
|
||||
/// <param name="dataSourceDbEntry"></param>
|
||||
public ShardingDataSourceEntry(Type entityType,ShardingDataSourceDbEntry dataSourceDbEntry)
|
||||
public ShardingDataSourceEntry(Type entityType, ShardingDataSourceDbEntry dataSourceDbEntry)
|
||||
{
|
||||
EntityType = entityType;
|
||||
DataSourceDbEntry = dataSourceDbEntry;
|
||||
|
@ -35,5 +36,23 @@ namespace ShardingCore.Core.ShardingDataSources
|
|||
/// 分库对应的数据库对象
|
||||
/// </summary>
|
||||
public ShardingDataSourceDbEntry DataSourceDbEntry { get; }
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return this.EntityType.GetHashCode() ^ 31;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (!(obj is ShardingDataSourceEntry))
|
||||
return false;
|
||||
|
||||
if (ReferenceEquals(this, obj))
|
||||
return true;
|
||||
|
||||
ShardingDataSourceEntry item = (ShardingDataSourceEntry) obj;
|
||||
|
||||
return item.EntityType == this.EntityType;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using ShardingCore.Extensions;
|
||||
|
||||
namespace ShardingCore.Core.ShardingDataSources
|
||||
{
|
||||
|
|
|
@ -9,6 +9,7 @@ using ShardingCore.Core.Internal.RoutingRuleEngines;
|
|||
using ShardingCore.Core.Internal.StreamMerge;
|
||||
using ShardingCore.Core.Internal.StreamMerge.GenericMerges;
|
||||
using ShardingCore.Core.Internal.StreamMerge.GenericMerges.Proxies;
|
||||
using ShardingCore.Core.VirtualRoutes.DataSourceRoutes.RoutingRuleEngine;
|
||||
using ShardingCore.Core.VirtualTables;
|
||||
using ShardingCore.Extensions;
|
||||
#if EFCORE2
|
||||
|
@ -32,15 +33,18 @@ namespace ShardingCore.Core
|
|||
{
|
||||
private IQueryable<T> _source;
|
||||
private readonly IStreamMergeContextFactory _streamMergeContextFactory;
|
||||
private readonly RouteRuleContext<T> _routeRuleContext;
|
||||
//private readonly RouteRuleContext<T> _routeRuleContext;
|
||||
private readonly DataSourceRoutingRuleContext<T> _dataSourceRoutingRuleContext;
|
||||
|
||||
|
||||
private ShardingQueryable(IQueryable<T> source)
|
||||
{
|
||||
_source = source;
|
||||
_streamMergeContextFactory = ShardingContainer.Services.GetService<IStreamMergeContextFactory>();
|
||||
var routingRuleEngineFactory=ShardingContainer.Services.GetService<IRoutingRuleEngineFactory>();
|
||||
_routeRuleContext = routingRuleEngineFactory.CreateContext<T>(source);
|
||||
//var routingRuleEngineFactory=ShardingContainer.Services.GetService<IRoutingRuleEngineFactory>();
|
||||
var dataSourceRoutingRuleEngineFactory=ShardingContainer.Services.GetService<IDataSourceRoutingRuleEngineFactory>();
|
||||
//_routeRuleContext = routingRuleEngineFactory.CreateContext<T>(source);
|
||||
_dataSourceRoutingRuleContext = dataSourceRoutingRuleEngineFactory.CreateContext<T>(source);
|
||||
}
|
||||
|
||||
public static ShardingQueryable<TSource> Create<TSource>(IQueryable<TSource> source)
|
||||
|
@ -51,33 +55,37 @@ namespace ShardingCore.Core
|
|||
|
||||
public IShardingQueryable<T> EnableAutoRouteParse()
|
||||
{
|
||||
_routeRuleContext.EnableAutoRouteParse();
|
||||
return this;
|
||||
throw new NotImplementedException();
|
||||
//_routeRuleContext.EnableAutoRouteParse();
|
||||
//return this;
|
||||
}
|
||||
|
||||
public IShardingQueryable<T> DisableAutoRouteParse()
|
||||
{
|
||||
_routeRuleContext.DisableAutoRouteParse();
|
||||
return this;
|
||||
throw new NotImplementedException();
|
||||
//_routeRuleContext.DisableAutoRouteParse();
|
||||
//return this;
|
||||
}
|
||||
|
||||
public IShardingQueryable<T> AddManualRoute<TShardingEntity>(Expression<Func<TShardingEntity, bool>> predicate) where TShardingEntity : class, IShardingEntity
|
||||
{
|
||||
_routeRuleContext.AddRoute(predicate);
|
||||
return this;
|
||||
throw new NotImplementedException();
|
||||
//_routeRuleContext.AddRoute(predicate);
|
||||
//return this;
|
||||
}
|
||||
|
||||
public IShardingQueryable<T> AddManualRoute<TShardingEntity>( string tail) where TShardingEntity : class, IShardingEntity
|
||||
{
|
||||
_routeRuleContext.AddRoute<TShardingEntity>(tail);
|
||||
throw new NotImplementedException();
|
||||
//_routeRuleContext.AddRoute<TShardingEntity>(tail);
|
||||
|
||||
return this;
|
||||
//return this;
|
||||
}
|
||||
|
||||
|
||||
private StreamMergeContext<T> GetContext()
|
||||
{
|
||||
return _streamMergeContextFactory.Create(_source,_routeRuleContext);
|
||||
return _streamMergeContextFactory.Create(_source,_dataSourceRoutingRuleContext);
|
||||
}
|
||||
private async Task<List<TResult>> GetGenericMergeEngine<TResult>(Func<IQueryable, Task<TResult>> efQuery)
|
||||
{
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using ShardingCore.Core.PhysicDataSources;
|
||||
using ShardingCore.Core.PhysicTables;
|
||||
using ShardingCore.Core.VirtualRoutes;
|
||||
using ShardingCore.Core.VirtualRoutes.DataSourceRoutes;
|
||||
|
@ -19,32 +18,21 @@ namespace ShardingCore.Core.VirtualDataSources
|
|||
public interface IVirtualDataSource
|
||||
{
|
||||
Type EntityType{get;}
|
||||
/// <summary>
|
||||
/// 获取所有的物理数据源
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
List<IPhysicDataSource> GetAllDataSources();
|
||||
|
||||
/// <summary>
|
||||
/// 路由到具体的物理数据源
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
List<IPhysicDataSource> RouteTo(VirutalDataSourceConfig routeConfig);
|
||||
|
||||
/// <summary>
|
||||
/// 添加物理表 add physic table
|
||||
/// </summary>
|
||||
/// <param name="physicTable"></param>
|
||||
void AddDataSource(IPhysicDataSource physicTable);
|
||||
List<string> RouteTo(VirutalDataSourceRouteConfig routeRouteConfig);
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前数据源的路由
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
IVirtualDataSourceRoute GetRoute();
|
||||
IDataSourceVirtualRoute GetRoute();
|
||||
}
|
||||
public interface IVirtualDataSource<T> : IVirtualDataSource where T : class, IShardingDataSource
|
||||
{
|
||||
new IVirtualDataSourceRoute<T> GetRoute();
|
||||
new IDataSourceVirtualRoute<T> GetRoute();
|
||||
}
|
||||
}
|
|
@ -1,6 +1,5 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using ShardingCore.Core.PhysicDataSources;
|
||||
|
||||
namespace ShardingCore.Core.VirtualDataSources
|
||||
{
|
||||
|
@ -12,11 +11,37 @@ namespace ShardingCore.Core.VirtualDataSources
|
|||
*/
|
||||
public interface IVirtualDataSourceManager
|
||||
{
|
||||
/// <summary>
|
||||
/// 添加链接
|
||||
/// </summary>
|
||||
/// <param name="connectKey"></param>
|
||||
void AddShardingConnectKey(string connectKey);
|
||||
/// <summary>
|
||||
/// 获取所有的链接
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
ISet<string> GetAllShardingConnectKeys();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 添加虚拟数据源应用启动时 add virtual table when app start
|
||||
/// </summary>
|
||||
/// <param name="virtualDataSource"></param>
|
||||
void AddVirtualDataSource(IVirtualDataSource virtualDataSource);
|
||||
/// <summary>
|
||||
/// 获取所有的虚拟连接 get all virtual table
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
List<IVirtualDataSource> GetAllVirtualDataSources();
|
||||
|
||||
/// <summary>
|
||||
/// 添加链接对应的对象
|
||||
/// </summary>
|
||||
/// <param name="connectKey"></param>
|
||||
/// <param name="entityType"></param>
|
||||
void AddConnectEntities(string connectKey,Type entityType);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 获取虚拟表 get virtual table by sharding entity type
|
||||
/// </summary>
|
||||
|
@ -29,23 +54,11 @@ namespace ShardingCore.Core.VirtualDataSources
|
|||
/// <returns></returns>
|
||||
IVirtualDataSource<T> GetVirtualDataSource<T>() where T:class,IShardingDataSource;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 添加虚拟数据源应用启动时 add virtual table when app start
|
||||
/// </summary>
|
||||
/// <param name="virtualDataSource"></param>
|
||||
void AddVirtualDataSource(IVirtualDataSource virtualDataSource);
|
||||
/// <summary>
|
||||
/// 添加物理表 add physic table
|
||||
/// </summary>
|
||||
/// <param name="virtualDataSource"></param>
|
||||
/// <param name="physicDataSource"></param>
|
||||
void AddPhysicDataSource(IVirtualDataSource virtualDataSource, IPhysicDataSource physicDataSource);
|
||||
/// <summary>
|
||||
/// 添加物理表 add physic table
|
||||
/// </summary>
|
||||
/// <param name="shardingEntityType"></param>
|
||||
/// <param name="physicDataSource"></param>
|
||||
void AddPhysicDataSource(Type shardingEntityType, IPhysicDataSource physicDataSource);
|
||||
string GetDefaultConnectKey();
|
||||
bool IsShardingDataSource();
|
||||
bool HasVirtualShardingDataSourceRoute(Type shardingEntityType);
|
||||
|
||||
List<string> GetEntityTypeLinkedConnectKeys(Type shardingEntityType);
|
||||
|
||||
}
|
||||
}
|
|
@ -2,7 +2,7 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using ShardingCore.Core.PhysicDataSources;
|
||||
using System.Reflection;
|
||||
using ShardingCore.Core.VirtualRoutes.DataSourceRoutes;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using ShardingCore.Core.Internal;
|
||||
|
@ -20,62 +20,55 @@ namespace ShardingCore.Core.VirtualDataSources
|
|||
*/
|
||||
public class VirtualDataSource<T>:IVirtualDataSource<T> where T:class,IShardingDataSource
|
||||
{
|
||||
private readonly List<IPhysicDataSource> _physicDataSources;
|
||||
private readonly IVirtualDataSourceRoute<T> _virtualDataSourceRoute;
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly IDataSourceVirtualRoute<T> _dataSourceVirtualRoute;
|
||||
public ShardingEntityBaseType ShardingEntityType { get; }
|
||||
|
||||
public Type EntityType { get; }
|
||||
|
||||
public VirtualDataSource(IServiceProvider serviceProvider)
|
||||
public VirtualDataSource(IServiceProvider serviceProvider, IDataSourceVirtualRoute<T> virtualRoute)
|
||||
{
|
||||
_physicDataSources = new List<IPhysicDataSource>();
|
||||
_virtualDataSourceRoute = serviceProvider.GetService<IVirtualDataSourceRoute<T>>() ?? throw new ArgumentNullException($"{typeof(T)}");
|
||||
_serviceProvider = serviceProvider;
|
||||
_dataSourceVirtualRoute = virtualRoute;
|
||||
EntityType = typeof(T);
|
||||
ShardingEntityType = ShardingUtil.Parse(EntityType);
|
||||
}
|
||||
|
||||
public List<IPhysicDataSource> GetAllDataSources()
|
||||
{
|
||||
return _physicDataSources;
|
||||
}
|
||||
|
||||
public List<IPhysicDataSource> RouteTo(VirutalDataSourceConfig routeConfig)
|
||||
public List<string> RouteTo(VirutalDataSourceRouteConfig routeRouteConfig)
|
||||
{
|
||||
if (routeConfig.UseQueryable())
|
||||
return _virtualDataSourceRoute.RouteWithWhere(_physicDataSources, routeConfig.GetQueryable());
|
||||
if (routeConfig.UsePredicate())
|
||||
return _virtualDataSourceRoute.RouteWithWhere(_physicDataSources, new EnumerableQuery<T>((Expression<Func<T, bool>>) routeConfig.GetPredicate()));
|
||||
//»ñÈ¡ËùÓеÄÊý¾ÝÔ´
|
||||
var virtualDataSourceManager = _serviceProvider.GetService<IVirtualDataSourceManager>();
|
||||
var allShardingDataSourceConfigs = virtualDataSourceManager.GetAllShardingConnectKeys();
|
||||
|
||||
if (routeRouteConfig.UseQueryable())
|
||||
return _dataSourceVirtualRoute.RouteWithWhere(allShardingDataSourceConfigs.ToList(), routeRouteConfig.GetQueryable());
|
||||
if (routeRouteConfig.UsePredicate())
|
||||
return _dataSourceVirtualRoute.RouteWithWhere(allShardingDataSourceConfigs.ToList(), new EnumerableQuery<T>((Expression<Func<T, bool>>) routeRouteConfig.GetPredicate()));
|
||||
object shardingKeyValue = null;
|
||||
if (routeConfig.UseValue())
|
||||
shardingKeyValue = routeConfig.GetShardingKeyValue();
|
||||
if (routeRouteConfig.UseValue())
|
||||
shardingKeyValue = routeRouteConfig.GetShardingKeyValue();
|
||||
|
||||
if (routeConfig.UseEntity())
|
||||
shardingKeyValue = routeConfig.GetShardingDataSource().GetPropertyValue(ShardingEntityType.ShardingDataSourceField);
|
||||
if (routeRouteConfig.UseEntity())
|
||||
shardingKeyValue = routeRouteConfig.GetShardingDataSource().GetPropertyValue(ShardingEntityType.ShardingDataSourceField);
|
||||
|
||||
if (shardingKeyValue != null)
|
||||
{
|
||||
var routeWithValue = _virtualDataSourceRoute.RouteWithValue(_physicDataSources, shardingKeyValue);
|
||||
return new List<IPhysicDataSource>(1) {routeWithValue};
|
||||
var routeWithValue = _dataSourceVirtualRoute.RouteWithValue(allShardingDataSourceConfigs.ToList(), shardingKeyValue);
|
||||
return new List<string>(1) {routeWithValue};
|
||||
}
|
||||
|
||||
throw new NotImplementedException(nameof(VirutalDataSourceConfig));
|
||||
throw new NotImplementedException(nameof(VirutalDataSourceRouteConfig));
|
||||
}
|
||||
|
||||
public void AddDataSource(IPhysicDataSource physicTable)
|
||||
IDataSourceVirtualRoute<T> IVirtualDataSource<T>.GetRoute()
|
||||
{
|
||||
if (_physicDataSources.Any(o => o.GetConnectionString() == physicTable.GetConnectionString()))
|
||||
return;
|
||||
_physicDataSources.Add(physicTable);
|
||||
return _dataSourceVirtualRoute;
|
||||
}
|
||||
|
||||
IVirtualDataSourceRoute<T> IVirtualDataSource<T>.GetRoute()
|
||||
public IDataSourceVirtualRoute GetRoute()
|
||||
{
|
||||
return _virtualDataSourceRoute;
|
||||
}
|
||||
|
||||
public IVirtualDataSourceRoute GetRoute()
|
||||
{
|
||||
return _virtualDataSourceRoute;
|
||||
return _dataSourceVirtualRoute;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,42 +2,76 @@ using System;
|
|||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using ShardingCore.Core.PhysicDataSources;
|
||||
using ShardingCore.Exceptions;
|
||||
using ShardingCore.Extensions;
|
||||
using ShardingCore.Helpers;
|
||||
|
||||
namespace ShardingCore.Core.VirtualDataSources
|
||||
{
|
||||
/*
|
||||
* @Author: xjm
|
||||
* @Description:
|
||||
* @Date: Saturday, 06 February 2021 15:24:08
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
public class VirtualDataSourceManager:IVirtualDataSourceManager
|
||||
/*
|
||||
* @Author: xjm
|
||||
* @Description:
|
||||
* @Date: Saturday, 06 February 2021 15:24:08
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
public class VirtualDataSourceManager : IVirtualDataSourceManager
|
||||
{
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly ConcurrentDictionary<Type, IVirtualDataSource> _virtualDataSources = new ConcurrentDictionary<Type, IVirtualDataSource>();
|
||||
|
||||
private readonly Dictionary<string, ISet<Type>> _shardingConnectKeys = new Dictionary<string,ISet<Type>>();
|
||||
private readonly Dictionary<Type, ISet<string>> _entityTypeConnectKeyIndex = new Dictionary<Type, ISet<string>>();
|
||||
|
||||
public VirtualDataSourceManager(IServiceProvider serviceProvider)
|
||||
{
|
||||
var shardingEntities = AssemblyHelper.CurrentDomain.GetAssemblies().SelectMany(o => o.GetTypes())
|
||||
.Where(type => !String.IsNullOrEmpty(type.Namespace))
|
||||
.Where(type => !type.IsAbstract&&type.GetInterfaces()
|
||||
.Any(it => it.IsInterface &&typeof(IShardingDataSource)==it)
|
||||
);
|
||||
foreach (var shardingEntity in shardingEntities)
|
||||
{
|
||||
Type genericType = typeof(IVirtualDataSource<>);
|
||||
Type interfaceType = genericType.MakeGenericType(shardingEntity);
|
||||
var virtualDataSource = (IVirtualDataSource)serviceProvider.GetService(interfaceType);
|
||||
_virtualDataSources.TryAdd(virtualDataSource.EntityType, virtualDataSource);
|
||||
}
|
||||
_serviceProvider = serviceProvider;
|
||||
//var shardingEntities = AssemblyHelper.CurrentDomain.GetAssemblies().SelectMany(o => o.GetTypes())
|
||||
// .Where(type => !String.IsNullOrEmpty(type.Namespace))
|
||||
// .Where(type => !type.IsAbstract&&type.GetInterfaces()
|
||||
// .Any(it => it.IsInterface &&typeof(IShardingDataSource)==it)
|
||||
// );
|
||||
//foreach (var shardingEntity in shardingEntities)
|
||||
//{
|
||||
// Type genericType = typeof(IVirtualDataSource<>);
|
||||
// Type interfaceType = genericType.MakeGenericType(shardingEntity);
|
||||
// var virtualDataSource = (IVirtualDataSource)serviceProvider.GetService(interfaceType);
|
||||
// _virtualDataSources.TryAdd(virtualDataSource.EntityType, virtualDataSource);
|
||||
//}
|
||||
}
|
||||
|
||||
public ISet<string> GetAllShardingConnectKeys()
|
||||
{
|
||||
return _shardingConnectKeys.Keys.ToHashSet();
|
||||
}
|
||||
|
||||
|
||||
public List<IVirtualDataSource> GetAllVirtualDataSources()
|
||||
{
|
||||
return _virtualDataSources.Select(o => o.Value).ToList();
|
||||
}
|
||||
|
||||
public void AddConnectEntities(string connectKey, Type entityType)
|
||||
{
|
||||
if (!_shardingConnectKeys.ContainsKey(connectKey))
|
||||
throw new ShardingCoreException("connectKey not init");
|
||||
_shardingConnectKeys[connectKey].Add(entityType);
|
||||
BuildIndex(connectKey, entityType);
|
||||
}
|
||||
|
||||
private void BuildIndex(string connectKey, Type entityType)
|
||||
{
|
||||
|
||||
if (_entityTypeConnectKeyIndex.ContainsKey(entityType))
|
||||
{
|
||||
_entityTypeConnectKeyIndex[entityType].Add(connectKey);
|
||||
}
|
||||
else
|
||||
{
|
||||
_entityTypeConnectKeyIndex.Add(entityType,new HashSet<string>(){ connectKey
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public IVirtualDataSource GetVirtualDataSource(Type shardingEntityType)
|
||||
{
|
||||
if (!_virtualDataSources.TryGetValue(shardingEntityType, out var virtualTable) || virtualTable == null)
|
||||
|
@ -50,21 +84,37 @@ namespace ShardingCore.Core.VirtualDataSources
|
|||
return (IVirtualDataSource<T>)GetVirtualDataSource(typeof(T));
|
||||
}
|
||||
|
||||
public string GetDefaultConnectKey()
|
||||
{
|
||||
return _shardingConnectKeys.Keys.FirstOrDefault();
|
||||
}
|
||||
|
||||
public bool IsShardingDataSource()
|
||||
{
|
||||
return _shardingConnectKeys.Count > 1;
|
||||
}
|
||||
|
||||
public bool HasVirtualShardingDataSourceRoute(Type shardingEntityType)
|
||||
{
|
||||
return _virtualDataSources.ContainsKey(shardingEntityType);
|
||||
}
|
||||
|
||||
public List<string> GetEntityTypeLinkedConnectKeys(Type shardingEntityType)
|
||||
{
|
||||
if (!_entityTypeConnectKeyIndex.ContainsKey(shardingEntityType))
|
||||
throw new ShardingCoreException($"entity:[{shardingEntityType}] not found");
|
||||
return _entityTypeConnectKeyIndex[shardingEntityType].ToList();
|
||||
}
|
||||
|
||||
public void AddShardingConnectKey(string connectKey)
|
||||
{
|
||||
if (!_shardingConnectKeys.ContainsKey(connectKey))
|
||||
_shardingConnectKeys.Add(connectKey,new HashSet<Type>());
|
||||
}
|
||||
|
||||
public void AddVirtualDataSource(IVirtualDataSource virtualDataSource)
|
||||
{
|
||||
_virtualDataSources.TryAdd(virtualDataSource.EntityType, virtualDataSource);
|
||||
}
|
||||
|
||||
public void AddPhysicDataSource(IVirtualDataSource virtualDataSource, IPhysicDataSource physicDataSource)
|
||||
{
|
||||
AddPhysicDataSource(virtualDataSource.EntityType, physicDataSource);
|
||||
}
|
||||
|
||||
public void AddPhysicDataSource(Type shardingEntityType, IPhysicDataSource physicDataSource)
|
||||
{
|
||||
var virtualTable = GetVirtualDataSource(shardingEntityType);
|
||||
virtualTable.AddDataSource(physicDataSource);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -10,7 +10,7 @@ namespace ShardingCore.Core.VirtualDataSources
|
|||
* @Date: Saturday, 06 February 2021 11:28:33
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
public class VirutalDataSourceConfig
|
||||
public class VirutalDataSourceRouteConfig
|
||||
{
|
||||
|
||||
private readonly IQueryable _queryable;
|
||||
|
@ -19,7 +19,7 @@ namespace ShardingCore.Core.VirtualDataSources
|
|||
private readonly Expression _predicate;
|
||||
|
||||
|
||||
public VirutalDataSourceConfig(IQueryable queryable=null,IShardingDataSource shardingDataSource=null,object shardingKeyValue=null,Expression predicate=null)
|
||||
public VirutalDataSourceRouteConfig(IQueryable queryable=null,IShardingDataSource shardingDataSource=null,object shardingKeyValue=null,Expression predicate=null)
|
||||
{
|
||||
_queryable = queryable;
|
||||
_shardingDataSource = shardingDataSource;
|
|
@ -1,7 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using ShardingCore.Core.PhysicDataSources;
|
||||
|
||||
namespace ShardingCore.Core.VirtualRoutes.DataSourceRoutes
|
||||
{
|
||||
|
@ -11,10 +10,10 @@ namespace ShardingCore.Core.VirtualRoutes.DataSourceRoutes
|
|||
* @Date: Friday, 05 February 2021 17:06:49
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
public abstract class AbstractDataSourceVirtualRoute<T,TKey>:IVirtualDataSourceRoute<T> where T:class,IShardingDataSource
|
||||
public abstract class AbstractDataSourceVirtualRoute<T,TKey>:IDataSourceVirtualRoute<T> where T:class,IShardingDataSource
|
||||
{
|
||||
public Type ShardingEntityType => typeof(T);
|
||||
public abstract IPhysicDataSource RouteWithValue(List<IPhysicDataSource> allPhysicDataSources, object shardingKey);
|
||||
public abstract string RouteWithValue(List<string> allConnectKeys, object shardingKey);
|
||||
|
||||
|
||||
protected abstract TKey ConvertToShardingKey(object shardingKey);
|
||||
|
@ -24,24 +23,24 @@ namespace ShardingCore.Core.VirtualRoutes.DataSourceRoutes
|
|||
/// <param name="allPhysicDataSources"></param>
|
||||
/// <param name="queryable"></param>
|
||||
/// <returns></returns>
|
||||
public List<IPhysicDataSource> RouteWithWhere(List<IPhysicDataSource> allPhysicDataSources, IQueryable queryable)
|
||||
public List<string> RouteWithWhere(List<string> allPhysicDataSources, IQueryable queryable)
|
||||
{
|
||||
return AfterFilter(allPhysicDataSources,DoRouteWithWhere(allPhysicDataSources,queryable));
|
||||
}
|
||||
/// <summary>
|
||||
/// 实际路由
|
||||
/// </summary>
|
||||
/// <param name="allPhysicDataSources"></param>
|
||||
/// <param name="allShardingDataSourceConfigs"></param>
|
||||
/// <param name="queryable"></param>
|
||||
/// <returns></returns>
|
||||
protected abstract List<IPhysicDataSource> DoRouteWithWhere(List<IPhysicDataSource> allPhysicDataSources, IQueryable queryable);
|
||||
protected abstract List<string> DoRouteWithWhere(List<string> allShardingDataSourceConfigs, IQueryable queryable);
|
||||
/// <summary>
|
||||
/// 物理表过滤后
|
||||
/// </summary>
|
||||
/// <param name="allPhysicDataSources">所有的数据源</param>
|
||||
/// <param name="filterPhysicDataSources">过滤后的数据源</param>
|
||||
/// <returns></returns>
|
||||
public virtual List<IPhysicDataSource> AfterFilter(List<IPhysicDataSource> allPhysicDataSources,List<IPhysicDataSource> filterPhysicDataSources)
|
||||
public virtual List<string> AfterFilter(List<string> allPhysicDataSources,List<string> filterPhysicDataSources)
|
||||
{
|
||||
return filterPhysicDataSources;
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using ShardingCore.Core.PhysicDataSources;
|
||||
using ShardingCore.Exceptions;
|
||||
using ShardingCore.Extensions;
|
||||
using ShardingCore.Utils;
|
||||
|
@ -23,18 +22,18 @@ namespace ShardingCore.Core.VirtualRoutes.DataSourceRoutes
|
|||
/// <param name="shardingKey">分表的值</param>
|
||||
/// <param name="shardingOperator">操作</param>
|
||||
/// <returns>如果返回true表示返回该表 第一个参数 tail 第二参数是否返回该物理表</returns>
|
||||
protected abstract Expression<Func<IPhysicDataSource, bool>> GetRouteToFilter(TKey shardingKey, ShardingOperatorEnum shardingOperator);
|
||||
protected abstract Expression<Func<string, bool>> GetRouteToFilter(TKey shardingKey, ShardingOperatorEnum shardingOperator);
|
||||
/// <summary>
|
||||
/// 通过iqueryable来解析本次路由到的具体数据源
|
||||
/// </summary>
|
||||
/// <param name="allPhysicDataSources"></param>
|
||||
/// <param name="allShardingDataSourceConfigs"></param>
|
||||
/// <param name="queryable"></param>
|
||||
/// <returns></returns>
|
||||
protected override List<IPhysicDataSource> DoRouteWithWhere(List<IPhysicDataSource> allPhysicDataSources, IQueryable queryable)
|
||||
protected override List<string> DoRouteWithWhere(List<string> allShardingDataSourceConfigs, IQueryable queryable)
|
||||
{
|
||||
//获取所有需要路由的表后缀
|
||||
var filter = ShardingUtil.GetRouteDataSourceFilter(queryable, ShardingUtil.Parse(typeof(T)), ConvertToShardingKey, GetRouteToFilter);
|
||||
var physicTables = allPhysicDataSources.Where(o => filter(o)).ToList();
|
||||
var physicTables = allShardingDataSourceConfigs.Where(o => filter(o)).ToList();
|
||||
return physicTables;
|
||||
}
|
||||
/// <summary>
|
||||
|
@ -45,7 +44,7 @@ namespace ShardingCore.Core.VirtualRoutes.DataSourceRoutes
|
|||
/// <returns></returns>
|
||||
/// <exception cref="ShardingDataSourceRouteNotMatchException"></exception>
|
||||
/// <exception cref="ShardingDataSourceRouteMatchMoreException"></exception>
|
||||
public override IPhysicDataSource RouteWithValue(List<IPhysicDataSource> allPhysicDataSources, object shardingKey)
|
||||
public override string RouteWithValue(List<string> allPhysicDataSources, object shardingKey)
|
||||
{
|
||||
var filter = GetRouteToFilter(ConvertToShardingKey(shardingKey), ShardingOperatorEnum.Equal).Compile();
|
||||
|
||||
|
@ -57,7 +56,7 @@ namespace ShardingCore.Core.VirtualRoutes.DataSourceRoutes
|
|||
}
|
||||
|
||||
if (physicDataSources.Count > 1)
|
||||
throw new ShardingDataSourceRouteMatchMoreException($"data source :{string.Join(",", physicDataSources.Select(o => $"[{o.GetDataSourceType()}]"))}");
|
||||
throw new ShardingDataSourceRouteMatchMoreException($"data source :{string.Join(",", physicDataSources.Select(o => $"[{o}]"))}");
|
||||
return physicDataSources[0];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Text;
|
||||
|
||||
namespace ShardingCore.Core.VirtualRoutes.DataSourceRoutes
|
||||
{
|
||||
/*
|
||||
* @Author: xjm
|
||||
* @Description:
|
||||
* @Date: 2021/3/2 16:08:34
|
||||
* @Ver: 1.0
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
public class DataSourceRouteConfig
|
||||
{
|
||||
private readonly IQueryable _queryable;
|
||||
private readonly IShardingDataSource _shardingDataSource;
|
||||
private readonly object _shardingKeyValue;
|
||||
private readonly Expression _predicate;
|
||||
|
||||
|
||||
public DataSourceRouteConfig(IQueryable queryable = null, IShardingDataSource shardingDataSource = null, object shardingKeyValue = null, Expression predicate = null)
|
||||
{
|
||||
_queryable = queryable;
|
||||
_shardingDataSource = shardingDataSource;
|
||||
_shardingKeyValue = shardingKeyValue;
|
||||
_predicate = predicate;
|
||||
}
|
||||
|
||||
public IQueryable GetQueryable()
|
||||
{
|
||||
return _queryable;
|
||||
}
|
||||
public object GetShardingKeyValue()
|
||||
{
|
||||
return _shardingKeyValue;
|
||||
}
|
||||
|
||||
public IShardingDataSource GetShardingDataSource()
|
||||
{
|
||||
return _shardingDataSource;
|
||||
}
|
||||
|
||||
public Expression GetPredicate()
|
||||
{
|
||||
return _predicate;
|
||||
}
|
||||
|
||||
public bool UseQueryable()
|
||||
{
|
||||
return _queryable != null;
|
||||
}
|
||||
|
||||
public bool UseValue()
|
||||
{
|
||||
return _shardingKeyValue != null;
|
||||
}
|
||||
|
||||
public bool UseEntity()
|
||||
{
|
||||
return _shardingDataSource != null;
|
||||
}
|
||||
|
||||
public bool UsePredicate()
|
||||
{
|
||||
return _predicate != null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using ShardingCore.Core.PhysicDataSources;
|
||||
|
||||
namespace ShardingCore.Core.VirtualRoutes.DataSourceRoutes
|
||||
{
|
||||
|
@ -11,7 +10,7 @@ namespace ShardingCore.Core.VirtualRoutes.DataSourceRoutes
|
|||
* @Date: Friday, 05 February 2021 13:03:58
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
public interface IVirtualDataSourceRoute
|
||||
public interface IDataSourceVirtualRoute
|
||||
{
|
||||
Type ShardingEntityType { get; }
|
||||
|
||||
|
@ -21,7 +20,7 @@ namespace ShardingCore.Core.VirtualRoutes.DataSourceRoutes
|
|||
/// <param name="allPhysicDataSources"></param>
|
||||
/// <param name="queryable"></param>
|
||||
/// <returns></returns>
|
||||
List<IPhysicDataSource> RouteWithWhere(List<IPhysicDataSource> allPhysicDataSources,IQueryable queryable);
|
||||
List<string> RouteWithWhere(List<string> allPhysicDataSources,IQueryable queryable);
|
||||
|
||||
/// <summary>
|
||||
/// 根据值进行路由
|
||||
|
@ -29,11 +28,11 @@ namespace ShardingCore.Core.VirtualRoutes.DataSourceRoutes
|
|||
/// <param name="allPhysicDataSources"></param>
|
||||
/// <param name="shardingKeyValue"></param>
|
||||
/// <returns></returns>
|
||||
IPhysicDataSource RouteWithValue(List<IPhysicDataSource> allPhysicDataSources, object shardingKeyValue);
|
||||
string RouteWithValue(List<string> allPhysicDataSources, object shardingKeyValue);
|
||||
|
||||
}
|
||||
|
||||
public interface IVirtualDataSourceRoute<T> : IVirtualDataSourceRoute where T : class, IShardingDataSource
|
||||
public interface IDataSourceVirtualRoute<T> : IDataSourceVirtualRoute where T : class, IShardingDataSource
|
||||
{
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace ShardingCore.Core.VirtualRoutes.DataSourceRoutes.RoutingRuleEngine
|
||||
{
|
||||
/*
|
||||
* @Author: xjm
|
||||
* @Description:
|
||||
* @Date: 2021/3/2 16:13:49
|
||||
* @Ver: 1.0
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
public class DataSourceRoutingResult
|
||||
{
|
||||
public DataSourceRoutingResult(ISet<string> intersectConfigs)
|
||||
{
|
||||
IntersectConfigs = intersectConfigs;
|
||||
}
|
||||
/// <summary>
|
||||
/// 交集
|
||||
/// </summary>
|
||||
public ISet<string> IntersectConfigs { get; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using ShardingCore.Core.VirtualDataSources;
|
||||
|
||||
namespace ShardingCore.Core.VirtualRoutes.DataSourceRoutes.RoutingRuleEngine
|
||||
{
|
||||
/*
|
||||
* @Author: xjm
|
||||
* @Description:
|
||||
* @Date: 2021/3/2 16:17:05
|
||||
* @Ver: 1.0
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
public class DataSourceRoutingRuleContext<T>
|
||||
{
|
||||
|
||||
public DataSourceRoutingRuleContext(IQueryable<T> queryable)
|
||||
{
|
||||
Queryable = queryable;
|
||||
}
|
||||
/// <summary>
|
||||
/// 查询条件
|
||||
/// </summary>
|
||||
public IQueryable<T> Queryable { get; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using ShardingCore.Core.Internal.RoutingRuleEngines;
|
||||
using ShardingCore.Core.PhysicTables;
|
||||
using ShardingCore.Core.VirtualDataSources;
|
||||
using ShardingCore.Core.VirtualRoutes.TableRoutes;
|
||||
using ShardingCore.Core.VirtualTables;
|
||||
using ShardingCore.Extensions;
|
||||
|
||||
namespace ShardingCore.Core.VirtualRoutes.DataSourceRoutes.RoutingRuleEngine
|
||||
{
|
||||
/*
|
||||
* @Author: xjm
|
||||
* @Description:
|
||||
* @Date: 2021/3/2 16:20:37
|
||||
* @Ver: 1.0
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
public class DataSourceRoutingRuleEngine: IDataSourceRoutingRuleEngine
|
||||
{
|
||||
private readonly IVirtualDataSourceManager _virtualDataSourceManager;
|
||||
|
||||
public DataSourceRoutingRuleEngine(IVirtualDataSourceManager virtualDataSourceManager)
|
||||
{
|
||||
_virtualDataSourceManager = virtualDataSourceManager;
|
||||
}
|
||||
|
||||
public DataSourceRoutingResult Route<T>(DataSourceRoutingRuleContext<T> routingRuleContext)
|
||||
{
|
||||
var queryEntities = routingRuleContext.Queryable.ParseQueryableRoute().Where(o=>o.IsShardingDataSource()).ToList();
|
||||
if (queryEntities.IsEmpty())
|
||||
return new DataSourceRoutingResult(_virtualDataSourceManager.GetAllShardingConnectKeys());
|
||||
|
||||
var dataSourceMaps = new Dictionary<Type, ISet<string>>();
|
||||
foreach (var queryEntity in queryEntities)
|
||||
{
|
||||
var virtualDataSource = _virtualDataSourceManager.GetVirtualDataSource(queryEntity);
|
||||
var dataSourceConfigs = virtualDataSource.RouteTo(new VirutalDataSourceRouteConfig(routingRuleContext.Queryable));
|
||||
if (!dataSourceMaps.ContainsKey(queryEntity))
|
||||
{
|
||||
dataSourceMaps.Add(queryEntity, dataSourceConfigs.ToHashSet());
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var shardingDataSource in dataSourceConfigs)
|
||||
{
|
||||
dataSourceMaps[queryEntity].Add(shardingDataSource);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (dataSourceMaps.IsEmpty())
|
||||
return new DataSourceRoutingResult(new HashSet<string>());
|
||||
if(dataSourceMaps.Count==1)
|
||||
return new DataSourceRoutingResult(dataSourceMaps.FirstOrDefault().Value);
|
||||
var intersect = dataSourceMaps.Select(o => o.Value).Aggregate((p, n) => p.Intersect(n).ToHashSet());
|
||||
return new DataSourceRoutingResult(intersect);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using ShardingCore.Core.VirtualDataSources;
|
||||
|
||||
namespace ShardingCore.Core.VirtualRoutes.DataSourceRoutes.RoutingRuleEngine
|
||||
{
|
||||
/*
|
||||
* @Author: xjm
|
||||
* @Description:
|
||||
* @Date: 2021/3/3 8:39:34
|
||||
* @Ver: 1.0
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
public class DataSourceRoutingRuleEngineFactory:IDataSourceRoutingRuleEngineFactory
|
||||
|
||||
{
|
||||
private readonly IDataSourceRoutingRuleEngine _routeRuleEngine;
|
||||
|
||||
public DataSourceRoutingRuleEngineFactory(IDataSourceRoutingRuleEngine routeRuleEngine)
|
||||
{
|
||||
_routeRuleEngine = routeRuleEngine;
|
||||
}
|
||||
|
||||
public IDataSourceRoutingRuleEngine CreateEngine()
|
||||
{
|
||||
return _routeRuleEngine;
|
||||
}
|
||||
|
||||
public DataSourceRoutingRuleContext<T> CreateContext<T>(IQueryable<T> queryable)
|
||||
{
|
||||
return new DataSourceRoutingRuleContext<T>(queryable);
|
||||
}
|
||||
|
||||
public DataSourceRoutingResult Route<T>(IQueryable<T> queryable)
|
||||
{
|
||||
var engine = CreateEngine();
|
||||
var ruleContext = CreateContext<T>(queryable);
|
||||
return engine.Route(ruleContext);
|
||||
}
|
||||
|
||||
public DataSourceRoutingResult Route<T>(IQueryable<T> queryable, DataSourceRoutingRuleContext<T> ruleContext)
|
||||
{
|
||||
var engine = CreateEngine();
|
||||
return engine.Route(ruleContext);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace ShardingCore.Core.VirtualRoutes.DataSourceRoutes.RoutingRuleEngine
|
||||
{
|
||||
/*
|
||||
* @Author: xjm
|
||||
* @Description:
|
||||
* @Date: 2021/3/2 16:13:12
|
||||
* @Ver: 1.0
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
/// <summary>
|
||||
/// 分库路由引擎
|
||||
/// </summary>
|
||||
public interface IDataSourceRoutingRuleEngine
|
||||
{
|
||||
DataSourceRoutingResult Route<T>(DataSourceRoutingRuleContext<T> routingRuleContext);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace ShardingCore.Core.VirtualRoutes.DataSourceRoutes.RoutingRuleEngine
|
||||
{
|
||||
/*
|
||||
* @Author: xjm
|
||||
* @Description:
|
||||
* @Date: 2021/3/3 8:32:30
|
||||
* @Ver: 1.0
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
public interface IDataSourceRoutingRuleEngineFactory
|
||||
{
|
||||
IDataSourceRoutingRuleEngine CreateEngine();
|
||||
DataSourceRoutingRuleContext<T> CreateContext<T>(IQueryable<T> queryable);
|
||||
DataSourceRoutingResult Route<T>(IQueryable<T> queryable);
|
||||
DataSourceRoutingResult Route<T>(IQueryable<T> queryable, DataSourceRoutingRuleContext<T> ruleContext);
|
||||
}
|
||||
}
|
|
@ -7,7 +7,7 @@ using ShardingCore.Exceptions;
|
|||
using ShardingCore.Extensions;
|
||||
using ShardingCore.Utils;
|
||||
|
||||
namespace ShardingCore.Core.VirtualRoutes.Abstractions
|
||||
namespace ShardingCore.Core.VirtualRoutes.TableRoutes
|
||||
{
|
||||
/*
|
||||
* @Author: xjm
|
|
@ -3,7 +3,7 @@ using System.Collections.Generic;
|
|||
using System.Linq;
|
||||
using ShardingCore.Core.PhysicTables;
|
||||
|
||||
namespace ShardingCore.Core.VirtualRoutes.Abstractions
|
||||
namespace ShardingCore.Core.VirtualRoutes.TableRoutes
|
||||
{
|
||||
/*
|
||||
* @Author: xjm
|
|
@ -3,7 +3,7 @@ using System.Collections.Generic;
|
|||
using System.Linq;
|
||||
using ShardingCore.Core.PhysicTables;
|
||||
|
||||
namespace ShardingCore.Core.VirtualRoutes
|
||||
namespace ShardingCore.Core.VirtualRoutes.TableRoutes
|
||||
{
|
||||
/*
|
||||
* @Author: xjm
|
|
@ -1,7 +1,7 @@
|
|||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace ShardingCore.Core.VirtualRoutes
|
||||
namespace ShardingCore.Core.VirtualRoutes.TableRoutes
|
||||
{
|
||||
/*
|
||||
* @Author: xjm
|
||||
|
@ -9,7 +9,7 @@ namespace ShardingCore.Core.VirtualRoutes
|
|||
* @Date: Friday, 18 December 2020 14:15:02
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
public class RouteConfig
|
||||
public class TableRouteConfig
|
||||
{
|
||||
private readonly IQueryable _queryable;
|
||||
private readonly IShardingEntity _shardingEntity;
|
||||
|
@ -17,7 +17,7 @@ namespace ShardingCore.Core.VirtualRoutes
|
|||
private readonly Expression _predicate;
|
||||
|
||||
|
||||
public RouteConfig(IQueryable queryable=null,IShardingEntity shardingEntity=null,object shardingKeyValue=null,Expression predicate=null)
|
||||
public TableRouteConfig(IQueryable queryable=null,IShardingEntity shardingEntity=null,object shardingKeyValue=null,Expression predicate=null)
|
||||
{
|
||||
_queryable = queryable;
|
||||
_shardingEntity = shardingEntity;
|
|
@ -2,6 +2,7 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using ShardingCore.Core.PhysicTables;
|
||||
using ShardingCore.Core.VirtualRoutes;
|
||||
using ShardingCore.Core.VirtualRoutes.TableRoutes;
|
||||
|
||||
namespace ShardingCore.Core.VirtualTables
|
||||
{
|
||||
|
@ -31,9 +32,9 @@ namespace ShardingCore.Core.VirtualTables
|
|||
/// <summary>
|
||||
/// 路由到具体的物理表 which physic table route
|
||||
/// </summary>
|
||||
/// <param name="routeConfig"></param>
|
||||
/// <param name="tableRouteConfig"></param>
|
||||
/// <returns></returns>
|
||||
List<IPhysicTable> RouteTo(RouteConfig routeConfig);
|
||||
List<IPhysicTable> RouteTo(TableRouteConfig tableRouteConfig);
|
||||
|
||||
/// <summary>
|
||||
/// 添加物理表 add physic table
|
||||
|
|
|
@ -16,52 +16,80 @@ namespace ShardingCore.Core.VirtualTables
|
|||
public interface IVirtualTableManager
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取所有的虚拟表 get all virtual table
|
||||
/// 添加虚拟表应用启动时 add virtual table when app start
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
List<IVirtualTable> GetAllVirtualTables();
|
||||
/// <param name="connectKey">链接</param>
|
||||
/// <param name="virtualTable">虚拟表</param>
|
||||
void AddVirtualTable(string connectKey, IVirtualTable virtualTable);
|
||||
|
||||
/// <summary>
|
||||
/// 获取虚拟表 get virtual table by sharding entity type
|
||||
/// </summary>
|
||||
/// <param name="connectKey"></param>
|
||||
/// <param name="shardingEntityType"></param>
|
||||
/// <returns></returns>
|
||||
IVirtualTable GetVirtualTable(Type shardingEntityType);
|
||||
IVirtualTable GetVirtualTable(string connectKey, Type shardingEntityType);
|
||||
|
||||
/// <summary>
|
||||
/// 获取虚拟表 get virtual table by sharding entity type
|
||||
/// </summary>
|
||||
/// <param name="connectKey"></param>
|
||||
/// <returns></returns>
|
||||
IVirtualTable<T> GetVirtualTable<T>() where T:class,IShardingEntity;
|
||||
|
||||
IVirtualTable<T> GetVirtualTable<T>(string connectKey) where T : class, IShardingEntity;
|
||||
/// <summary>
|
||||
/// 获取虚拟表 get virtual table by original table name
|
||||
/// </summary>
|
||||
/// <param name="connectKey"></param>
|
||||
/// <param name="originalTableName"></param>
|
||||
/// <returns></returns>
|
||||
IVirtualTable GetVirtualTable(string originalTableName);
|
||||
IVirtualTable GetVirtualTable(string connectKey,string originalTableName);
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 添加虚拟表应用启动时 add virtual table when app start
|
||||
/// 获取所有的虚拟表 get all virtual table
|
||||
/// </summary>
|
||||
/// <param name="virtualTable"></param>
|
||||
void AddVirtualTable(IVirtualTable virtualTable);
|
||||
/// <summary>
|
||||
/// 添加物理表 add physic table
|
||||
/// </summary>
|
||||
/// <param name="virtualTable"></param>
|
||||
/// <param name="physicTable"></param>
|
||||
void AddPhysicTable(IVirtualTable virtualTable, IPhysicTable physicTable);
|
||||
/// <summary>
|
||||
/// 添加物理表 add physic table
|
||||
/// </summary>
|
||||
/// <param name="shardingEntityType"></param>
|
||||
/// <param name="physicTable"></param>
|
||||
void AddPhysicTable(Type shardingEntityType, IPhysicTable physicTable);
|
||||
/// <summary>
|
||||
/// 判断是否是分表字段
|
||||
/// </summary>
|
||||
/// <param name="shardingEntityType"></param>
|
||||
/// <param name="shardingField"></param>
|
||||
/// <param name="connectKey"></param>
|
||||
/// <returns></returns>
|
||||
bool IsShardingKey(Type shardingEntityType, string shardingField);
|
||||
List<IVirtualTable> GetAllVirtualTables(string connectKey);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 添加物理表 add physic table
|
||||
/// </summary>
|
||||
/// <param name="connectKey"></param>
|
||||
/// <param name="virtualTable"></param>
|
||||
/// <param name="physicTable"></param>
|
||||
void AddPhysicTable(string connectKey,IVirtualTable virtualTable, IPhysicTable physicTable);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 添加物理表 add physic table
|
||||
/// </summary>
|
||||
/// <param name="connectKey"></param>
|
||||
/// <param name="shardingEntityType"></param>
|
||||
/// <param name="physicTable"></param>
|
||||
void AddPhysicTable(string connectKey, Type shardingEntityType, IPhysicTable physicTable);
|
||||
|
||||
///// <summary>
|
||||
///// 添加物理表 add physic table
|
||||
///// </summary>
|
||||
///// <param name="virtualTable"></param>
|
||||
///// <param name="physicTable"></param>
|
||||
//void AddPhysicTable(IVirtualTable virtualTable, IPhysicTable physicTable);
|
||||
///// <summary>
|
||||
///// 添加物理表 add physic table
|
||||
///// </summary>
|
||||
///// <param name="shardingEntityType"></param>
|
||||
///// <param name="physicTable"></param>
|
||||
//void AddPhysicTable(Type shardingEntityType, IPhysicTable physicTable);
|
||||
///// <summary>
|
||||
///// 判断是否是分表字段
|
||||
///// </summary>
|
||||
///// <param name="shardingEntityType"></param>
|
||||
///// <param name="shardingField"></param>
|
||||
///// <returns></returns>
|
||||
//bool IsShardingKey(Type shardingEntityType, string shardingField);
|
||||
|
||||
}
|
||||
}
|
|
@ -5,6 +5,7 @@ using System.Linq.Expressions;
|
|||
using Microsoft.Extensions.DependencyInjection;
|
||||
using ShardingCore.Core.PhysicTables;
|
||||
using ShardingCore.Core.VirtualRoutes;
|
||||
using ShardingCore.Core.VirtualRoutes.TableRoutes;
|
||||
using ShardingCore.Exceptions;
|
||||
using ShardingCore.Extensions;
|
||||
using ShardingCore.Utils;
|
||||
|
@ -29,9 +30,9 @@ namespace ShardingCore.Core.VirtualTables
|
|||
public ShardingEntityConfig ShardingConfig { get; }
|
||||
private readonly List<IPhysicTable> _physicTables = new List<IPhysicTable>();
|
||||
|
||||
public OneDbVirtualTable(IServiceProvider serviceProvider)
|
||||
public OneDbVirtualTable(IVirtualRoute<T> virtualRoute)
|
||||
{
|
||||
_virtualRoute = serviceProvider.GetService<IVirtualRoute<T>>() ?? throw new ShardingOwnerNotFoundException($"{EntityType}");
|
||||
_virtualRoute = virtualRoute;
|
||||
ShardingConfig = ShardingKeyUtil.Parse(EntityType);
|
||||
}
|
||||
|
||||
|
@ -40,19 +41,19 @@ namespace ShardingCore.Core.VirtualTables
|
|||
return _physicTables;
|
||||
}
|
||||
|
||||
public List<IPhysicTable> RouteTo(RouteConfig routeConfig)
|
||||
public List<IPhysicTable> RouteTo(TableRouteConfig tableRouteConfig)
|
||||
{
|
||||
var route = _virtualRoute;
|
||||
if (routeConfig.UseQueryable())
|
||||
return route.RouteWithWhere(_physicTables, routeConfig.GetQueryable());
|
||||
if (routeConfig.UsePredicate())
|
||||
return route.RouteWithWhere(_physicTables, new EnumerableQuery<T>((Expression<Func<T, bool>>) routeConfig.GetPredicate()));
|
||||
if (tableRouteConfig.UseQueryable())
|
||||
return route.RouteWithWhere(_physicTables, tableRouteConfig.GetQueryable());
|
||||
if (tableRouteConfig.UsePredicate())
|
||||
return route.RouteWithWhere(_physicTables, new EnumerableQuery<T>((Expression<Func<T, bool>>) tableRouteConfig.GetPredicate()));
|
||||
object shardingKeyValue = null;
|
||||
if (routeConfig.UseValue())
|
||||
shardingKeyValue = routeConfig.GetShardingKeyValue();
|
||||
if (tableRouteConfig.UseValue())
|
||||
shardingKeyValue = tableRouteConfig.GetShardingKeyValue();
|
||||
|
||||
if (routeConfig.UseEntity())
|
||||
shardingKeyValue = routeConfig.GetShardingEntity().GetPropertyValue(ShardingConfig.ShardingField);
|
||||
if (tableRouteConfig.UseEntity())
|
||||
shardingKeyValue = tableRouteConfig.GetShardingEntity().GetPropertyValue(ShardingConfig.ShardingField);
|
||||
|
||||
if (shardingKeyValue != null)
|
||||
{
|
||||
|
@ -60,7 +61,7 @@ namespace ShardingCore.Core.VirtualTables
|
|||
return new List<IPhysicTable>(1) {routeWithValue};
|
||||
}
|
||||
|
||||
throw new NotImplementedException(nameof(RouteConfig));
|
||||
throw new NotImplementedException(nameof(TableRouteConfig));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -19,91 +19,89 @@ namespace ShardingCore.Core.VirtualTables
|
|||
/// </summary>
|
||||
public class OneDbVirtualTableManager : IVirtualTableManager
|
||||
{
|
||||
private readonly ConcurrentDictionary<Type, IVirtualTable> _virtualTables = new ConcurrentDictionary<Type, IVirtualTable>();
|
||||
private readonly ConcurrentDictionary<string, ConcurrentDictionary<Type, IVirtualTable>> _shardingVirtualTables = new ConcurrentDictionary<string, ConcurrentDictionary<Type, IVirtualTable>>();
|
||||
|
||||
public OneDbVirtualTableManager(IServiceProvider serviceProvider)
|
||||
{
|
||||
var shardingEntities = AssemblyHelper.CurrentDomain.GetAssemblies().SelectMany(o => o.GetTypes())
|
||||
.Where(type => !String.IsNullOrEmpty(type.Namespace))
|
||||
.Where(type => !type.IsAbstract&&type.GetInterfaces()
|
||||
.Any(it => it.IsInterface &&typeof(IShardingEntity)==it)
|
||||
);
|
||||
foreach (var shardingEntity in shardingEntities)
|
||||
//var shardingEntities = AssemblyHelper.CurrentDomain.GetAssemblies().SelectMany(o => o.GetTypes())
|
||||
// .Where(type => !String.IsNullOrEmpty(type.Namespace))
|
||||
// .Where(type => !type.IsAbstract&&type.GetInterfaces()
|
||||
// .Any(it => it.IsInterface &&typeof(IShardingEntity)==it)
|
||||
// );
|
||||
//foreach (var shardingEntity in shardingEntities)
|
||||
//{
|
||||
// Type genericType = typeof(IVirtualTable<>);
|
||||
// Type interfaceType = genericType.MakeGenericType(shardingEntity);
|
||||
// var virtualTable = (IVirtualTable)serviceProvider.GetService(interfaceType);
|
||||
// _virtualTables.TryAdd(virtualTable.EntityType, virtualTable);
|
||||
//}
|
||||
}
|
||||
|
||||
public void AddVirtualTable(string connectKey, IVirtualTable virtualTable)
|
||||
{
|
||||
if (!_shardingVirtualTables.ContainsKey(connectKey))
|
||||
{
|
||||
Type genericType = typeof(IVirtualTable<>);
|
||||
Type interfaceType = genericType.MakeGenericType(shardingEntity);
|
||||
var virtualTable = (IVirtualTable)serviceProvider.GetService(interfaceType);
|
||||
_virtualTables.TryAdd(virtualTable.EntityType, virtualTable);
|
||||
_shardingVirtualTables.TryAdd(connectKey, new ConcurrentDictionary<Type, IVirtualTable>());
|
||||
}
|
||||
|
||||
var shardingVirtualTable = _shardingVirtualTables[connectKey];
|
||||
shardingVirtualTable.TryAdd(virtualTable.EntityType, virtualTable);
|
||||
}
|
||||
|
||||
public List<IVirtualTable> GetAllVirtualTables()
|
||||
public IVirtualTable GetVirtualTable(string connectKey, Type shardingEntityType)
|
||||
{
|
||||
return _virtualTables.Select(o=>o.Value).ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定类型的虚拟表
|
||||
/// </summary>
|
||||
/// <param name="shardingEntityType"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="VirtualTableNotFoundException"></exception>
|
||||
public IVirtualTable GetVirtualTable(Type shardingEntityType)
|
||||
{
|
||||
if (!_virtualTables.TryGetValue(shardingEntityType, out var virtualTable) || virtualTable == null)
|
||||
throw new VirtualTableNotFoundException($"{shardingEntityType}");
|
||||
if (!_shardingVirtualTables.TryGetValue(connectKey, out var tableKv))
|
||||
throw new ShardingVirtualTableNotFoundException(connectKey);
|
||||
if (!tableKv.TryGetValue(shardingEntityType, out var virtualTable))
|
||||
throw new ShardingVirtualTableNotFoundException($"[{connectKey}]-[{shardingEntityType}]");
|
||||
return virtualTable;
|
||||
}
|
||||
|
||||
public IVirtualTable<T> GetVirtualTable<T>() where T : class, IShardingEntity
|
||||
public IVirtualTable<T> GetVirtualTable<T>(string connectKey) where T : class, IShardingEntity
|
||||
{
|
||||
var shardingEntityType = typeof(T);
|
||||
return (IVirtualTable<T>)GetVirtualTable(shardingEntityType);
|
||||
return (IVirtualTable<T>)GetVirtualTable(connectKey, typeof(T));
|
||||
}
|
||||
|
||||
public IVirtualTable GetVirtualTable(string originalTableName)
|
||||
public IVirtualTable GetVirtualTable(string connectKey, string originalTableName)
|
||||
{
|
||||
return _virtualTables.Values.FirstOrDefault(o => o.GetOriginalTableName() == originalTableName) ?? throw new CreateSqlVirtualTableNotFoundException(originalTableName);
|
||||
if (!_shardingVirtualTables.TryGetValue(connectKey, out var tableKv))
|
||||
throw new ShardingVirtualTableNotFoundException(connectKey);
|
||||
var virtualTable = tableKv.Where(o => o.Value.GetOriginalTableName() == originalTableName).Select(o=>o.Value).FirstOrDefault();
|
||||
if (virtualTable==null)
|
||||
throw new ShardingVirtualTableNotFoundException($"[{connectKey}]-[{originalTableName}]");
|
||||
return virtualTable;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加虚拟表
|
||||
/// </summary>
|
||||
/// <param name="virtualTable"></param>
|
||||
public void AddVirtualTable(IVirtualTable virtualTable)
|
||||
public List<IVirtualTable> GetAllVirtualTables(string connectKey)
|
||||
{
|
||||
_virtualTables.TryAdd(virtualTable.EntityType, virtualTable);
|
||||
if (!_shardingVirtualTables.ContainsKey(connectKey))
|
||||
return new List<IVirtualTable>(0);
|
||||
return _shardingVirtualTables[connectKey].Select(o => o.Value).ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加物理表
|
||||
/// </summary>
|
||||
/// <param name="virtualTable"></param>
|
||||
/// <param name="physicTable"></param>
|
||||
public void AddPhysicTable(IVirtualTable virtualTable, IPhysicTable physicTable)
|
||||
public void AddPhysicTable(string connectKey, IVirtualTable virtualTable, IPhysicTable physicTable)
|
||||
{
|
||||
AddPhysicTable(virtualTable.EntityType, physicTable);
|
||||
AddPhysicTable(connectKey, virtualTable.EntityType, physicTable);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加物理表
|
||||
/// </summary>
|
||||
/// <param name="shardingEntityType"></param>
|
||||
/// <param name="physicTable"></param>
|
||||
public void AddPhysicTable(Type shardingEntityType, IPhysicTable physicTable)
|
||||
public void AddPhysicTable(string connectKey, Type shardingEntityType, IPhysicTable physicTable)
|
||||
{
|
||||
var virtualTable = GetVirtualTable(shardingEntityType);
|
||||
if (!_shardingVirtualTables.ContainsKey(connectKey))
|
||||
throw new ShardingConnectKeyNotFoundException(connectKey);
|
||||
var virtualTable = GetVirtualTable(connectKey,shardingEntityType);
|
||||
virtualTable.AddPhysicTable(physicTable);
|
||||
}
|
||||
/// <summary>
|
||||
/// 是否是分表字段
|
||||
/// </summary>
|
||||
/// <param name="shardingEntityType"></param>
|
||||
/// <param name="shardingField"></param>
|
||||
/// <returns></returns>
|
||||
public bool IsShardingKey(Type shardingEntityType, string shardingField)
|
||||
{
|
||||
return _virtualTables.TryGetValue(shardingEntityType, out var virtualTable) && virtualTable.ShardingConfig.ShardingField == shardingField;
|
||||
}
|
||||
|
||||
|
||||
///// <summary>
|
||||
///// 是否是分表字段
|
||||
///// </summary>
|
||||
///// <param name="shardingEntityType"></param>
|
||||
///// <param name="shardingField"></param>
|
||||
///// <returns></returns>
|
||||
//public bool IsShardingKey(Type shardingEntityType, string shardingField)
|
||||
//{
|
||||
// return _virtualTables.TryGetValue(shardingEntityType, out var virtualTable) && virtualTable.ShardingConfig.ShardingField == shardingField;
|
||||
//}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
using ShardingCore.DbContexts.ShardingTableDbContexts;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using ShardingCore.DbContexts.ShardingDbContexts;
|
||||
|
||||
namespace ShardingCore.DbContexts
|
||||
{
|
||||
|
@ -10,6 +11,6 @@ namespace ShardingCore.DbContexts
|
|||
*/
|
||||
public interface IShardingDbContextFactory
|
||||
{
|
||||
ShardingTableDbContext Create(ShardingTableDbContextOptions shardingDbContextOptions);
|
||||
DbContext Create(string connectKey,ShardingDbContextOptions shardingDbContextOptions);
|
||||
}
|
||||
}
|
|
@ -10,6 +10,6 @@ namespace ShardingCore.DbContexts
|
|||
*/
|
||||
public interface IShardingParallelDbContextFactory
|
||||
{
|
||||
DbContext Create(string tail);
|
||||
DbContext Create(string connectKey, string tail);
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
using Microsoft.EntityFrameworkCore;
|
||||
using ShardingCore.DbContexts.ShardingDbContexts;
|
||||
using ShardingCore.DbContexts.ShardingTableDbContexts;
|
||||
|
||||
namespace ShardingCore.DbContexts
|
||||
{
|
||||
|
@ -11,9 +11,16 @@ namespace ShardingCore.DbContexts
|
|||
*/
|
||||
public class ShardingDbContextFactory:IShardingDbContextFactory
|
||||
{
|
||||
public ShardingTableDbContext Create(ShardingTableDbContextOptions shardingDbContextOptions)
|
||||
private readonly IShardingCoreOptions _shardingCoreOptions;
|
||||
|
||||
public ShardingDbContextFactory(IShardingCoreOptions shardingCoreOptions)
|
||||
{
|
||||
return new ShardingDbContext(shardingDbContextOptions);
|
||||
_shardingCoreOptions = shardingCoreOptions;
|
||||
}
|
||||
public DbContext Create(string connectKey, ShardingDbContextOptions shardingDbContextOptions)
|
||||
{
|
||||
var shardingConfigEntry = _shardingCoreOptions.GetShardingConfig(connectKey);
|
||||
return shardingConfigEntry.Creator(shardingDbContextOptions);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,43 +1,43 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace ShardingCore.DbContexts.ShardingTableDbContexts
|
||||
namespace ShardingCore.DbContexts.ShardingDbContexts
|
||||
{
|
||||
/*
|
||||
* @Author: xjm
|
||||
* @Description: 用于分表使用 分表比较特殊必须使用规定的dbcontext
|
||||
* @Date: Thursday, 18 February 2021 15:06:46
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public abstract class ShardingTableDbContext:DbContext
|
||||
/*
|
||||
* @Author: xjm
|
||||
* @Description:
|
||||
* @Date: 2021/3/4 16:11:18
|
||||
* @Ver: 1.0
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
public abstract class AbstractShardingDbContext : DbContext
|
||||
{
|
||||
public string Tail { get; }
|
||||
public Dictionary<Type,VirtualTableDbContextConfig> VirtualTableConfigs { get; }
|
||||
public bool RemoveRemoveShardingEntity { get; }
|
||||
|
||||
public ShardingTableDbContext(ShardingTableDbContextOptions options)
|
||||
public Dictionary<Type, VirtualTableDbContextConfig> VirtualTableConfigs { get; }
|
||||
|
||||
protected AbstractShardingDbContext(ShardingDbContextOptions options)
|
||||
{
|
||||
Tail = options.Tail;
|
||||
VirtualTableConfigs = options.VirtualTableDbContextConfigs.ToDictionary(o=>o.ShardingEntityType,o=>o);
|
||||
RemoveRemoveShardingEntity = options.RemoveShardingEntity;
|
||||
VirtualTableConfigs = options.VirtualTableDbContextConfigs.ToDictionary(o => o.ShardingEntityType, o => o);
|
||||
}
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
{
|
||||
base.OnModelCreating(modelBuilder);
|
||||
OnShardingModelCreating(modelBuilder);
|
||||
OnModelCreatingAfter(modelBuilder);
|
||||
}
|
||||
|
||||
protected abstract void OnShardingModelCreating(ModelBuilder modelBuilder);
|
||||
|
||||
protected virtual void OnModelCreatingAfter(ModelBuilder modelBuilder)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(Tail))
|
||||
{
|
||||
var mutableEntityTypes = modelBuilder.Model.GetEntityTypes().Where(o=>VirtualTableConfigs.ContainsKey(o.ClrType));
|
||||
var mutableEntityTypes = modelBuilder.Model.GetEntityTypes().Where(o => VirtualTableConfigs.ContainsKey(o.ClrType));
|
||||
foreach (var entityType in mutableEntityTypes)
|
||||
{
|
||||
var virtualTableConfig = VirtualTableConfigs[entityType.ClrType];
|
|
@ -1,147 +0,0 @@
|
|||
// using System;
|
||||
// using System.Collections.Concurrent;
|
||||
// using System.Collections.Generic;
|
||||
// using System.Linq;
|
||||
// using Microsoft.EntityFrameworkCore;
|
||||
// using ShardingCore.Extensions;
|
||||
// using ShardingCore.Helpers;
|
||||
//
|
||||
// namespace ShardingCore.DbContexts.ShardingDbContexts
|
||||
// {
|
||||
// /*
|
||||
// * @Author: xjm
|
||||
// * @Description:
|
||||
// * @Date: Wednesday, 16 December 2020 15:28:12
|
||||
// * @Email: 326308290@qq.com
|
||||
// */
|
||||
// public class ShardingDbContext : DbContext
|
||||
// {
|
||||
// public string Tail { get; }
|
||||
// public List<VirtualTableDbContextConfig> VirtualTableConfigs { get; }
|
||||
// public bool RemoveRemoveShardingEntity { get; }
|
||||
// private static readonly ConcurrentDictionary<Type, Type> _entityTypeConfigurationTypeCaches = new ConcurrentDictionary<Type, Type>();
|
||||
// private static readonly object buildEntityTypeConfigurationLock = new object();
|
||||
//
|
||||
// public ShardingDbContext(ShardingDbContextOptions shardingDbContextOptions) : base(shardingDbContextOptions.DbContextOptions)
|
||||
// {
|
||||
// Tail = shardingDbContextOptions.Tail;
|
||||
// VirtualTableConfigs = shardingDbContextOptions.VirtualTableDbContextConfigs;
|
||||
// RemoveRemoveShardingEntity = shardingDbContextOptions.RemoveShardingEntity;
|
||||
// }
|
||||
//
|
||||
// /// <summary>
|
||||
// /// 模型构建
|
||||
// /// </summary>
|
||||
// /// <param name="modelBuilder"></param>
|
||||
// protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
// {
|
||||
// if (!string.IsNullOrWhiteSpace(Tail))
|
||||
// {
|
||||
// //支持IEntityTypeConfiguration配置
|
||||
// VirtualTableConfigs.ForEach(virtualTable =>
|
||||
// {
|
||||
// var shardingEntityType = virtualTable.ShardingEntityType;
|
||||
// if (!_entityTypeConfigurationTypeCaches.TryGetValue(shardingEntityType, out var entityTypeConfigurationType))
|
||||
// throw new Exception($"未找到对应的类型无法进行IEntityTypeConfiguration配置:[{shardingEntityType.Name}]");
|
||||
// if (entityTypeConfigurationType == null)
|
||||
// throw new NotSupportedException($"{shardingEntityType}的[IBaseEntityTypeConfiguration]未找到");
|
||||
// var method = modelBuilder.GetType()
|
||||
// .GetMethods()
|
||||
// .FirstOrDefault(x => x.Name == nameof(ModelBuilder.ApplyConfiguration)
|
||||
// && x.GetParameters().Count() == 1
|
||||
// && x.GetParameters()[0].ParameterType.GetGenericTypeDefinition() == typeof(IEntityTypeConfiguration<>));
|
||||
// method.MakeGenericMethod(shardingEntityType).Invoke(modelBuilder, new object[] {Activator.CreateInstance(entityTypeConfigurationType)});
|
||||
// });
|
||||
//
|
||||
// VirtualTableConfigs.ForEach(virtualTableConfig =>
|
||||
// {
|
||||
// var shardingEntity = virtualTableConfig.ShardingEntityType;
|
||||
// var tailPrefix = virtualTableConfig.TailPrefix;
|
||||
// var entity = modelBuilder.Entity(shardingEntity);
|
||||
// var tableName = virtualTableConfig.OriginalTableName;
|
||||
// if (string.IsNullOrWhiteSpace(tableName))
|
||||
// throw new ArgumentNullException($"{shardingEntity}:无法找到对应的原始表名。");
|
||||
// #if DEBUG
|
||||
// Console.WriteLine($"映射表:[tableName]-->[{tableName}{tailPrefix}{Tail}]");
|
||||
// #endif
|
||||
// entity.ToTable($"{tableName}{tailPrefix}{Tail}");
|
||||
// });
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// BuildEntityTypeConfigurationCaches();
|
||||
// //支持IEntityTypeConfiguration配置
|
||||
// foreach (var entityTypeConfigurationType in _entityTypeConfigurationTypeCaches)
|
||||
// {
|
||||
// var shardingEntityType = entityTypeConfigurationType.Key;
|
||||
// if (RemoveRemoveShardingEntity && shardingEntityType.IsShardingEntity())
|
||||
// continue;
|
||||
// var method = modelBuilder.GetType()
|
||||
// .GetMethods()
|
||||
// .FirstOrDefault(x => x.Name == nameof(ModelBuilder.ApplyConfiguration)
|
||||
// && x.GetParameters().Count() == 1
|
||||
// && x.GetParameters()[0].ParameterType.GetGenericTypeDefinition() == typeof(IEntityTypeConfiguration<>));
|
||||
// method.MakeGenericMethod(shardingEntityType).Invoke(modelBuilder, new object[] {Activator.CreateInstance(entityTypeConfigurationType.Value)});
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// ////字段注释,需要开启程序集XML文档
|
||||
//
|
||||
// //foreach (var entityType in modelBuilder.Model.GetEntityTypes())
|
||||
// //{
|
||||
// // var comments = XmlHelper.GetPropertyCommentBySummary(entityType.ClrType) ?? new Dictionary<string, string>();
|
||||
// // foreach (var property in entityType.GetProperties())
|
||||
// // {
|
||||
// // if (comments.ContainsKey(property.Name))
|
||||
// // {
|
||||
// // property.SetComment(comments[property.Name]);
|
||||
// // }
|
||||
// // }
|
||||
// //}
|
||||
// //
|
||||
// #if !EFCORE2
|
||||
// //字段注释,需要开启程序集XML文档
|
||||
// foreach (var entityType in modelBuilder.Model.GetEntityTypes())
|
||||
// {
|
||||
// var comments = XmlHelper.GetProperyCommentBySummary(entityType.ClrType) ?? new Dictionary<string, string>();
|
||||
// foreach (var property in entityType.GetProperties())
|
||||
// {
|
||||
// if (comments.ContainsKey(property.Name))
|
||||
// {
|
||||
// property.SetComment(comments[property.Name]);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// #endif
|
||||
// }
|
||||
//
|
||||
// /// <summary>
|
||||
// /// 构建类型
|
||||
// /// </summary>
|
||||
// public void BuildEntityTypeConfigurationCaches()
|
||||
// {
|
||||
// if (!_entityTypeConfigurationTypeCaches.Any())
|
||||
// {
|
||||
// lock (buildEntityTypeConfigurationLock)
|
||||
// {
|
||||
// if (!_entityTypeConfigurationTypeCaches.Any())
|
||||
// {
|
||||
// var typesToRegister = AssemblyHelper.CurrentDomain.GetAssemblies().SelectMany(o => o.GetTypes())
|
||||
// .Where(type => !String.IsNullOrEmpty(type.Namespace))
|
||||
// //获取类型namespce不是空的所有接口是范型的当前范型是IEntityTypeConfiguration<>的进行fluent api 映射
|
||||
// .Where(type => !type.IsAbstract && type.GetInterfaces()
|
||||
// .Any(it => it.IsInterface && it.IsGenericType && it.GetGenericTypeDefinition() == typeof(IEntityTypeConfiguration<>)
|
||||
// && it.GetGenericArguments().Any())
|
||||
// ).ToDictionary(o => o.GetInterfaces().FirstOrDefault(it => it.IsInterface && it.IsGenericType && it.GetGenericTypeDefinition() == typeof(IEntityTypeConfiguration<>)
|
||||
// && it.GetGenericArguments().Any())
|
||||
// ?.GetGenericArguments()[0], o => o);
|
||||
// foreach (var type in typesToRegister)
|
||||
// {
|
||||
// _entityTypeConfigurationTypeCaches.TryAdd(type.Key, type.Value);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
|
@ -1,28 +1,26 @@
|
|||
// using System.Collections.Generic;
|
||||
// using Microsoft.EntityFrameworkCore;
|
||||
//
|
||||
// namespace ShardingCore.DbContexts.ShardingDbContexts
|
||||
// {
|
||||
// /*
|
||||
// * @Author: xjm
|
||||
// * @Description:
|
||||
// * @Date: Wednesday, 16 December 2020 16:15:43
|
||||
// * @Email: 326308290@qq.com
|
||||
// */
|
||||
// public class ShardingDbContextOptions
|
||||
// {
|
||||
//
|
||||
// public ShardingDbContextOptions(DbContextOptions dbContextOptions, string tail, List<VirtualTableDbContextConfig> virtualTableDbContextConfigs, bool removeShardingEntity=false)
|
||||
// {
|
||||
// DbContextOptions = dbContextOptions;
|
||||
// Tail = tail;
|
||||
// VirtualTableDbContextConfigs = virtualTableDbContextConfigs;
|
||||
// RemoveShardingEntity = removeShardingEntity;
|
||||
// }
|
||||
//
|
||||
// public DbContextOptions DbContextOptions { get; }
|
||||
// public string Tail { get; }
|
||||
// public List<VirtualTableDbContextConfig> VirtualTableDbContextConfigs { get; }
|
||||
// public bool RemoveShardingEntity { get;}
|
||||
// }
|
||||
// }
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace ShardingCore.DbContexts.ShardingDbContexts
|
||||
{
|
||||
/*
|
||||
* @Author: xjm
|
||||
* @Description:
|
||||
* @Date: Wednesday, 16 December 2020 16:15:43
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
public class ShardingDbContextOptions
|
||||
{
|
||||
|
||||
public ShardingDbContextOptions(DbContextOptions dbContextOptions, string tail, List<VirtualTableDbContextConfig> virtualTableDbContextConfigs)
|
||||
{
|
||||
DbContextOptions = dbContextOptions;
|
||||
Tail = tail;
|
||||
VirtualTableDbContextConfigs = virtualTableDbContextConfigs;
|
||||
}
|
||||
|
||||
public DbContextOptions DbContextOptions { get; }
|
||||
public string Tail { get; }
|
||||
public List<VirtualTableDbContextConfig> VirtualTableDbContextConfigs { get; }
|
||||
}
|
||||
}
|
|
@ -1,34 +1,34 @@
|
|||
// using System;
|
||||
//
|
||||
// namespace ShardingCore.DbContexts.ShardingDbContexts
|
||||
// {
|
||||
// /*
|
||||
// * @Author: xjm
|
||||
// * @Description:
|
||||
// * @Date: Friday, 01 January 2021 16:24:57
|
||||
// * @Email: 326308290@qq.com
|
||||
// */
|
||||
// public class VirtualTableDbContextConfig
|
||||
// {
|
||||
// public VirtualTableDbContextConfig(Type shardingEntityType, string originalTableName, string tailPrefix)
|
||||
// {
|
||||
// ShardingEntityType = shardingEntityType;
|
||||
// OriginalTableName = originalTableName;
|
||||
// TailPrefix = tailPrefix;
|
||||
// }
|
||||
//
|
||||
// /// <summary>
|
||||
// /// 分表实体类型
|
||||
// /// </summary>
|
||||
// public Type ShardingEntityType { get; }
|
||||
//
|
||||
// /// <summary>
|
||||
// /// 原始表名不带后缀
|
||||
// /// </summary>
|
||||
// public string OriginalTableName { get; }
|
||||
// /// <summary>
|
||||
// /// 表尾巴前缀
|
||||
// /// </summary>
|
||||
// public string TailPrefix { get; }
|
||||
// }
|
||||
// }
|
||||
using System;
|
||||
|
||||
namespace ShardingCore.DbContexts.ShardingDbContexts
|
||||
{
|
||||
/*
|
||||
* @Author: xjm
|
||||
* @Description:
|
||||
* @Date: Friday, 01 January 2021 16:24:57
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
public class VirtualTableDbContextConfig
|
||||
{
|
||||
public VirtualTableDbContextConfig(Type shardingEntityType, string originalTableName, string tailPrefix)
|
||||
{
|
||||
ShardingEntityType = shardingEntityType;
|
||||
OriginalTableName = originalTableName;
|
||||
TailPrefix = tailPrefix;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 分表实体类型
|
||||
/// </summary>
|
||||
public Type ShardingEntityType { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 原始表名不带后缀
|
||||
/// </summary>
|
||||
public string OriginalTableName { get; }
|
||||
/// <summary>
|
||||
/// 表尾巴前缀
|
||||
/// </summary>
|
||||
public string TailPrefix { get; }
|
||||
}
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace ShardingCore.DbContexts
|
||||
{
|
||||
/*
|
||||
* @Author: xjm
|
||||
* @Description:
|
||||
* @Date: Monday, 22 February 2021 16:45:11
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
public class ShardingParallelDbContextFactoryManager:IShardingParallelDbContextFactoryManager
|
||||
{
|
||||
private readonly Dictionary<>
|
||||
public DbContext CreateDbContext(string connectKey, string tail)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace ShardingCore.DbContexts.ShardingTableDbContexts
|
||||
{
|
||||
/*
|
||||
* @Author: xjm
|
||||
* @Description:
|
||||
* @Date: Thursday, 18 February 2021 15:22:46
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
public class ShardingTableDbContextOptions
|
||||
{
|
||||
|
||||
public ShardingTableDbContextOptions(DbContextOptions dbContextOptions, string tail, List<VirtualTableDbContextConfig> virtualTableDbContextConfigs, bool removeShardingEntity=false)
|
||||
{
|
||||
DbContextOptions = dbContextOptions;
|
||||
Tail = tail;
|
||||
VirtualTableDbContextConfigs = virtualTableDbContextConfigs;
|
||||
RemoveShardingEntity = removeShardingEntity;
|
||||
}
|
||||
|
||||
public DbContextOptions DbContextOptions { get; }
|
||||
public string Tail { get; }
|
||||
public List<VirtualTableDbContextConfig> VirtualTableDbContextConfigs { get; }
|
||||
public bool RemoveShardingEntity { get;}
|
||||
}
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace ShardingCore.DbContexts.ShardingTableDbContexts
|
||||
{
|
||||
/*
|
||||
* @Author: xjm
|
||||
* @Description:
|
||||
* @Date: Friday, 01 January 2021 16:24:57
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
public class VirtualTableDbContextConfig
|
||||
{
|
||||
public VirtualTableDbContextConfig(Type shardingEntityType, string originalTableName, string tailPrefix)
|
||||
{
|
||||
ShardingEntityType = shardingEntityType;
|
||||
OriginalTableName = originalTableName;
|
||||
TailPrefix = tailPrefix;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 分表实体类型
|
||||
/// </summary>
|
||||
public Type ShardingEntityType { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 原始表名不带后缀
|
||||
/// </summary>
|
||||
public string OriginalTableName { get; }
|
||||
/// <summary>
|
||||
/// 表尾巴前缀
|
||||
/// </summary>
|
||||
public string TailPrefix { get; }
|
||||
}
|
||||
}
|
|
@ -11,6 +11,6 @@ namespace ShardingCore.DbContexts.VirtualDbContexts
|
|||
*/
|
||||
public interface IDbContextOptionsProvider:IDisposable
|
||||
{
|
||||
DbContextOptions GetDbContextOptions();
|
||||
DbContextOptions GetDbContextOptions(string connectKey);
|
||||
}
|
||||
}
|
|
@ -13,13 +13,13 @@ namespace ShardingCore.DbContexts.VirtualDbContexts
|
|||
*/
|
||||
public class ShardingBatchDeleteEntry<T>where T:class
|
||||
{
|
||||
public ShardingBatchDeleteEntry(Expression<Func<T, bool>> @where, List<DbContext> dbContexts)
|
||||
public ShardingBatchDeleteEntry(Expression<Func<T, bool>> @where, List<(string connectKey,List<DbContext>)> dbContextGroups)
|
||||
{
|
||||
Where = @where;
|
||||
DbContexts = dbContexts;
|
||||
DbContextGroups = dbContextGroups;
|
||||
}
|
||||
|
||||
public Expression<Func<T, bool>> Where{ get; }
|
||||
public List<DbContext> DbContexts { get; }
|
||||
public List<(string connectKey, List<DbContext>)> DbContextGroups { get; }
|
||||
}
|
||||
}
|
|
@ -13,15 +13,15 @@ namespace ShardingCore.DbContexts.VirtualDbContexts
|
|||
*/
|
||||
public class ShardingBatchUpdateEntry<T> where T:class
|
||||
{
|
||||
public ShardingBatchUpdateEntry(Expression<Func<T, bool>> @where, Expression<Func<T, T>> updateExp, List<DbContext> dbContexts)
|
||||
public ShardingBatchUpdateEntry(Expression<Func<T, bool>> @where, Expression<Func<T, T>> updateExp, List<(string connectKey, List<DbContext> dbContexts)> dbContextGroups)
|
||||
{
|
||||
Where = @where;
|
||||
UpdateExp = updateExp;
|
||||
DbContexts = dbContexts;
|
||||
DbContextGroups = dbContextGroups;
|
||||
}
|
||||
|
||||
public Expression<Func<T, bool>> Where {get;}
|
||||
public Expression<Func<T, T>> UpdateExp{get;}
|
||||
public List<DbContext> DbContexts { get; }
|
||||
public List<(string connectKey, List<DbContext> dbContexts)> DbContextGroups { get; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.Common;
|
||||
using System.Text;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace ShardingCore.DbContexts.VirtualDbContexts.ShareDbContextOptionsProviders
|
||||
{
|
||||
/*
|
||||
* @Author: xjm
|
||||
* @Description:
|
||||
* @Date: 2021/3/5 9:04:12
|
||||
* @Ver: 1.0
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
public class ShareDbContextWrapItem
|
||||
{
|
||||
public ShareDbContextWrapItem(DbConnection connection, DbContextOptions contextOptions)
|
||||
{
|
||||
Connection = connection;
|
||||
ContextOptions = contextOptions;
|
||||
}
|
||||
|
||||
public string ConnectKey { get; }
|
||||
public DbConnection Connection { get; }
|
||||
public DbContextOptions ContextOptions { get; }
|
||||
}
|
||||
}
|
|
@ -6,35 +6,39 @@ using System.Linq.Expressions;
|
|||
using System.Threading.Tasks;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using ShardingCore.Core;
|
||||
using ShardingCore.Core.VirtualDataSources;
|
||||
using ShardingCore.Core.VirtualRoutes;
|
||||
using ShardingCore.Core.VirtualRoutes.TableRoutes;
|
||||
using ShardingCore.Core.VirtualTables;
|
||||
using ShardingCore.DbContexts.ShardingTableDbContexts;
|
||||
using ShardingCore.DbContexts.ShardingDbContexts;
|
||||
using ShardingCore.DbContexts.Transactions;
|
||||
using ShardingCore.Exceptions;
|
||||
using ShardingCore.Extensions;
|
||||
|
||||
namespace ShardingCore.DbContexts.VirtualDbContexts
|
||||
{
|
||||
/*
|
||||
* @Author: xjm
|
||||
* @Description:
|
||||
* @Date: Thursday, 17 December 2020 21:50:49
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
/*
|
||||
* @Author: xjm
|
||||
* @Description:
|
||||
* @Date: Thursday, 17 December 2020 21:50:49
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
public class VirtualDbContext : AbstractInjectVirtualDbContext, IVirtualDbContext
|
||||
{
|
||||
private readonly string EMPTY_SHARDING_TAIL_ID = Guid.NewGuid().ToString("n");
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly IVirtualDataSourceManager _virtualDataSourceManager;
|
||||
private readonly IVirtualTableManager _virtualTableManager;
|
||||
private readonly IShardingDbContextFactory _shardingDbContextFactory;
|
||||
private readonly ConcurrentDictionary<string, DbContext> _dbContextCaches = new ConcurrentDictionary<string, DbContext>();
|
||||
private readonly ConcurrentDictionary<string, ConcurrentDictionary<string, DbContext>> _dbContextCaches = new ConcurrentDictionary<string,ConcurrentDictionary<string, DbContext>>();
|
||||
|
||||
private IShardingTransaction _dbTransaction = new ShardingTransaction();
|
||||
|
||||
public VirtualDbContext(IServiceProvider serviceProvider,
|
||||
public VirtualDbContext(IServiceProvider serviceProvider, IVirtualDataSourceManager virtualDataSourceManager,
|
||||
IVirtualTableManager virtualTableManager, IShardingDbContextFactory shardingDbContextFactory) : base(serviceProvider)
|
||||
{
|
||||
_serviceProvider = serviceProvider;
|
||||
_virtualDataSourceManager = virtualDataSourceManager;
|
||||
_virtualTableManager = virtualTableManager;
|
||||
_shardingDbContextFactory = shardingDbContextFactory;
|
||||
}
|
||||
|
@ -45,7 +49,13 @@ namespace ShardingCore.DbContexts.VirtualDbContexts
|
|||
public IShardingTransaction BeginTransaction()
|
||||
{
|
||||
_dbTransaction.Open();
|
||||
_dbContextCaches.ForEach(kv => { _dbTransaction.Use(kv.Value); });
|
||||
_dbContextCaches.ForEach(kv =>
|
||||
{
|
||||
kv.Value.ForEach(d =>
|
||||
{
|
||||
_dbTransaction.Use(d.Value);
|
||||
});
|
||||
});
|
||||
return _dbTransaction;
|
||||
}
|
||||
|
||||
|
@ -62,7 +72,7 @@ namespace ShardingCore.DbContexts.VirtualDbContexts
|
|||
|
||||
public IQueryable<T> Set<T>() where T : class
|
||||
{
|
||||
return GetOrCreateShardingDbContext(EMPTY_SHARDING_TAIL_ID).Set<T>().AsNoTracking();
|
||||
return GetOrCreateShardingDbContext(_virtualDataSourceManager.GetDefaultConnectKey(),EMPTY_SHARDING_TAIL_ID).Set<T>().AsNoTracking();
|
||||
}
|
||||
|
||||
public async Task<int> InsertAsync<T>(T entity) where T : class
|
||||
|
@ -85,7 +95,7 @@ namespace ShardingCore.DbContexts.VirtualDbContexts
|
|||
|
||||
foreach (var group in groups)
|
||||
{
|
||||
await group.Key.AddRangeAsync(group.Select(o=>o.Entity));
|
||||
await group.Key.AddRangeAsync(group.Select(o => o.Entity));
|
||||
}
|
||||
|
||||
return entities.Count;
|
||||
|
@ -111,7 +121,7 @@ namespace ShardingCore.DbContexts.VirtualDbContexts
|
|||
|
||||
foreach (var group in groups)
|
||||
{
|
||||
group.Key.UpdateRange(group.Select(o=>o.Entity));
|
||||
group.Key.UpdateRange(group.Select(o => o.Entity));
|
||||
}
|
||||
|
||||
return Task.FromResult(entities.Count);
|
||||
|
@ -137,7 +147,7 @@ namespace ShardingCore.DbContexts.VirtualDbContexts
|
|||
|
||||
foreach (var group in groups)
|
||||
{
|
||||
group.Key.RemoveRange(group.Select(o=>o.Entity));
|
||||
group.Key.RemoveRange(group.Select(o => o.Entity));
|
||||
}
|
||||
|
||||
return Task.FromResult(entities.Count);
|
||||
|
@ -145,7 +155,7 @@ namespace ShardingCore.DbContexts.VirtualDbContexts
|
|||
|
||||
public async Task<int> SaveChangesAsync()
|
||||
{
|
||||
var transOpenNow = !_dbTransaction.IsOpened&&_dbContextCaches.Count>1;
|
||||
var transOpenNow = !_dbTransaction.IsOpened && _dbContextCaches.Count > 1;
|
||||
if (transOpenNow)
|
||||
{
|
||||
BeginTransaction();
|
||||
|
@ -153,7 +163,10 @@ namespace ShardingCore.DbContexts.VirtualDbContexts
|
|||
var effects = 0;
|
||||
foreach (var dbContextCache in _dbContextCaches)
|
||||
{
|
||||
effects += await dbContextCache.Value.SaveChangesAsync();
|
||||
foreach (var dbContext in dbContextCache.Value)
|
||||
{
|
||||
effects += await dbContext.Value.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
|
||||
if (transOpenNow)
|
||||
|
@ -182,7 +195,7 @@ namespace ShardingCore.DbContexts.VirtualDbContexts
|
|||
|
||||
foreach (var group in groups)
|
||||
{
|
||||
group.Key.AddRange(group.Select(o=>o.Entity));
|
||||
group.Key.AddRange(group.Select(o => o.Entity));
|
||||
}
|
||||
|
||||
return entities.Count;
|
||||
|
@ -208,7 +221,7 @@ namespace ShardingCore.DbContexts.VirtualDbContexts
|
|||
|
||||
foreach (var group in groups)
|
||||
{
|
||||
group.Key.UpdateRange(group.Select(o=>o.Entity));
|
||||
group.Key.UpdateRange(group.Select(o => o.Entity));
|
||||
}
|
||||
|
||||
return entities.Count;
|
||||
|
@ -234,7 +247,7 @@ namespace ShardingCore.DbContexts.VirtualDbContexts
|
|||
|
||||
foreach (var group in groups)
|
||||
{
|
||||
group.Key.RemoveRange(group.Select(o=>o.Entity));
|
||||
group.Key.RemoveRange(group.Select(o => o.Entity));
|
||||
}
|
||||
|
||||
return entities.Count;
|
||||
|
@ -242,7 +255,7 @@ namespace ShardingCore.DbContexts.VirtualDbContexts
|
|||
|
||||
public int SaveChanges()
|
||||
{
|
||||
var transOpenNow = !_dbTransaction.IsOpened&&_dbContextCaches.Count>1;
|
||||
var transOpenNow = !_dbTransaction.IsOpened && _dbContextCaches.Count > 1;
|
||||
if (transOpenNow)
|
||||
{
|
||||
BeginTransaction();
|
||||
|
@ -250,10 +263,13 @@ namespace ShardingCore.DbContexts.VirtualDbContexts
|
|||
var effects = 0;
|
||||
foreach (var dbContextCache in _dbContextCaches)
|
||||
{
|
||||
effects += dbContextCache.Value.SaveChanges();
|
||||
foreach (var dbContext in dbContextCache.Value)
|
||||
{
|
||||
effects += dbContext.Value.SaveChanges();
|
||||
}
|
||||
}
|
||||
if (transOpenNow)
|
||||
_dbTransaction.Commit();
|
||||
_dbTransaction.Commit();
|
||||
|
||||
return effects;
|
||||
}
|
||||
|
@ -269,93 +285,127 @@ namespace ShardingCore.DbContexts.VirtualDbContexts
|
|||
Entity = o
|
||||
};
|
||||
}).GroupBy(g => g.DbContext)
|
||||
.ToDictionary(o => (DbContext) o.Key, o => o.Select(item => item.Entity).ToList());
|
||||
.ToDictionary(o => (DbContext)o.Key, o => o.Select(item => item.Entity).ToList());
|
||||
return new ShardingBatchInsertEntry<T>(groups);
|
||||
}
|
||||
|
||||
public ShardingBatchUpdateEntry<T> BulkUpdate<T>(Expression<Func<T, bool>> where, Expression<Func<T, T>> updateExp) where T : class
|
||||
{
|
||||
List<DbContext> dbContexts = null;
|
||||
if (typeof(T).IsShardingEntity())
|
||||
List<(string connectKey, List<DbContext> dbContexts)> dbContexts = null;
|
||||
var connectKeys = _virtualDataSourceManager.GetConnectKeys<T>(where);
|
||||
|
||||
if (typeof(T).IsShardingTable())
|
||||
{
|
||||
var shardingDbContexts = CreateShardingDbContexts<IShardingEntity>(new EnumerableQuery<T>(where).AsQueryable());
|
||||
dbContexts = shardingDbContexts.Select(o => (DbContext) o).ToList();
|
||||
dbContexts = CreateShardingDbContexts<IShardingEntity>(connectKeys, new EnumerableQuery<T>(where).AsQueryable());
|
||||
}
|
||||
else
|
||||
{
|
||||
dbContexts = new List<DbContext>(1)
|
||||
dbContexts = connectKeys.Select(connectKey =>
|
||||
{
|
||||
GetOrCreateShardingDbContext(EMPTY_SHARDING_TAIL_ID)
|
||||
};
|
||||
return (connectKey, new List<DbContext>(1)
|
||||
{
|
||||
GetOrCreateShardingDbContext(connectKey, EMPTY_SHARDING_TAIL_ID)
|
||||
});
|
||||
}).ToList();
|
||||
}
|
||||
|
||||
return new ShardingBatchUpdateEntry<T>(where,updateExp,dbContexts);
|
||||
return new ShardingBatchUpdateEntry<T>(where, updateExp, dbContexts);
|
||||
}
|
||||
|
||||
public ShardingBatchDeleteEntry<T> BulkDelete<T>(Expression<Func<T, bool>> where) where T : class
|
||||
{
|
||||
List<DbContext> dbContexts = null;
|
||||
if (typeof(T).IsShardingEntity())
|
||||
List<(string connectKey,List<DbContext> dbContexts)> dbContexts = null;
|
||||
var connectKeys = _virtualDataSourceManager.GetConnectKeys<T>(where);
|
||||
|
||||
if (typeof(T).IsShardingTable())
|
||||
{
|
||||
var shardingDbContexts = CreateShardingDbContexts<IShardingEntity>(new EnumerableQuery<T>(where).AsQueryable());
|
||||
dbContexts = shardingDbContexts.Select(o => (DbContext) o).ToList();
|
||||
dbContexts = CreateShardingDbContexts<IShardingEntity>(connectKeys, new EnumerableQuery<T>(where).AsQueryable());
|
||||
}
|
||||
else
|
||||
{
|
||||
dbContexts = new List<DbContext>(1)
|
||||
dbContexts = connectKeys.Select(connectKey =>
|
||||
{
|
||||
GetOrCreateShardingDbContext(EMPTY_SHARDING_TAIL_ID)
|
||||
};
|
||||
return (connectKey, new List<DbContext>(1)
|
||||
{
|
||||
GetOrCreateShardingDbContext(connectKey, EMPTY_SHARDING_TAIL_ID)
|
||||
});
|
||||
}).ToList();
|
||||
}
|
||||
|
||||
return new ShardingBatchDeleteEntry<T>(where,dbContexts);
|
||||
return new ShardingBatchDeleteEntry<T>(where, dbContexts);
|
||||
}
|
||||
|
||||
private DbContext CreateGenericDbContext<T>(T entity) where T : class
|
||||
{
|
||||
var tail = EMPTY_SHARDING_TAIL_ID;
|
||||
if (entity.IsShardingEntity())
|
||||
var connectKey = _virtualDataSourceManager.GetConnectKey(entity);
|
||||
if (entity.IsShardingTable())
|
||||
{
|
||||
var physicTable = _virtualTableManager.GetVirtualTable(entity.GetType()).RouteTo(new RouteConfig(null, entity as IShardingEntity, null))[0];
|
||||
var physicTable = _virtualTableManager.GetVirtualTable(connectKey, entity.GetType()).RouteTo(new TableRouteConfig(null, entity as IShardingEntity, null))[0];
|
||||
tail = physicTable.Tail;
|
||||
}
|
||||
return GetOrCreateShardingDbContext(tail);
|
||||
return GetOrCreateShardingDbContext(connectKey,tail);
|
||||
}
|
||||
|
||||
private List<ShardingDbContext> CreateShardingDbContexts<T>(IQueryable queryable) where T : class, IShardingEntity
|
||||
private List<(string connectKey, List<DbContext> dbContexts)> CreateShardingDbContexts<T>(List<string> connectKeys,IQueryable queryable) where T : class, IShardingEntity
|
||||
{
|
||||
var physicTables = _virtualTableManager.GetVirtualTable(typeof(T)).RouteTo(new RouteConfig(queryable, null, null));
|
||||
if (physicTables.Any())
|
||||
var results =
|
||||
new List<(string connectKey, List<DbContext> dbContexts)>();
|
||||
foreach (var connectKey in connectKeys)
|
||||
{
|
||||
var shardingDbContexts = new List<ShardingDbContext>(physicTables.Count);
|
||||
foreach (var physicTable in physicTables)
|
||||
var physicTables = _virtualTableManager.GetVirtualTable(connectKey,typeof(T)).RouteTo(new TableRouteConfig(queryable, null, null));
|
||||
if (physicTables.Any())
|
||||
{
|
||||
var shardingDbContext = GetOrCreateShardingDbContext(physicTable.Tail);
|
||||
var dbContexts = new List<DbContext>(physicTables.Count);
|
||||
foreach (var physicTable in physicTables)
|
||||
{
|
||||
var dbContext = GetOrCreateShardingDbContext(connectKey,physicTable.Tail);
|
||||
|
||||
shardingDbContexts.Add(shardingDbContext);
|
||||
dbContexts.Add(dbContext);
|
||||
}
|
||||
results.Add((connectKey, dbContexts));
|
||||
}
|
||||
|
||||
return shardingDbContexts;
|
||||
}
|
||||
|
||||
if (results.Any())
|
||||
return results;
|
||||
|
||||
throw new QueryableRouteNotMatchException($"{typeof(T)} -> {nameof(queryable)}");
|
||||
}
|
||||
|
||||
private DbContext GetOrCreateShardingDbContext(string tail)
|
||||
private DbContext GetOrCreateShardingDbContext(string connectKey,string tail)
|
||||
{
|
||||
if (!_dbContextCaches.TryGetValue(tail, out var shardingDbContext))
|
||||
if (!_dbContextCaches.TryGetValue(connectKey, out var dbContexts))
|
||||
{
|
||||
var virtualTableConfigs = _virtualTableManager.GetAllVirtualTables().GetVirtualTableDbContextConfigs();
|
||||
shardingDbContext = _shardingDbContextFactory.Create(new ShardingTableDbContextOptions(DbContextOptionsProvider.GetDbContextOptions(), tail == EMPTY_SHARDING_TAIL_ID ? string.Empty : tail, virtualTableConfigs));
|
||||
_dbContextCaches.TryAdd(tail, shardingDbContext);
|
||||
dbContexts = new ConcurrentDictionary<string, DbContext>();
|
||||
_dbContextCaches.TryAdd(connectKey, dbContexts);
|
||||
}
|
||||
if(!dbContexts.TryGetValue(tail,out var dbContext))
|
||||
{
|
||||
var virtualTableConfigs = _virtualTableManager.GetAllVirtualTables(connectKey).GetVirtualTableDbContextConfigs();
|
||||
dbContext = _shardingDbContextFactory.Create(connectKey, new ShardingDbContextOptions(DbContextOptionsProvider.GetDbContextOptions(connectKey), tail == EMPTY_SHARDING_TAIL_ID ? string.Empty : tail, virtualTableConfigs));
|
||||
dbContexts.TryAdd(tail, dbContext);
|
||||
}
|
||||
|
||||
if (IsOpenTransaction)
|
||||
{
|
||||
_dbTransaction.Use(shardingDbContext);
|
||||
_dbTransaction.Use(dbContext);
|
||||
}
|
||||
|
||||
return shardingDbContext;
|
||||
return dbContext;
|
||||
//if (!_dbContextCaches.TryGetValue(tail, out var dbContext))
|
||||
//{
|
||||
// var virtualTableConfigs = _virtualTableManager.GetAllVirtualTables().GetVirtualTableDbContextConfigs();
|
||||
// dbContext = _shardingDbContextFactory.Create(new ShardingDbContextOptions(DbContextOptionsProvider.GetDbContextOptions(), tail == EMPTY_SHARDING_TAIL_ID ? string.Empty : tail, virtualTableConfigs));
|
||||
// _dbContextCaches.TryAdd(tail, dbContext);
|
||||
//}
|
||||
|
||||
//if (IsOpenTransaction)
|
||||
//{
|
||||
// _dbTransaction.Use(dbContext);
|
||||
//}
|
||||
|
||||
//return dbContext;
|
||||
}
|
||||
|
||||
|
||||
|
@ -365,14 +415,17 @@ namespace ShardingCore.DbContexts.VirtualDbContexts
|
|||
{
|
||||
_dbContextCaches.ForEach(o =>
|
||||
{
|
||||
try
|
||||
o.Value.ForEach(v =>
|
||||
{
|
||||
o.Value.Dispose();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine(e);
|
||||
}
|
||||
try
|
||||
{
|
||||
v.Value.Dispose();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine(e);
|
||||
}
|
||||
});
|
||||
});
|
||||
_dbContextCaches.Clear();
|
||||
}
|
||||
|
|
|
@ -15,14 +15,13 @@ namespace ShardingCore.EFCores
|
|||
{
|
||||
public object Create(DbContext context)
|
||||
{
|
||||
if (context is ShardingDbContext shardingDbContext)
|
||||
if (context is AbstractShardingDbContext shardingDbContext)
|
||||
{
|
||||
//当出现尾巴不一样,本次映射的数据库实体数目不一样就需要重建ef model
|
||||
var tail = shardingDbContext.Tail;
|
||||
var removeSharding = shardingDbContext.RemoveRemoveShardingEntity;
|
||||
var allEntities = string.Join(",",shardingDbContext.VirtualTableConfigs.Select(o=>o.ShardingEntityType.FullName).OrderBy(o=>o).ToList());
|
||||
var allEntities = string.Join(",",shardingDbContext.VirtualTableConfigs.Values.Select(o=>o.ShardingEntityType.FullName).OrderBy(o=>o).ToList());
|
||||
|
||||
return $"{context.GetType()}_{allEntities}_{tail}_{removeSharding}";
|
||||
return $"{context.GetType()}_{allEntities}_{tail}";
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -263,7 +263,7 @@ namespace ShardingCore.EFCores
|
|||
return database.CompileAsyncQuery<TResult>(queryModel);
|
||||
}
|
||||
private static async Task<TResult> ExecuteSingletonAsyncQuery<TResult>(
|
||||
QueryContext queryContext,
|
||||
QueryContext queryContext,
|
||||
Func<QueryContext, IAsyncEnumerable<TResult>> compiledQuery,
|
||||
IDiagnosticsLogger<DbLoggerCategory.Query> logger,
|
||||
Type contextType)
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Text;
|
||||
|
||||
namespace ShardingCore.Exceptions
|
||||
{
|
||||
/*
|
||||
* @Author: xjm
|
||||
* @Description:
|
||||
* @Date: 2021/3/5 8:11:30
|
||||
* @Ver: 1.0
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
public class ShardingConfigNotFoundException:Exception
|
||||
{
|
||||
public ShardingConfigNotFoundException()
|
||||
{
|
||||
}
|
||||
|
||||
protected ShardingConfigNotFoundException(SerializationInfo info, StreamingContext context) : base(info, context)
|
||||
{
|
||||
}
|
||||
|
||||
public ShardingConfigNotFoundException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public ShardingConfigNotFoundException(string message, Exception innerException) : base(message, innerException)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Text;
|
||||
|
||||
namespace ShardingCore.Exceptions
|
||||
{
|
||||
/*
|
||||
* @Author: xjm
|
||||
* @Description:
|
||||
* @Date: 2021/3/5 13:25:51
|
||||
* @Ver: 1.0
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
public class ShardingConnectKeyNotFoundException: Exception
|
||||
{
|
||||
public ShardingConnectKeyNotFoundException()
|
||||
{
|
||||
}
|
||||
|
||||
protected ShardingConnectKeyNotFoundException(SerializationInfo info, StreamingContext context) : base(info, context)
|
||||
{
|
||||
}
|
||||
|
||||
public ShardingConnectKeyNotFoundException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public ShardingConnectKeyNotFoundException(string message, Exception innerException) : base(message, innerException)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Text;
|
||||
|
||||
namespace ShardingCore.Exceptions
|
||||
{
|
||||
/*
|
||||
* @Author: xjm
|
||||
* @Description:
|
||||
* @Date: 2021/3/5 15:18:55
|
||||
* @Ver: 1.0
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
public class ShardingCoreException: Exception
|
||||
{
|
||||
public ShardingCoreException()
|
||||
{
|
||||
}
|
||||
|
||||
protected ShardingCoreException(SerializationInfo info, StreamingContext context) : base(info, context)
|
||||
{
|
||||
}
|
||||
|
||||
public ShardingCoreException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public ShardingCoreException(string message, Exception innerException) : base(message, innerException)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Text;
|
||||
|
||||
namespace ShardingCore.Exceptions
|
||||
{
|
||||
/*
|
||||
* @Author: xjm
|
||||
* @Description:
|
||||
* @Date: 2021/3/5 13:06:39
|
||||
* @Ver: 1.0
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
public class ShardingVirtualTableNotFoundException: Exception
|
||||
{
|
||||
public ShardingVirtualTableNotFoundException()
|
||||
{
|
||||
}
|
||||
|
||||
protected ShardingVirtualTableNotFoundException(SerializationInfo info, StreamingContext context) : base(info, context)
|
||||
{
|
||||
}
|
||||
|
||||
public ShardingVirtualTableNotFoundException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public ShardingVirtualTableNotFoundException(string message, Exception innerException) : base(message, innerException)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
|
@ -30,11 +30,29 @@ namespace ShardingCore.Extensions
|
|||
return typeof(IShardingDataSource).IsAssignableFrom(entityType);
|
||||
}
|
||||
/// <summary>
|
||||
/// 是否基继承至IShardingDataSource
|
||||
/// </summary>
|
||||
/// <param name="entity"></param>
|
||||
/// <returns></returns>
|
||||
public static bool IsShardingDataSource(this object entity)
|
||||
{
|
||||
if (entity == null)
|
||||
throw new ArgumentNullException(nameof(entity));
|
||||
return typeof(IShardingDataSource).IsAssignableFrom(entity.GetType());
|
||||
}
|
||||
|
||||
public static bool IsShardingDbContext(this Type entityType)
|
||||
{
|
||||
if (entityType == null)
|
||||
throw new ArgumentNullException(nameof(entityType));
|
||||
return typeof(AbstractShardingDbContext).IsAssignableFrom(entityType);
|
||||
}
|
||||
/// <summary>
|
||||
/// 是否基继承至IShardingEntity
|
||||
/// </summary>
|
||||
/// <param name="entityType"></param>
|
||||
/// <returns></returns>
|
||||
public static bool IsShardingEntity(this Type entityType)
|
||||
public static bool IsShardingTable(this Type entityType)
|
||||
{
|
||||
if (entityType == null)
|
||||
throw new ArgumentNullException(nameof(entityType));
|
||||
|
@ -46,7 +64,7 @@ namespace ShardingCore.Extensions
|
|||
/// </summary>
|
||||
/// <param name="entity"></param>
|
||||
/// <returns></returns>
|
||||
public static bool IsShardingEntity(this object entity)
|
||||
public static bool IsShardingTable(this object entity)
|
||||
{
|
||||
if (entity == null)
|
||||
throw new ArgumentNullException(nameof(entity));
|
||||
|
@ -71,6 +89,7 @@ namespace ShardingCore.Extensions
|
|||
{
|
||||
return express.Method.DeclaringType.Namespace.IsIn("System.Linq", "System.Collections.Generic") && methodName == nameof(IList.Contains);
|
||||
}
|
||||
|
||||
public static ISet<Type> ParseQueryableRoute(this IQueryable queryable)
|
||||
{
|
||||
return ShardingKeyUtil.GetQueryEntitiesFilter(queryable);
|
||||
|
|
|
@ -52,11 +52,11 @@ namespace ShardingCore.Extensions
|
|||
/// 给IEnumerable拓展ForEach方法
|
||||
/// </summary>
|
||||
/// <typeparam name="T">模型类</typeparam>
|
||||
/// <param name="iEnumberable">数据源</param>
|
||||
/// <param name="enumberable">数据源</param>
|
||||
/// <param name="func">方法</param>
|
||||
public static void ForEach<T>(this IEnumerable<T> iEnumberable, Action<T> func)
|
||||
public static void ForEach<T>(this IEnumerable<T> enumberable, Action<T> func)
|
||||
{
|
||||
foreach (var item in iEnumberable)
|
||||
foreach (var item in enumberable)
|
||||
{
|
||||
func(item);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Text;
|
||||
using ShardingCore.Core;
|
||||
using ShardingCore.Core.VirtualDataSources;
|
||||
using ShardingCore.Exceptions;
|
||||
|
||||
namespace ShardingCore.Extensions
|
||||
{
|
||||
/*
|
||||
* @Author: xjm
|
||||
* @Description:
|
||||
* @Date: 2021/3/5 15:43:09
|
||||
* @Ver: 1.0
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
public static class VirtualDbContextExtension
|
||||
{
|
||||
public static string GetConnectKey<T>(this IVirtualDataSourceManager virtualDataSourceManager, T entity) where T : class
|
||||
{
|
||||
var type = entity.GetType();
|
||||
var connectKeys = virtualDataSourceManager.GetEntityTypeLinkedConnectKeys(type);
|
||||
if (connectKeys.IsEmpty())
|
||||
throw new ShardingCoreException($"entity:[{type}] connect not found");
|
||||
if (connectKeys.Count == 1)
|
||||
return connectKeys[0];
|
||||
if (!entity.IsShardingDataSource())
|
||||
throw new ShardingCoreException($"entity:[{type}] is not sharding data source and not found connect");
|
||||
return virtualDataSourceManager.GetVirtualDataSource(type)
|
||||
.RouteTo(new VirutalDataSourceRouteConfig(shardingDataSource: entity as IShardingDataSource))[0];
|
||||
}
|
||||
public static List<string> GetConnectKeys<T>(this IVirtualDataSourceManager virtualDataSourceManager, Expression<Func<T, bool>> where) where T : class
|
||||
{
|
||||
var type = typeof(T);
|
||||
var connectKeys = virtualDataSourceManager.GetEntityTypeLinkedConnectKeys(type);
|
||||
if (connectKeys.IsEmpty())
|
||||
throw new ShardingCoreException($"entity:[{type}] connect not found");
|
||||
|
||||
if (!type.IsShardingDataSource())
|
||||
throw new ShardingCoreException($"entity:[{type}] is not sharding data source and not found connect");
|
||||
return virtualDataSourceManager.GetVirtualDataSource(type)
|
||||
.RouteTo(new VirutalDataSourceRouteConfig(predicate: where));
|
||||
}
|
||||
public static List<string> GetConnectKeys<T>(this IVirtualDataSourceManager virtualDataSourceManager, IQueryable queryable) where T : class
|
||||
{
|
||||
var type = typeof(T);
|
||||
var connectKeys = virtualDataSourceManager.GetEntityTypeLinkedConnectKeys(type);
|
||||
if (connectKeys.IsEmpty())
|
||||
throw new ShardingCoreException($"entity:[{type}] connect not found");
|
||||
|
||||
if (!type.IsShardingDataSource())
|
||||
throw new ShardingCoreException($"entity:[{type}] is not sharding data source and not found connect");
|
||||
return virtualDataSourceManager.GetVirtualDataSource(type)
|
||||
.RouteTo(new VirutalDataSourceRouteConfig(queryable: queryable));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using ShardingCore.Core.VirtualRoutes.DataSourceRoutes;
|
||||
|
||||
namespace ShardingCore
|
||||
{
|
||||
/*
|
||||
* @Author: xjm
|
||||
* @Description:
|
||||
* @Date: 2021/3/4 13:11:16
|
||||
* @Ver: 1.0
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
public interface IShardingCoreOptions
|
||||
{
|
||||
void AddShardingDbContext<T>(string connectKey, string connectString, Action<ShardingDbConfigOptions> func) where T : DbContext;
|
||||
|
||||
void AddShardingDbContext<T>(string connectKey, string connectString) where T : DbContext;
|
||||
|
||||
|
||||
void AddDataSourceVirtualRoute<TRoute>() where TRoute : IDataSourceVirtualRoute;
|
||||
|
||||
|
||||
ISet<ShardingConfigEntry> GetShardingConfigs();
|
||||
ShardingConfigEntry GetShardingConfig(string connectKey);
|
||||
ISet<Type> GetVirtualRoutes();
|
||||
Type GetVirtualRoute(Type entityType);
|
||||
|
||||
}
|
||||
}
|
|
@ -1,39 +1,49 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using ShardingCore.Core.PhysicTables;
|
||||
using ShardingCore.Core.VirtualDataSources;
|
||||
using ShardingCore.Core.VirtualRoutes.DataSourceRoutes;
|
||||
using ShardingCore.Core.VirtualRoutes.TableRoutes;
|
||||
using ShardingCore.Core.VirtualTables;
|
||||
using ShardingCore.DbContexts;
|
||||
using ShardingCore.DbContexts.ShardingTableDbContexts;
|
||||
using ShardingCore.DbContexts.ShardingDbContexts;
|
||||
using ShardingCore.DbContexts.VirtualDbContexts;
|
||||
using ShardingCore.Exceptions;
|
||||
using ShardingCore.Extensions;
|
||||
using ShardingCore.TableCreator;
|
||||
|
||||
namespace ShardingCore
|
||||
{
|
||||
/*
|
||||
* @Author: xjm
|
||||
* @Description:
|
||||
* @Date: Monday, 21 December 2020 09:10:07
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
public class ShardingBootstrapper:IShardingBootstrapper
|
||||
/*
|
||||
* @Author: xjm
|
||||
* @Description:
|
||||
* @Date: Monday, 21 December 2020 09:10:07
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
public class ShardingBootstrapper : IShardingBootstrapper
|
||||
{
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly IShardingCoreOptions _shardingCoreOptions;
|
||||
private readonly IVirtualDataSourceManager _virtualDataSourceManager;
|
||||
private readonly IVirtualTableManager _virtualTableManager;
|
||||
private readonly IShardingTableCreator _tableCreator;
|
||||
private readonly ILogger<ShardingBootstrapper> _logger;
|
||||
private readonly IShardingDbContextFactory _shardingDbContextFactory;
|
||||
private readonly ShardingCoreConfig _shardingCoreConfig;
|
||||
|
||||
public ShardingBootstrapper(IServiceProvider serviceProvider, IVirtualTableManager virtualTableManager
|
||||
public ShardingBootstrapper(IServiceProvider serviceProvider, IShardingCoreOptions shardingCoreOptions, IVirtualDataSourceManager virtualDataSourceManager, IVirtualTableManager virtualTableManager
|
||||
, IShardingTableCreator tableCreator, ILogger<ShardingBootstrapper> logger,
|
||||
IShardingDbContextFactory shardingDbContextFactory, ShardingCoreConfig shardingCoreConfig)
|
||||
{
|
||||
ShardingContainer.SetServices(serviceProvider);
|
||||
_serviceProvider = serviceProvider;
|
||||
_shardingCoreOptions = shardingCoreOptions;
|
||||
_virtualDataSourceManager = virtualDataSourceManager;
|
||||
_virtualTableManager = virtualTableManager;
|
||||
_tableCreator = tableCreator;
|
||||
_logger = logger;
|
||||
|
@ -43,36 +53,120 @@ namespace ShardingCore
|
|||
|
||||
public void Start()
|
||||
{
|
||||
EnsureCreated();
|
||||
var virtualTables = _virtualTableManager.GetAllVirtualTables();
|
||||
using var scope = _serviceProvider.CreateScope();
|
||||
var dbContextOptionsProvider = scope.ServiceProvider.GetService<IDbContextOptionsProvider>();
|
||||
using var context = _shardingDbContextFactory.Create(new ShardingTableDbContextOptions(dbContextOptionsProvider.GetDbContextOptions(), string.Empty, virtualTables.GetVirtualTableDbContextConfigs()));
|
||||
|
||||
foreach (var virtualTable in virtualTables)
|
||||
//EnsureCreated();
|
||||
//_shardingCoreOptions.GetShardingConfigs().Select(o=>o.ConnectKey).ForEach(connectKey=> _virtualDataSourceManager.AddShardingConnectKey(connectKey));
|
||||
var isShardingDataSource = _shardingCoreOptions.GetShardingConfigs().Count > 1;
|
||||
foreach (var virtualRouteType in _shardingCoreOptions.GetVirtualRoutes())
|
||||
{
|
||||
//获取ShardingEntity的实际表名
|
||||
#if !EFCORE2
|
||||
var tableName = context.Model.FindEntityType(virtualTable.EntityType).GetTableName();
|
||||
#endif
|
||||
#if EFCORE2
|
||||
var tableName = context.Model.FindEntityType(virtualTable.EntityType).Relational().TableName;
|
||||
#endif
|
||||
virtualTable.SetOriginalTableName(tableName);
|
||||
CreateDataTable(virtualTable);
|
||||
var virtualRoute = CreateDataSourceVirtualRoute(virtualRouteType);
|
||||
var virtualDataSource = CreateDataSourceVirtualTable(virtualRoute.ShardingEntityType, virtualRoute);
|
||||
_virtualDataSourceManager.AddVirtualDataSource(virtualDataSource);
|
||||
}
|
||||
}
|
||||
|
||||
private void EnsureCreated()
|
||||
{
|
||||
if (_shardingCoreConfig.EnsureCreated)
|
||||
foreach (var shardingConfig in _shardingCoreOptions.GetShardingConfigs())
|
||||
{
|
||||
var connectKey = shardingConfig.ConnectKey;
|
||||
_virtualDataSourceManager.AddShardingConnectKey(connectKey);
|
||||
|
||||
using var scope = _serviceProvider.CreateScope();
|
||||
var dbContextOptionsProvider = scope.ServiceProvider.GetService<IDbContextOptionsProvider>();
|
||||
using var context = _shardingDbContextFactory.Create(new ShardingTableDbContextOptions(dbContextOptionsProvider.GetDbContextOptions(), string.Empty, new List<VirtualTableDbContextConfig>(), true));
|
||||
context.Database.EnsureCreated();
|
||||
using var context = _shardingDbContextFactory.Create(connectKey, new ShardingDbContextOptions(dbContextOptionsProvider.GetDbContextOptions(connectKey), string.Empty, new List<VirtualTableDbContextConfig>()));
|
||||
foreach (var entity in context.Model.GetEntityTypes())
|
||||
{
|
||||
|
||||
_virtualDataSourceManager.AddConnectEntities(connectKey,entity.ClrType);
|
||||
if (entity.IsShardingTable())
|
||||
{
|
||||
var routeType = shardingConfig.DbConfigOptions.GetVirtualRoute(entity.ClrType);
|
||||
var virtualRoute = CreateVirtualRoute(routeType);
|
||||
var virtualTable = CreateVirtualTable(entity.ClrType, virtualRoute);
|
||||
|
||||
//获取ShardingEntity的实际表名
|
||||
#if !EFCORE2
|
||||
var tableName = context.Model.FindEntityType(virtualTable.EntityType).GetTableName();
|
||||
#endif
|
||||
#if EFCORE2
|
||||
var tableName = context.Model.FindEntityType(virtualTable.EntityType).Relational().TableName;
|
||||
#endif
|
||||
virtualTable.SetOriginalTableName(tableName);
|
||||
_virtualTableManager.AddVirtualTable(connectKey, virtualTable);
|
||||
CreateDataTable(connectKey,virtualTable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
private IDataSourceVirtualRoute CreateDataSourceVirtualRoute(Type virtualRouteType)
|
||||
{
|
||||
var constructors
|
||||
= virtualRouteType.GetTypeInfo().DeclaredConstructors
|
||||
.Where(c => !c.IsStatic && c.IsPublic)
|
||||
.ToArray();
|
||||
if (constructors.IsEmpty())
|
||||
{
|
||||
object o = Activator.CreateInstance(virtualRouteType);
|
||||
return (IDataSourceVirtualRoute)o;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (constructors.Length > 1)
|
||||
{
|
||||
throw new ArgumentException(
|
||||
$"data source virtual route :[{virtualRouteType}] found more declared constructor ");
|
||||
}
|
||||
var @params = constructors[0].GetParameters().Select(x => _serviceProvider.GetService(x.ParameterType)).ToArray();
|
||||
object o = Activator.CreateInstance(virtualRouteType, @params);
|
||||
return (IDataSourceVirtualRoute)o;
|
||||
}
|
||||
}
|
||||
private IVirtualDataSource CreateDataSourceVirtualTable(Type entityType, IDataSourceVirtualRoute virtualRoute)
|
||||
{
|
||||
Type type = typeof(VirtualDataSource<>);
|
||||
type = type.MakeGenericType(entityType);
|
||||
object o = Activator.CreateInstance(type,_serviceProvider, virtualRoute);
|
||||
return (IVirtualDataSource)o;
|
||||
}
|
||||
private IVirtualRoute CreateVirtualRoute(Type virtualRouteType)
|
||||
{
|
||||
var constructors
|
||||
= virtualRouteType.GetTypeInfo().DeclaredConstructors
|
||||
.Where(c => !c.IsStatic && c.IsPublic)
|
||||
.ToArray();
|
||||
if (constructors.IsEmpty())
|
||||
{
|
||||
object o = Activator.CreateInstance(virtualRouteType);
|
||||
return (IVirtualRoute)o;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (constructors.Length > 1)
|
||||
{
|
||||
throw new ArgumentException(
|
||||
$"virtual route :[{virtualRouteType}] found more declared constructor ");
|
||||
}
|
||||
var @params = constructors[0].GetParameters().Select(x => _serviceProvider.GetService(x.ParameterType)).ToArray();
|
||||
object o = Activator.CreateInstance(virtualRouteType, @params);
|
||||
return (IVirtualRoute)o;
|
||||
}
|
||||
}
|
||||
|
||||
private IVirtualTable CreateVirtualTable(Type entityType, IVirtualRoute virtualRoute)
|
||||
{
|
||||
Type type = typeof(OneDbVirtualTable<>);
|
||||
type = type.MakeGenericType(entityType);
|
||||
object o = Activator.CreateInstance(type, virtualRoute);
|
||||
return (IVirtualTable)o;
|
||||
}
|
||||
|
||||
//private void EnsureCreated()
|
||||
//{
|
||||
// if (_shardingCoreConfig.EnsureCreated)
|
||||
// {
|
||||
// using var scope = _serviceProvider.CreateScope();
|
||||
// var dbContextOptionsProvider = scope.ServiceProvider.GetService<IDbContextOptionsProvider>();
|
||||
// using var context = _shardingDbContextFactory.Create(new ShardingTableDbContextOptions(dbContextOptionsProvider.GetDbContextOptions(), string.Empty, new List<VirtualTableDbContextConfig>(), true));
|
||||
// context.Database.EnsureCreated();
|
||||
// }
|
||||
//}
|
||||
|
||||
private bool NeedCreateTable(ShardingEntityConfig config)
|
||||
{
|
||||
|
@ -82,7 +176,7 @@ namespace ShardingCore
|
|||
}
|
||||
return _shardingCoreConfig.CreateShardingTableOnStart.GetValueOrDefault();
|
||||
}
|
||||
private void CreateDataTable(IVirtualTable virtualTable)
|
||||
private void CreateDataTable(string connectKey,IVirtualTable virtualTable)
|
||||
{
|
||||
var shardingConfig = virtualTable.ShardingConfig;
|
||||
foreach (var tail in virtualTable.GetTaleAllTails())
|
||||
|
@ -91,7 +185,7 @@ namespace ShardingCore
|
|||
{
|
||||
try
|
||||
{
|
||||
_tableCreator.CreateTable(virtualTable.EntityType, tail);
|
||||
_tableCreator.CreateTable(connectKey,virtualTable.EntityType, tail);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using ShardingCore.Core;
|
||||
using ShardingCore.DbContexts.ShardingDbContexts;
|
||||
|
||||
namespace ShardingCore
|
||||
{
|
||||
/*
|
||||
* @Author: xjm
|
||||
* @Description:
|
||||
* @Date: 2021/3/3 16:30:21
|
||||
* @Ver: 1.0
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
public class ShardingConfigEntry
|
||||
{
|
||||
public ShardingConfigEntry(string connectKey,string connectionString, Func<ShardingDbContextOptions, DbContext> creator, Type dbContextType, Action<ShardingDbConfigOptions> shardingDbConfigConfigure)
|
||||
{
|
||||
ConnectKey = connectKey;
|
||||
ConnectionString = connectionString;
|
||||
Creator = creator;
|
||||
DbContextType = dbContextType;
|
||||
DbConfigOptions = new ShardingDbConfigOptions();
|
||||
shardingDbConfigConfigure?.Invoke(DbConfigOptions);
|
||||
}
|
||||
|
||||
public Type DbContextType { get; }
|
||||
public Func<ShardingDbContextOptions, DbContext> Creator { get; }
|
||||
public ShardingDbConfigOptions DbConfigOptions { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 连接标识
|
||||
/// </summary>
|
||||
public string ConnectKey { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 连接字符串
|
||||
/// </summary>
|
||||
public string ConnectionString { get; }
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return this.ConnectKey.GetHashCode() ^ 31;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (!(obj is ShardingConfigEntry))
|
||||
return false;
|
||||
|
||||
if (ReferenceEquals(this, obj))
|
||||
return true;
|
||||
|
||||
ShardingConfigEntry item = (ShardingConfigEntry)obj;
|
||||
|
||||
return item.ConnectKey == this.ConnectKey;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using ShardingCore.Core.VirtualRoutes.DataSourceRoutes;
|
||||
using ShardingCore.Core.VirtualRoutes.TableRoutes;
|
||||
using ShardingCore.Extensions;
|
||||
|
||||
namespace ShardingCore
|
||||
{
|
||||
/*
|
||||
* @Author: xjm
|
||||
* @Description:
|
||||
* @Date: 2021/3/3 16:15:11
|
||||
* @Ver: 1.0
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
public class ShardingDbConfigOptions
|
||||
{
|
||||
|
||||
|
||||
private readonly Dictionary<Type,Type> _virtualRoutes = new Dictionary<Type, Type>();
|
||||
public void AddShardingTableRoute<TRoute>() where TRoute : IVirtualRoute
|
||||
{
|
||||
var routeType = typeof(TRoute);
|
||||
//获取类型
|
||||
var shardingEntityType = routeType.GetGenericArguments()[0];
|
||||
if (shardingEntityType == null)
|
||||
throw new ArgumentException("add sharding table route type error not assignable from IVirtualRoute<>");
|
||||
if (!_virtualRoutes.ContainsKey(shardingEntityType))
|
||||
{
|
||||
_virtualRoutes.Add(shardingEntityType, routeType);
|
||||
}
|
||||
}
|
||||
|
||||
public Type GetVirtualRoute(Type entityType)
|
||||
{
|
||||
if (!_virtualRoutes.ContainsKey(entityType))
|
||||
throw new ArgumentException("not found IVirtualRoute");
|
||||
return _virtualRoutes[entityType];
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using ShardingCore.Core;
|
||||
using ShardingCore.Exceptions;
|
||||
|
||||
namespace ShardingCore.TableCreator
|
||||
{
|
||||
|
@ -17,15 +18,17 @@ namespace ShardingCore.TableCreator
|
|||
/// <summary>
|
||||
/// 创建表
|
||||
/// </summary>
|
||||
/// <param name="connectKey"></param>
|
||||
/// <param name="tail"></param>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
void CreateTable<T>(string tail) where T : class, IShardingEntity;
|
||||
void CreateTable<T>(string connectKey,string tail) where T : class, IShardingEntity;
|
||||
/// <summary>
|
||||
/// 创建表
|
||||
/// </summary>
|
||||
/// <param name="connectKey"></param>
|
||||
/// <param name="shardingEntityType"></param>
|
||||
/// <param name="tail"></param>
|
||||
/// <exception cref="ShardingCreateException"></exception>
|
||||
void CreateTable(Type shardingEntityType,string tail);
|
||||
void CreateTable(string connectKey, Type shardingEntityType,string tail);
|
||||
}
|
||||
}
|
|
@ -34,24 +34,25 @@ namespace ShardingCore.TableCreator
|
|||
_serviceProvider = serviceProvider;
|
||||
}
|
||||
|
||||
public void CreateTable<T>(string tail) where T : class, IShardingEntity
|
||||
public void CreateTable<T>(string connectKey,string tail) where T : class, IShardingEntity
|
||||
{
|
||||
CreateTable(typeof(T), tail);
|
||||
CreateTable(connectKey,typeof(T), tail);
|
||||
}
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="connectKey"></param>
|
||||
/// <param name="shardingEntityType"></param>
|
||||
/// <param name="tail"></param>
|
||||
/// <exception cref="ShardingCreateException"></exception>
|
||||
public void CreateTable(Type shardingEntityType, string tail)
|
||||
public void CreateTable(string connectKey, Type shardingEntityType, string tail)
|
||||
{
|
||||
using (var serviceScope = _serviceProvider.CreateScope())
|
||||
{
|
||||
var dbContextOptionsProvider = serviceScope.ServiceProvider.GetService<IDbContextOptionsProvider>();
|
||||
var virtualTable = _virtualTableManager.GetVirtualTable(shardingEntityType);
|
||||
var virtualTable = _virtualTableManager.GetVirtualTable(connectKey,shardingEntityType);
|
||||
|
||||
using (var dbContext = _shardingDbContextFactory.Create(new ShardingDbContextOptions(dbContextOptionsProvider.GetDbContextOptions(), tail,
|
||||
using (var dbContext = _shardingDbContextFactory.Create(connectKey,new ShardingDbContextOptions(dbContextOptionsProvider.GetDbContextOptions(connectKey), tail,
|
||||
new List<VirtualTableDbContextConfig>() {new VirtualTableDbContextConfig(shardingEntityType, virtualTable.GetOriginalTableName(), virtualTable.ShardingConfig.TailPrefix)})))
|
||||
{
|
||||
var databaseCreator = dbContext.Database.GetService<IDatabaseCreator>() as RelationalDatabaseCreator;
|
||||
|
|
|
@ -6,9 +6,7 @@ using System.Reflection;
|
|||
using ShardingCore.Core;
|
||||
using ShardingCore.Core.Internal;
|
||||
using ShardingCore.Core.Internal.Visitors;
|
||||
using ShardingCore.Core.PhysicDataSources;
|
||||
using ShardingCore.Core.VirtualRoutes;
|
||||
using ShardingCore.Core.VirtualTables;
|
||||
using ShardingCore.Extensions;
|
||||
|
||||
namespace ShardingCore.Utils
|
||||
|
@ -35,7 +33,7 @@ namespace ShardingCore.Utils
|
|||
}
|
||||
|
||||
var isShardingDataSource = entityType.IsShardingDataSource();
|
||||
var isShardingTable = entityType.IsShardingEntity();
|
||||
var isShardingTable = entityType.IsShardingTable();
|
||||
baseType = new ShardingEntityBaseType()
|
||||
{
|
||||
EntityType = entityType,
|
||||
|
@ -95,7 +93,7 @@ namespace ShardingCore.Utils
|
|||
}
|
||||
|
||||
|
||||
public static Func<IPhysicDataSource, bool> GetRouteDataSourceFilter<TKey>(IQueryable queryable, ShardingEntityBaseType shardingEntityBaseType, Func<object, TKey> shardingKeyConvert, Func<TKey, ShardingOperatorEnum, Expression<Func<IPhysicDataSource, bool>>> keyToTailExpression)
|
||||
public static Func<string, bool> GetRouteDataSourceFilter<TKey>(IQueryable queryable, ShardingEntityBaseType shardingEntityBaseType, Func<object, TKey> shardingKeyConvert, Func<TKey, ShardingOperatorEnum, Expression<Func<string, bool>>> keyToTailExpression)
|
||||
{
|
||||
QueryableRouteShardingDataSourceDiscoverVisitor<TKey> visitor = new QueryableRouteShardingDataSourceDiscoverVisitor<TKey>(shardingEntityBaseType, shardingKeyConvert, keyToTailExpression);
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ using System.Collections.Generic;
|
|||
using System.Linq.Expressions;
|
||||
using ShardingCore.Core;
|
||||
using ShardingCore.Core.VirtualRoutes;
|
||||
using ShardingCore.Core.VirtualRoutes.Abstractions;
|
||||
using ShardingCore.Core.VirtualRoutes.TableRoutes;
|
||||
|
||||
namespace ShardingCore.VirtualRoutes.Abstractions
|
||||
{
|
||||
|
|
|
@ -3,7 +3,7 @@ using System.Collections.Generic;
|
|||
using System.Linq.Expressions;
|
||||
using ShardingCore.Core;
|
||||
using ShardingCore.Core.VirtualRoutes;
|
||||
using ShardingCore.Core.VirtualRoutes.Abstractions;
|
||||
using ShardingCore.Core.VirtualRoutes.TableRoutes;
|
||||
|
||||
namespace ShardingCore.VirtualRoutes.Abstractions
|
||||
{
|
||||
|
|
|
@ -3,7 +3,6 @@ using System.Collections.Generic;
|
|||
using System.Linq.Expressions;
|
||||
using ShardingCore.Core;
|
||||
using ShardingCore.Core.VirtualRoutes;
|
||||
using ShardingCore.Core.VirtualRoutes.Abstractions;
|
||||
using ShardingCore.VirtualRoutes.Abstractions;
|
||||
|
||||
namespace ShardingCore.VirtualRoutes.Days
|
||||
|
|
|
@ -3,7 +3,6 @@ using System.Collections.Generic;
|
|||
using System.Linq.Expressions;
|
||||
using ShardingCore.Core;
|
||||
using ShardingCore.Core.VirtualRoutes;
|
||||
using ShardingCore.Core.VirtualRoutes.Abstractions;
|
||||
using ShardingCore.Helpers;
|
||||
using ShardingCore.VirtualRoutes.Abstractions;
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ using System.Linq;
|
|||
using System.Linq.Expressions;
|
||||
using ShardingCore.Core;
|
||||
using ShardingCore.Core.VirtualRoutes;
|
||||
using ShardingCore.Core.VirtualRoutes.Abstractions;
|
||||
using ShardingCore.Core.VirtualRoutes.TableRoutes;
|
||||
|
||||
namespace ShardingCore.VirtualRoutes.Mods
|
||||
{
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue