完成分表分库插件的第一个版本

This commit is contained in:
xuejiaming 2021-03-05 16:55:52 +08:00
parent 9530e1bb85
commit ce80b12158
110 changed files with 2207 additions and 1255 deletions

View File

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

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>

View File

@ -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<>();
});
}

View File

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

View File

@ -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();
}

View File

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

View File

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

View File

@ -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());
}
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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());
}
}
}

View File

@ -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: 202047 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];
}
}
}

View File

@ -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();
}
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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
// });
// }
//}
}
}

View File

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

View File

@ -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());
}
}
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using Microsoft.EntityFrameworkCore.Query;
using ShardingCore.Extensions;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -12,7 +12,7 @@ namespace ShardingCore.Core
/// 数据源分库规则字段
/// </summary>
[AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]
public class ShardingDataSourceKeyAttribute
public class ShardingDataSourceKeyAttribute: Attribute
{
}
}

View File

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

View File

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

View File

@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using ShardingCore.Extensions;
namespace ShardingCore.Core.ShardingDataSources
{

View File

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

View File

@ -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();
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -10,6 +10,6 @@ namespace ShardingCore.DbContexts
*/
public interface IShardingParallelDbContextFactory
{
DbContext Create(string tail);
DbContext Create(string connectKey, string tail);
}
}

View File

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

View File

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

View File

@ -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);
// }
// }
// }
// }
// }
// }
// }

View File

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

View File

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

View File

@ -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();
}
}
}

View File

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

View File

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

View File

@ -11,6 +11,6 @@ namespace ShardingCore.DbContexts.VirtualDbContexts
*/
public interface IDbContextOptionsProvider:IDisposable
{
DbContextOptions GetDbContextOptions();
DbContextOptions GetDbContextOptions(string connectKey);
}
}

View File

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

View File

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

View File

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

View File

@ -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();
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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