第一个测试版本

This commit is contained in:
xuejiaming 2021-08-20 13:50:49 +08:00
parent 070a952bfd
commit 4accc08567
56 changed files with 841 additions and 1076 deletions

View File

@ -2,7 +2,7 @@
::定义版本
set EFCORE2=2.1.0.21
set EFCORE3=3.1.0.21
set EFCORE5=5.1.0.21
set EFCORE5=5.2.0.02
::删除所有bin与obj下的文件
@echo off

View File

@ -1,4 +1,3 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Builder;
@ -6,8 +5,6 @@ using Microsoft.Extensions.DependencyInjection;
using Sample.SqlServer.DbContexts;
using Sample.SqlServer.Domain.Entities;
using ShardingCore;
using ShardingCore.DbContexts.VirtualDbContexts;
using ShardingCore.Extensions;
namespace Sample.SqlServer
{
@ -30,24 +27,24 @@ namespace Sample.SqlServer
{
using (var scope=app.ApplicationServices.CreateScope())
{
var virtualDbContext =scope.ServiceProvider.GetService<DefaultTableDbContext>();
//if (!virtualDbContext.Set<SysUserMod>().ShardingAny())
//{
// var ids = Enumerable.Range(1, 1000);
// var userMods = new List<SysUserMod>();
// foreach (var id in ids)
// {
// userMods.Add(new SysUserMod()
// {
// Id = id.ToString(),
// Age = id,
// Name = $"name_{id}",
// });
// }
var virtualDbContext =scope.ServiceProvider.GetService<DefaultShardingDbContext>();
if (!virtualDbContext.Set<SysUserMod>().Any())
{
var ids = Enumerable.Range(1, 1000);
var userMods = new List<SysUserMod>();
foreach (var id in ids)
{
userMods.Add(new SysUserMod()
{
Id = id.ToString(),
Age = id,
Name = $"name_{id}",
});
}
// virtualDbContext.AddRange(userMods);
// virtualDbContext.SaveChanges();
//}
virtualDbContext.AddRange(userMods);
virtualDbContext.SaveChanges();
}
}
}
}

View File

@ -21,5 +21,6 @@ namespace Sample.SqlServer.DbContexts
modelBuilder.ApplyConfiguration(new SysTestMap());
}
public override Type ShardingDbContextType => this.GetType();
}
}

View File

@ -5,4 +5,12 @@
<LangVersion>9.0</LangVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="5.0.9" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\ShardingCore\ShardingCore.csproj" />
</ItemGroup>
</Project>

View File

@ -1,21 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Data.SqlClient;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Sample.SqlServer.DbContexts;
using Sample.SqlServer.Shardings;
using ShardingCore;
using ShardingCore.EFCores;
using ShardingCore.SqlServer;
namespace Sample.SqlServer
{
@ -30,31 +21,17 @@ namespace Sample.SqlServer
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddShardingSqlServer(o =>
{
o.EnsureCreatedWithOutShardingTable = false;
o.CreateShardingTableOnStart = false;
o.UseShardingDbContext<DefaultTableDbContext>( dbConfig =>
{
dbConfig.AddShardingTableRoute<SysUserModVirtualTableRoute>();
});
//o.AddDataSourceVirtualRoute<>();
});
services.AddDbContext<DefaultTableDbContext>(o => o.UseSqlServer("Data Source=localhost;Initial Catalog=ShardingCoreDB;Integrated Security=True"));
services.AddShardingDbContext<DefaultShardingDbContext, DefaultTableDbContext>(op =>
services.AddShardingDbContext<DefaultShardingDbContext, DefaultTableDbContext>(o => o.UseSqlServer("Data Source=localhost;Initial Catalog=ShardingCoreDBxx;Integrated Security=True;MultipleActiveResultSets=True;")
,op =>
{
op.UseShardingDbContextOptions((connection, builder) =>
{
return builder.UseSqlServer(connection).UseLoggerFactory(efLogger)
.UseQueryTrackingBehavior(QueryTrackingBehavior.TrackAll)
.ReplaceService<IModelCacheKeyFactory, ShardingModelCacheKeyFactory>()
.ReplaceService<IModelCustomizer, ShardingModelCustomizer>().Options;
op.EnsureCreatedWithOutShardingTable = true;
op.CreateShardingTableOnStart = true;
op.UseShardingDbContextOptions((connection, builder) => builder.UseSqlServer(connection).UseLoggerFactory(efLogger));
op.AddShardingTableRoute<SysUserModVirtualTableRoute>();
});
},o =>
o.UseSqlServer("Data Source=localhost;Initial Catalog=ShardingCoreDB;Integrated Security=True;MultipleActiveResultSets=True;").UseSharding());
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
@ -70,7 +47,7 @@ namespace Sample.SqlServer
app.UseRouting();
app.UseEndpoints(endpoints => { endpoints.MapControllers(); });
//app.DbSeed();
app.DbSeed();
}
}
}

View File

@ -1,83 +0,0 @@
using Microsoft.EntityFrameworkCore;
using ShardingCore.DbContexts.Abstractions;
using ShardingCore.Helpers;
using ShardingCore.Sharding.Abstractions;
using System;
using System.Collections.Generic;
using System.Linq;
namespace ShardingCore
{
/*
* @Author: xjm
* @Description:
* @Date: 2021/3/5 17:30:10
* @Ver: 1.0
* @Email: 326308290@qq.com
*/
public abstract class AbstractShardingCoreOptions : IShardingCoreOptions
{
private ShardingConfigEntry _shardingConfigEntry;
public void UseShardingDbContext<TContext>(Action<ShardingDbConfigOptions> func) where TContext : DbContext,IShardingTableDbContext
{
if (_shardingConfigEntry!=null)
{
throw new ArgumentException($"same db context inited:[{typeof(TContext)}]");
}
ShardingCoreHelper.CheckContextConstructors<TContext>();
var creator = ShardingCoreHelper.CreateActivator<TContext>();
_shardingConfigEntry = new ShardingConfigEntry(creator, typeof(TContext), func);
}
private readonly Dictionary<Type, Type> _virtualRoutes = new Dictionary<Type, Type>();
public ShardingConfigEntry GetShardingConfig()
{
return _shardingConfigEntry;
}
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];
}
/// <summary>
/// 如果数据库不存在就创建并且创建表除了分表的
/// </summary>
public bool EnsureCreatedWithOutShardingTable { get; set; }
/// <summary>
/// 是否需要在启动时创建分表
/// </summary>
public bool? CreateShardingTableOnStart { get; set; }
public readonly List<Type> _filters = new List<Type>();
/// <summary>
/// 添加filter过滤器
/// </summary>
/// <typeparam name="TFilter"></typeparam>
public void AddDbContextCreateFilter<TFilter>() where TFilter : class, IDbContextCreateFilter
{
if (_filters.Contains(typeof(TFilter)))
throw new ArgumentException("请勿重复添加DbContextCreateFilter");
_filters.Add(typeof(TFilter));
}
public List<Type> GetFilters()
{
return _filters;
}
public bool? IgnoreCreateTableError { get; set; }
}
}

View File

@ -1,13 +0,0 @@
namespace ShardingCore.Core.ShardingAccessors
{
/*
* @Author: xjm
* @Description:
* @Date: Tuesday, 22 December 2020 15:13:44
* @Email: 326308290@qq.com
*/
public interface IShardingAccessor
{
ShardingContext ShardingContext { get; set; }
}
}

View File

@ -1,20 +0,0 @@
namespace ShardingCore.Core.ShardingAccessors
{
/*
* @Author: xjm
* @Description:
* @Date: Wednesday, 23 December 2020 07:51:00
* @Email: 326308290@qq.com
*/
/// <summary>
/// 查询scope创建
/// </summary>
public interface IShardingScopeFactory
{
/// <summary>
/// 创建查询scope
/// </summary>
/// <returns></returns>
ShardingScope CreateScope();
}
}

View File

@ -1,26 +0,0 @@
using System.Threading;
using ShardingCore.Core.VirtualTables;
namespace ShardingCore.Core.ShardingAccessors
{
/*
* @Author: xjm
* @Description:
* @Date: Tuesday, 22 December 2020 15:14:15
* @Email: 326308290@qq.com
*/
/// <summary>
/// 分表访问器
/// </summary>
public class ShardingAccessor : IShardingAccessor
{
private static AsyncLocal<ShardingContext> _shardingContext = new AsyncLocal<ShardingContext>();
/// <inheritdoc />
public ShardingContext ShardingContext
{
get => _shardingContext.Value;
set => _shardingContext.Value = value;
}
}
}

View File

@ -1,71 +0,0 @@
using System.Collections.Generic;
using ShardingCore.Core.VirtualRoutes.TableRoutes.RoutingRuleEngine;
using ShardingCore.Core.VirtualTables;
using ShardingCore.Extensions;
namespace ShardingCore.Core.ShardingAccessors
{
/*
* @Author: xjm
* @Description:
* @Date: Tuesday, 22 December 2020 15:04:47
* @Email: 326308290@qq.com
*/
public class ShardingContext
{
private ShardingContext(RouteResult routeResult)
{
foreach (var physicTable in routeResult.ReplaceTables)
{
_shardingTables.Add(physicTable.VirtualTable, new List<string>(1){physicTable.Tail});
}
}
/// <summary>
/// 分表操作上下文 key:物理表名 value:虚拟表和本次分表tails
/// </summary>
private readonly Dictionary<IVirtualTable, List<string>> _shardingTables = new Dictionary<IVirtualTable, List<string>>();
/// <summary>
/// 尝试添加本次操作表
/// </summary>
/// <param name="virtualTable"></param>
/// <param name="tails"></param>
/// <returns></returns>
public void TryAddShardingTable(IVirtualTable virtualTable, List<string> tails)
{
_shardingTables.Add(virtualTable, tails);
}
/// <summary>
/// 创建一个分表上下文
/// </summary>
/// <returns></returns>
public static ShardingContext Create(RouteResult routeResult)
{
return new ShardingContext(routeResult);
}
/// <summary>
/// 获取分表信息
/// </summary>
/// <param name="virtualTable"></param>
/// <returns></returns>
public List<string> GetContextQueryTails(IVirtualTable virtualTable)
{
if (_shardingTables.ContainsKey(virtualTable))
return _shardingTables[virtualTable] ?? new List<string>(0);
return new List<string>(0);
}
/// <summary>
/// 是否是空的
/// </summary>
/// <returns></returns>
public bool IsEmpty()
{
return _shardingTables.IsEmpty();
}
}
}

View File

@ -1,36 +0,0 @@
using System;
namespace ShardingCore.Core.ShardingAccessors
{
/*
* @Author: xjm
* @Description:
* @Date: Wednesday, 23 December 2020 07:51:30
* @Email: 326308290@qq.com
*/
public class ShardingScope : IDisposable
{
/// <summary>
/// 分表配置访问器
/// </summary>
public IShardingAccessor ShardingAccessor { get; }
/// <summary>
/// 构造函数
/// </summary>
/// <param name="shardingAccessor"></param>
public ShardingScope(IShardingAccessor shardingAccessor)
{
ShardingAccessor = shardingAccessor;
}
/// <summary>
/// 回收
/// </summary>
public void Dispose()
{
ShardingAccessor.ShardingContext = null;
}
}
}

View File

@ -1,34 +0,0 @@
namespace ShardingCore.Core.ShardingAccessors
{
/*
* @Author: xjm
* @Description:
* @Date: Wednesday, 23 December 2020 08:11:06
* @Email: 326308290@qq.com
*/
/// <summary>
/// 分表查询环境创建
/// </summary>
public class ShardingScopeFactory : IShardingScopeFactory
{
private readonly IShardingAccessor _shardingAccessor;
/// <summary>
/// 构造函数
/// </summary>
/// <param name="shardingAccessor"></param>
public ShardingScopeFactory(IShardingAccessor shardingAccessor)
{
_shardingAccessor = shardingAccessor;
}
/// <summary>
/// 创建scope
/// </summary>
/// <returns></returns>
public ShardingScope CreateScope()
{
_shardingAccessor.ShardingContext = null;
return new ShardingScope(_shardingAccessor);
}
}
}

View File

@ -1,4 +1,7 @@
using System;
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore;
using ShardingCore.Sharding.Abstractions;
namespace ShardingCore.Core.VirtualRoutes.TableRoutes.RoutingRuleEngine
{
@ -10,6 +13,7 @@ namespace ShardingCore.Core.VirtualRoutes.TableRoutes.RoutingRuleEngine
*/
public interface IRouteRuleEngine
{
IEnumerable<RouteResult> Route<T>(RouteRuleContext<T> routeRuleContext);
IEnumerable<RouteResult> Route<T,TShardingDbContext>(RouteRuleContext<T> routeRuleContext) where TShardingDbContext:DbContext,IShardingDbContext;
IEnumerable<RouteResult> Route<T>(Type shardingDbContextType,RouteRuleContext<T> routeRuleContext);
}
}

View File

@ -1,5 +1,8 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using ShardingCore.Sharding.Abstractions;
namespace ShardingCore.Core.VirtualRoutes.TableRoutes.RoutingRuleEngine
{
@ -13,7 +16,9 @@ namespace ShardingCore.Core.VirtualRoutes.TableRoutes.RoutingRuleEngine
{
IRouteRuleEngine CreateEngine();
RouteRuleContext<T> CreateContext<T>(IQueryable<T> queryable);
IEnumerable<RouteResult> Route<T>(IQueryable<T> queryable);
IEnumerable<RouteResult> Route<T>(RouteRuleContext<T> ruleContext);
IEnumerable<RouteResult> Route<T,TShardingDbContext>(IQueryable<T> queryable) where TShardingDbContext:DbContext,IShardingDbContext;
IEnumerable<RouteResult> Route<T, TShardingDbContext>(RouteRuleContext<T> ruleContext) where TShardingDbContext : DbContext, IShardingDbContext;
IEnumerable<RouteResult> Route<T>(Type shardingDbContextType,IQueryable<T> queryable);
IEnumerable<RouteResult> Route<T>(Type shardingDbContextType,RouteRuleContext<T> ruleContext);
}
}

View File

@ -1,8 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using ShardingCore.Core.PhysicTables;
using ShardingCore.Core.VirtualTables;
using ShardingCore.Extensions;
using ShardingCore.Sharding.Abstractions;
#if !EFCORE5
using ShardingCore.Extensions;
#endif
@ -24,30 +28,9 @@ namespace ShardingCore.Core.VirtualRoutes.TableRoutes.RoutingRuleEngine
_virtualTableManager = virtualTableManager;
}
public IEnumerable<RouteResult> Route<T>(RouteRuleContext<T> routeRuleContext)
public IEnumerable<RouteResult> Route<T, TShardingDbContext>(RouteRuleContext<T> routeRuleContext) where TShardingDbContext : DbContext, IShardingDbContext
{
Dictionary<IVirtualTable, ISet<IPhysicTable>> routeMaps = new Dictionary<IVirtualTable, ISet<IPhysicTable>>();
var queryEntities = routeRuleContext.Queryable.ParseQueryableRoute();
var shardingEntities = queryEntities.Where(o => o.IsShardingTable());
foreach (var shardingEntity in shardingEntities)
{
var virtualTable = _virtualTableManager.GetVirtualTable(shardingEntity);
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 Route(typeof(TShardingDbContext), routeRuleContext);
////先添加手动路由到当前上下文,之后将不再手动路由里面的自动路由添加到当前上下文
//foreach (var kv in routeRuleContext.ManualTails)
//{
@ -105,6 +88,32 @@ namespace ShardingCore.Core.VirtualRoutes.TableRoutes.RoutingRuleEngine
// }
// }
//}
}
public IEnumerable<RouteResult> Route<T>(Type shardingDbContextType, RouteRuleContext<T> routeRuleContext)
{
Dictionary<IVirtualTable, ISet<IPhysicTable>> routeMaps = new Dictionary<IVirtualTable, ISet<IPhysicTable>>();
var queryEntities = routeRuleContext.Queryable.ParseQueryableRoute();
var shardingEntities = queryEntities.Where(o => o.IsShardingTable());
foreach (var shardingEntity in shardingEntities)
{
var virtualTable = _virtualTableManager.GetVirtualTable(shardingDbContextType, shardingEntity);
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,6 +1,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using ShardingCore.Core.VirtualTables;
using ShardingCore.Sharding.Abstractions;
namespace ShardingCore.Core.VirtualRoutes.TableRoutes.RoutingRuleEngine
{
@ -31,17 +34,30 @@ namespace ShardingCore.Core.VirtualRoutes.TableRoutes.RoutingRuleEngine
return new RouteRuleContext<T>(queryable, _virtualTableManager);
}
public IEnumerable<RouteResult> Route<T>(IQueryable<T> queryable)
public IEnumerable<RouteResult> Route<T, TShardingDbContext>(IQueryable<T> queryable) where TShardingDbContext : DbContext, IShardingDbContext
{
var engine = CreateEngine();
var ruleContext = CreateContext<T>(queryable);
return engine.Route(ruleContext);
return engine.Route<T,TShardingDbContext>(ruleContext);
}
public IEnumerable<RouteResult> Route<T>(RouteRuleContext<T> ruleContext)
public IEnumerable<RouteResult> Route<T, TShardingDbContext>(RouteRuleContext<T> ruleContext) where TShardingDbContext : DbContext, IShardingDbContext
{
var engine = CreateEngine();
return engine.Route(ruleContext);
return engine.Route<T, TShardingDbContext>(ruleContext);
}
public IEnumerable<RouteResult> Route<T>(Type shardingDbContextType, IQueryable<T> queryable)
{
var engine = CreateEngine();
var ruleContext = CreateContext<T>(queryable);
return engine.Route(shardingDbContextType,ruleContext);
}
public IEnumerable<RouteResult> Route<T>(Type shardingDbContextType, RouteRuleContext<T> ruleContext)
{
var engine = CreateEngine();
return engine.Route(shardingDbContextType,ruleContext);
}
}
}

View File

@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore;
using ShardingCore.Core.PhysicTables;
using ShardingCore.Sharding.Abstractions;
namespace ShardingCore.Core.VirtualTables
{
@ -18,58 +20,70 @@ namespace ShardingCore.Core.VirtualTables
/// <summary>
/// 添加虚拟表应用启动时 add virtual table when app start
/// </summary>
/// <param name="shardingDbContextType">分表的dbcontext类型</param>
/// <param name="virtualTable">虚拟表</param>
void AddVirtualTable(IVirtualTable virtualTable);
void AddVirtualTable(Type shardingDbContextType,IVirtualTable virtualTable);
/// <summary>
/// 获取虚拟表 get virtual table by sharding entity type
/// </summary>
/// <param name="shardingDbContextType">分表的dbcontext类型</param>
/// <param name="shardingEntityType"></param>
/// <returns></returns>
IVirtualTable GetVirtualTable(Type shardingEntityType);
IVirtualTable GetVirtualTable(Type shardingDbContextType, Type shardingEntityType);
/// <summary>
/// 获取虚拟表 get virtual table by sharding entity type
/// </summary>
/// <returns></returns>
IVirtualTable<T> GetVirtualTable<T>() where T : class, IShardingTable;
IVirtualTable<T> GetVirtualTable<TDbContext,T>() where T : class, IShardingTable where TDbContext : DbContext, IShardingDbContext;
/// <summary>
/// 获取虚拟表 get virtual table by original table name
/// </summary>
/// <param name="shardingDbContextType">分表的dbcontext类型</param>
/// <param name="originalTableName"></param>
/// <returns></returns>
IVirtualTable GetVirtualTable(string originalTableName);
IVirtualTable GetVirtualTable(Type shardingDbContextType, string originalTableName);
IVirtualTable GetVirtualTable<TDbContext>(string originalTableName) where TDbContext : DbContext, IShardingDbContext;
/// <summary>
/// 尝试获取虚拟表没有返回null
/// </summary>
/// <param name="shardingDbContextType">分表的dbcontext类型</param>
/// <param name="originalTableName"></param>
/// <returns></returns>
IVirtualTable TryGetVirtualTable(string originalTableName);
IVirtualTable TryGetVirtualTable(Type shardingDbContextType, string originalTableName);
IVirtualTable TryGetVirtualTablee<TDbContext>(string originalTableName) where TDbContext : DbContext, IShardingDbContext;
/// <summary>
/// 获取所有的虚拟表 get all virtual table
/// </summary>
/// <param name="shardingDbContextType">分表的dbcontext类型</param>
/// <returns></returns>
List<IVirtualTable> GetAllVirtualTables();
List<IVirtualTable> GetAllVirtualTables(Type shardingDbContextType);
List<IVirtualTable> GetAllVirtualTables<TDbContext>() where TDbContext : DbContext, IShardingDbContext;
/// <summary>
/// 添加物理表 add physic table
/// </summary>
/// <param name="shardingDbContextType">分表的dbcontext类型</param>
/// <param name="virtualTable"></param>
/// <param name="physicTable"></param>
void AddPhysicTable(IVirtualTable virtualTable, IPhysicTable physicTable);
void AddPhysicTable(Type shardingDbContextType,IVirtualTable virtualTable, IPhysicTable physicTable);
void AddPhysicTable<TDbContext>(IVirtualTable virtualTable, IPhysicTable physicTable) where TDbContext : DbContext, IShardingDbContext;
/// <summary>
/// 添加物理表 add physic table
/// </summary>
/// <param name="shardingDbContextType">分表的dbcontext类型</param>
/// <param name="shardingEntityType"></param>
/// <param name="physicTable"></param>
void AddPhysicTable(Type shardingEntityType, IPhysicTable physicTable);
void AddPhysicTable(Type shardingDbContextType,Type shardingEntityType, IPhysicTable physicTable);
void AddPhysicTable<TDbContext>(Type shardingEntityType, IPhysicTable physicTable) where TDbContext : DbContext, IShardingDbContext;
///// <summary>
///// 添加物理表 add physic table

View File

@ -2,8 +2,11 @@ using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using ShardingCore.Core.PhysicTables;
using ShardingCore.Exceptions;
using ShardingCore.Extensions;
using ShardingCore.Sharding.Abstractions;
namespace ShardingCore.Core.VirtualTables
{
@ -19,8 +22,9 @@ namespace ShardingCore.Core.VirtualTables
public class OneDbVirtualTableManager : IVirtualTableManager
{
private readonly IServiceProvider _serviceProvider;
private readonly ConcurrentDictionary<Type, IVirtualTable> _shardingVirtualTables = new ConcurrentDictionary<Type, IVirtualTable>();
private readonly ConcurrentDictionary<string, IVirtualTable> _shardingOriginalTaleVirtualTales = new ConcurrentDictionary<string, IVirtualTable>();
//{sharidngDbContextType:{entityType,virtualTableType}}
private readonly ConcurrentDictionary<Type, ConcurrentDictionary<Type, IVirtualTable>> _shardingVirtualTables = new ConcurrentDictionary<Type, ConcurrentDictionary<Type, IVirtualTable>>();
private readonly ConcurrentDictionary<Type, ConcurrentDictionary<string, IVirtualTable>> _shardingOriginalTaleVirtualTales = new ConcurrentDictionary<Type, ConcurrentDictionary<string, IVirtualTable>>();
public OneDbVirtualTableManager(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
@ -38,62 +42,135 @@ namespace ShardingCore.Core.VirtualTables
//}
}
public void AddVirtualTable(IVirtualTable virtualTable)
private void CheckShardingDbContextType(Type shardingDbContextType)
{
if (!_shardingVirtualTables.ContainsKey(virtualTable.EntityType))
{
_shardingVirtualTables.TryAdd(virtualTable.EntityType, virtualTable);
if (!shardingDbContextType.IsShardingDbContext())
throw new ShardingCoreException(
$"{shardingDbContextType.FullName} must impl {nameof(IShardingDbContext)}");
}
if (!_shardingOriginalTaleVirtualTales.ContainsKey(virtualTable.GetOriginalTableName()))
private void CheckShardingTableEntityType(Type shardingEntityType)
{
_shardingOriginalTaleVirtualTales.TryAdd(virtualTable.GetOriginalTableName(), virtualTable);
if (!shardingEntityType.IsShardingTable())
throw new ShardingCoreException(
$"{shardingEntityType.FullName} must impl {nameof(IShardingTable)}");
}
private string CreateShardingEntityTypeKey(Type shardingDbContextType, Type entityType)
{
return $"{shardingDbContextType.FullName}{entityType.FullName}";
}
private string CreateShardingTableNameKey(Type shardingDbContextType, string originalTableName)
{
return $"{shardingDbContextType.FullName}{originalTableName}";
}
public void AddVirtualTable(Type shardingDbContextType, IVirtualTable virtualTable)
{
CheckShardingDbContextType(shardingDbContextType);
var innerShardingVirtualTables = _shardingVirtualTables.GetOrAdd(shardingDbContextType,
key => new ConcurrentDictionary<Type, IVirtualTable>());
if (!innerShardingVirtualTables.ContainsKey(virtualTable.EntityType))
{
innerShardingVirtualTables.TryAdd(virtualTable.EntityType, virtualTable);
}
var innerShardingOriginalTableVirtualTables = _shardingOriginalTaleVirtualTales.GetOrAdd(shardingDbContextType,type=>new ConcurrentDictionary<string, IVirtualTable>());
if (!innerShardingOriginalTableVirtualTables.ContainsKey(virtualTable.GetOriginalTableName()))
{
innerShardingOriginalTableVirtualTables.TryAdd(virtualTable.GetOriginalTableName(), virtualTable);
}
}
public IVirtualTable GetVirtualTable(Type shardingEntityType)
public IVirtualTable GetVirtualTable(Type shardingDbContextType, Type shardingEntityType)
{
if (!_shardingVirtualTables.TryGetValue(shardingEntityType, out var virtualTable))
CheckShardingDbContextType(shardingDbContextType);
CheckShardingTableEntityType(shardingEntityType);
var shardingKey = CreateShardingEntityTypeKey(shardingDbContextType, shardingEntityType);
if(!_shardingVirtualTables.TryGetValue(shardingDbContextType,out var innerShardingVirtualTables) || innerShardingVirtualTables.IsEmpty())
throw new ShardingVirtualTableNotFoundException(shardingDbContextType.FullName);
if (!innerShardingVirtualTables.TryGetValue(shardingEntityType, out var virtualTable)||virtualTable==null)
throw new ShardingVirtualTableNotFoundException(shardingEntityType.FullName);
return virtualTable;
}
public IVirtualTable<T> GetVirtualTable<T>() where T : class, IShardingTable
public IVirtualTable<T> GetVirtualTable<TDbContext, T>() where T : class, IShardingTable where TDbContext : DbContext, IShardingDbContext
{
return (IVirtualTable<T>)GetVirtualTable(typeof(T));
return (IVirtualTable<T>)GetVirtualTable(typeof(TDbContext), typeof(T));
}
public IVirtualTable GetVirtualTable(string originalTableName)
public IVirtualTable GetVirtualTable(Type shardingDbContextType, string originalTableName)
{
if (!_shardingOriginalTaleVirtualTales.TryGetValue(originalTableName, out var virtualTable)||virtualTable==null)
CheckShardingDbContextType(shardingDbContextType);
if (!_shardingOriginalTaleVirtualTales.TryGetValue(shardingDbContextType, out var innerShardingOriginalTableVirtualTables) || innerShardingOriginalTableVirtualTables.IsEmpty())
throw new ShardingVirtualTableNotFoundException(shardingDbContextType.FullName);
if(!innerShardingOriginalTableVirtualTables.TryGetValue(originalTableName,out var virtualTable)|| virtualTable==null)
throw new ShardingVirtualTableNotFoundException(originalTableName);
return virtualTable;
}
public IVirtualTable TryGetVirtualTable(string originalTableName)
public IVirtualTable GetVirtualTable<TDbContext>(string originalTableName) where TDbContext : DbContext, IShardingDbContext
{
if (!_shardingOriginalTaleVirtualTales.TryGetValue(originalTableName, out var virtualTable))
return GetVirtualTable(typeof(TDbContext), originalTableName);
}
public IVirtualTable TryGetVirtualTable(Type shardingDbContextType, string originalTableName)
{
CheckShardingDbContextType(shardingDbContextType);
if (!_shardingOriginalTaleVirtualTales.TryGetValue(shardingDbContextType,
out var innerShardingOriginalTableVirtualTables) || innerShardingOriginalTableVirtualTables.IsEmpty())
return null;
if (!innerShardingOriginalTableVirtualTables.TryGetValue(originalTableName, out var virtualTable) || virtualTable == null)
return null;
return virtualTable;
}
public List<IVirtualTable> GetAllVirtualTables()
public IVirtualTable TryGetVirtualTablee<TDbContext>(string originalTableName) where TDbContext : DbContext, IShardingDbContext
{
return _shardingVirtualTables.Values.ToList();
return TryGetVirtualTable(typeof(TDbContext), originalTableName);
}
public void AddPhysicTable(IVirtualTable virtualTable, IPhysicTable physicTable)
public List<IVirtualTable> GetAllVirtualTables(Type shardingDbContextType)
{
AddPhysicTable(virtualTable.EntityType, physicTable);
if (!_shardingOriginalTaleVirtualTales.TryGetValue(shardingDbContextType,
out var innerShardingOriginalTableVirtualTables) || innerShardingOriginalTableVirtualTables.IsEmpty())
return new List<IVirtualTable>();
var keyPrefix = shardingDbContextType.FullName;
return innerShardingOriginalTableVirtualTables.Values.ToList();
}
public void AddPhysicTable(Type shardingEntityType, IPhysicTable physicTable)
public List<IVirtualTable> GetAllVirtualTables<TDbContext>() where TDbContext : DbContext, IShardingDbContext
{
var virtualTable = GetVirtualTable(shardingEntityType);
return GetAllVirtualTables(typeof(TDbContext));
}
public void AddPhysicTable(Type shardingDbContextType, IVirtualTable virtualTable, IPhysicTable physicTable)
{
AddPhysicTable(shardingDbContextType, virtualTable.EntityType, physicTable);
}
public void AddPhysicTable<TDbContext>(IVirtualTable virtualTable, IPhysicTable physicTable) where TDbContext : DbContext, IShardingDbContext
{
AddPhysicTable(typeof(TDbContext), virtualTable.EntityType, physicTable);
}
public void AddPhysicTable(Type shardingDbContextType, Type shardingEntityType, IPhysicTable physicTable)
{
var virtualTable = GetVirtualTable(shardingDbContextType, shardingEntityType);
virtualTable.AddPhysicTable(physicTable);
}
public void AddPhysicTable<TDbContext>(Type shardingEntityType, IPhysicTable physicTable) where TDbContext : DbContext, IShardingDbContext
{
var virtualTable = GetVirtualTable(typeof(TDbContext), shardingEntityType);
virtualTable.AddPhysicTable(physicTable);
}
///// <summary>
///// 是否是分表字段
@ -103,7 +180,7 @@ namespace ShardingCore.Core.VirtualTables
///// <returns></returns>
//public bool IsShardingKey(Type shardingEntityType, string shardingField)
//{
// return _virtualTables.TryGetValue(shardingEntityType, out var virtualTable) && virtualTable.ShardingConfig.ShardingField == shardingField;
// return _virtualTables.TryGetValue(shardingEntityType, out var virtualTable) && virtualTable.ShardingConfigOption.ShardingField == shardingField;
//}
}
}

View File

@ -1,17 +1,17 @@
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Internal;
using Microsoft.EntityFrameworkCore.Query.Internal;
using Microsoft.Extensions.DependencyInjection;
using ShardingCore.Core.Internal.StreamMerge;
using ShardingCore.Core.ShardingAccessors;
using ShardingCore.Core.VirtualRoutes.TableRoutes.RoutingRuleEngine;
using ShardingCore.Core.VirtualTables;
using ShardingCore.DbContexts;
using ShardingCore.DbContexts.Abstractions;
using ShardingCore.DbContexts.ShardingDbContexts;
using ShardingCore.EFCores;
using ShardingCore.Helpers;
using ShardingCore.Sharding;
using ShardingCore.Sharding.Abstractions;
using ShardingCore.Sharding.Enumerators;
using ShardingCore.TableCreator;
using System;
namespace ShardingCore
{
@ -24,9 +24,48 @@ namespace ShardingCore
public static class DIExtension
{
public static IServiceCollection AddShardingCore(this IServiceCollection services)
public static IServiceCollection AddShardingDbContext<TShardingDbContext, TActualDbContext>(this IServiceCollection services,
Action<DbContextOptionsBuilder> optionsAction = null,
Action<ShardingConfigOption<TShardingDbContext,TActualDbContext>> configure=null,
ServiceLifetime contextLifetime = ServiceLifetime.Scoped,
ServiceLifetime optionsLifetime = ServiceLifetime.Scoped)
where TActualDbContext : DbContext, IShardingTableDbContext
where TShardingDbContext : DbContext, IShardingTableDbContext<TActualDbContext>
{
if (configure == null)
throw new ArgumentNullException($"AddShardingDbContext params is null :{nameof(configure)}");
ShardingCoreHelper.CheckContextConstructors<TActualDbContext>();
var shardingConfigOptions = new ShardingConfigOption<TShardingDbContext,TActualDbContext>();
configure?.Invoke(shardingConfigOptions);
services.AddSingleton<IShardingConfigOption, ShardingConfigOption<TShardingDbContext, TActualDbContext>>(sp=> shardingConfigOptions);
//添加创建TActualDbContext 的 创建者
var config = new ShardingDbContextOptionsBuilderConfig<TShardingDbContext>(shardingConfigOptions.ShardingDbContextOptionsCreator);
services.AddSingleton<IShardingDbContextOptionsBuilderConfig, ShardingDbContextOptionsBuilderConfig<TShardingDbContext>>(sp=> config);
//添加创建TActualDbContext创建者
services.AddSingleton<IShardingDbContextCreatorConfig,DefaultShardingDbContextCreatorConfig<TShardingDbContext, TActualDbContext>>(sp=> new DefaultShardingDbContextCreatorConfig<TShardingDbContext, TActualDbContext>(typeof(TActualDbContext)));
Action<DbContextOptionsBuilder> shardingOptionAction = option =>
{
optionsAction?.Invoke(option);
option.UseSharding();
};
services.AddDbContext<TShardingDbContext>(shardingOptionAction, contextLifetime, optionsLifetime);
services.AddInternalShardingCore();
services.AddSingleton<IShardingBootstrapper, ShardingBootstrapper>();
return services;
}
internal static IServiceCollection AddInternalShardingCore(this IServiceCollection services)
{
services.AddSingleton<IDbContextCreateFilterManager, DbContextCreateFilterManager>();
services.AddSingleton<IStreamMergeContextFactory, StreamMergeContextFactory>();
services.AddSingleton<IShardingDbContextFactory, ShardingDbContextFactory>();
@ -38,33 +77,20 @@ namespace ShardingCore
//分表引擎
services.AddSingleton<IRouteRuleEngine, QueryRouteRuleEngines>();
//services.AddSingleton(typeof(IVirtualTable<>), typeof(OneDbVirtualTable<>));
services.AddSingleton<IShardingAccessor, ShardingAccessor>();
services.AddSingleton<IShardingScopeFactory, ShardingScopeFactory>();
//services.AddSingleton<IShardingAccessor, ShardingAccessor>();
//services.AddSingleton<IShardingScopeFactory, ShardingScopeFactory>();
return services;
}
public static IServiceCollection AddShardingDbContext<TShardingDbContext, TActualDbContext>(this IServiceCollection services,
Action<ShardingConfig<TActualDbContext>> configure,
Action<DbContextOptionsBuilder> optionsAction = null,
ServiceLifetime contextLifetime = ServiceLifetime.Scoped,
ServiceLifetime optionsLifetime = ServiceLifetime.Scoped)
where TActualDbContext : DbContext, IShardingTableDbContext
where TShardingDbContext : DbContext
internal static DbContextOptionsBuilder UseSharding(this DbContextOptionsBuilder optionsBuilder)
{
if (configure == null)
throw new ArgumentNullException($"AddScfSqlServerProvider 参数不能为空:{nameof(configure)}");
var shardingConfig = new ShardingConfig<TActualDbContext>();
configure?.Invoke(shardingConfig);
services.AddSingleton(shardingConfig);
services.AddDbContext<TShardingDbContext>(optionsAction, contextLifetime, optionsLifetime);
services.AddShardingCore();
services.AddSingleton<IShardingBootstrapper, ShardingBootstrapper>();
return services;
return optionsBuilder.ReplaceService<IDbSetSource, ShardingDbSetSource>()
.ReplaceService<IQueryCompiler, ShardingQueryCompiler>();
}
internal static DbContextOptionsBuilder UseInnerDbContextSharding<TShardingDbContext>(this DbContextOptionsBuilder optionsBuilder) where TShardingDbContext:DbContext,IShardingDbContext
{
return optionsBuilder.ReplaceService<IModelCacheKeyFactory, ShardingModelCacheKeyFactory>()
.ReplaceService<IModelCustomizer, ShardingModelCustomizer<TShardingDbContext>>();
}
}
}

View File

@ -1,31 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ShardingCore.DbContexts.Abstractions
{
/*
* @Author: xjm
* @Description:
* @Date: 2021/3/13 8:19:26
* @Ver: 1.0
* @Email: 326308290@qq.com
*/
public class DbContextCreateFilterManager: IDbContextCreateFilterManager
{
private readonly List<IDbContextCreateFilter> _filters = new List<IDbContextCreateFilter>();
public void RegisterFilter(IDbContextCreateFilter filter)
{
if (null == filter)
throw new ArgumentNullException(nameof(filter));
if(!_filters.Contains(filter))
_filters.Add(filter);
}
public List<IDbContextCreateFilter> GetFilters()
{
return _filters;
}
}
}

View File

@ -1,24 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.EntityFrameworkCore;
namespace ShardingCore.DbContexts.Abstractions
{
/*
* @Author: xjm
* @Description:
* @Date: 2021/3/13 8:17:41
* @Ver: 1.0
* @Email: 326308290@qq.com
*/
public interface IDbContextCreateFilter
{
/// <summary>
/// dbContext创建完成后
/// </summary>
/// <param name="dbContext"></param>
/// <param name="s"></param>
void CreateAfter(DbContext dbContext);
}
}

View File

@ -1,18 +0,0 @@
using System;
using System.Collections.Generic;
namespace ShardingCore.DbContexts.Abstractions
{
/*
* @Author: xjm
* @Description:
* @Date: Friday, 12 March 2021 22:25:10
* @Email: 326308290@qq.com
*/
public interface IDbContextCreateFilterManager
{
void RegisterFilter(IDbContextCreateFilter filter);
List<IDbContextCreateFilter> GetFilters();
}
}

View File

@ -1,47 +0,0 @@
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Query.Internal;
using Microsoft.Extensions.Logging;
using ShardingCore.EFCores;
namespace ShardingCore.DbContexts.Abstractions
{
/*
* @Author: xjm
* @Description:
* @Date: Sunday, 07 February 2021 15:25:36
* @Email: 326308290@qq.com
*/
public class ShardingDbContextOptionBuilder
{
private readonly DbContextOptionsBuilder _builder;
public ShardingDbContextOptionBuilder():this(new DbContextOptionsBuilder())
{
}
public ShardingDbContextOptionBuilder(DbContextOptionsBuilder optionsBuilder)
{
_builder = optionsBuilder
.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking)
.ReplaceService<IQueryCompiler, ShardingQueryCompiler>()
.ReplaceService<IModelCacheKeyFactory, ShardingModelCacheKeyFactory>()
.ReplaceService<IModelCustomizer, ShardingModelCustomizer>();
}
public ShardingDbContextOptionBuilder UseLoggerFactory(ILoggerFactory loggerFactory)
{
_builder.UseLoggerFactory(loggerFactory);
return this;
}
public DbContextOptionsBuilder GetOptionsBuilder()
{
return _builder;
}
}
public class ShardingDbContextOptionBuilder<T>:ShardingDbContextOptionBuilder where T:DbContext
{
}
}

View File

@ -3,6 +3,7 @@ using System.Data.Common;
using Microsoft.EntityFrameworkCore;
using ShardingCore.DbContexts.ShardingDbContexts;
using ShardingCore.DbContexts.VirtualDbContexts;
using ShardingCore.Sharding.Abstractions;
namespace ShardingCore.DbContexts
{
@ -14,7 +15,8 @@ namespace ShardingCore.DbContexts
*/
public interface IShardingDbContextFactory
{
DbContext Create(ShardingDbContextOptions shardingDbContextOptions);
DbContext Create(Type shardingDbContextType,ShardingDbContextOptions shardingDbContextOptions);
DbContext Create<TShardingDbContext>(ShardingDbContextOptions shardingDbContextOptions) where TShardingDbContext:DbContext,IShardingDbContext;
//DbContext Create(DbConnection dbConnection,string tail);
}
}

View File

@ -1,16 +0,0 @@
using System;
using Microsoft.EntityFrameworkCore;
namespace ShardingCore.DbContexts
{
/*
* @Author: xjm
* @Description:
* @Date: Tuesday, 29 December 2020 15:22:06
* @Email: 326308290@qq.com
*/
public interface IShardingParallelDbContextFactory
{
DbContext Create(string tail);
}
}

View File

@ -1,16 +0,0 @@
using System;
using Microsoft.EntityFrameworkCore;
namespace ShardingCore.DbContexts
{
/*
* @Author: xjm
* @Description:
* @Date: Saturday, 20 February 2021 15:04:25
* @Email: 326308290@qq.com
*/
public interface IShardingParallelDbContextFactoryManager
{
public DbContext CreateDbContext(string connectKey, string tail);
}
}

View File

@ -1,14 +1,11 @@
using System;
using System.Data.Common;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using ShardingCore.Core.VirtualTables;
using ShardingCore.DbContexts.Abstractions;
using ShardingCore.DbContexts.ShardingDbContexts;
using ShardingCore.DbContexts.VirtualDbContexts;
using ShardingCore.Exceptions;
using ShardingCore.Extensions;
using ShardingCore.Sharding.Abstractions;
using System;
using System.Collections.Generic;
using System.Linq;
namespace ShardingCore.DbContexts
{
@ -20,45 +17,38 @@ namespace ShardingCore.DbContexts
*/
public class ShardingDbContextFactory:IShardingDbContextFactory
{
private readonly IShardingCoreOptions _shardingCoreOptions;
private readonly IDbContextCreateFilterManager _dbContextCreateFilterManager;
private readonly IDbContextOptionsProvider _dbContextOptionsProvider;
private readonly IEnumerable<IShardingDbContextCreatorConfig> _shardingDbContextCreatorConfigs;
public ShardingDbContextFactory(IShardingCoreOptions shardingCoreOptions, IDbContextCreateFilterManager dbContextCreateFilterManager,IDbContextOptionsProvider dbContextOptionsProvider)
public ShardingDbContextFactory(IEnumerable<IShardingDbContextCreatorConfig> shardingDbContextCreatorConfigs)
{
_shardingCoreOptions = shardingCoreOptions;
_dbContextCreateFilterManager = dbContextCreateFilterManager;
_dbContextOptionsProvider = dbContextOptionsProvider;
_shardingDbContextCreatorConfigs = shardingDbContextCreatorConfigs;
}
public DbContext Create(ShardingDbContextOptions shardingDbContextOptions)
public DbContext Create(Type shardingDbContextType, ShardingDbContextOptions shardingDbContextOptions)
{
if (!shardingDbContextType.IsShardingDbContext())
throw new ShardingCoreException(
$"{shardingDbContextType.FullName} must impl {nameof(IShardingDbContext)}");
var shardingDbContextCreatorConfig = _shardingDbContextCreatorConfigs.FirstOrDefault(o=>o.ShardingDbContextType==shardingDbContextType);
if (shardingDbContextCreatorConfig == null)
{
throw new ShardingCoreException(
$"{shardingDbContextType.FullName} cant found DefaultShardingDbContextCreatorConfig<{shardingDbContextType.Name}> should use {nameof(DIExtension.AddShardingDbContext)}");
}
var tail=shardingDbContextOptions.Tail;
var shardingConfigEntry = _shardingCoreOptions.GetShardingConfig();
var dbContext = shardingConfigEntry.Creator(shardingDbContextOptions);
var dbContext = shardingDbContextCreatorConfig.Creator(shardingDbContextOptions);
if (!string.IsNullOrWhiteSpace(tail) && dbContext is IShardingTableDbContext shardingTableDbContext)
{
shardingTableDbContext.SetShardingTableDbContextTail(tail);
}
var filters = _dbContextCreateFilterManager.GetFilters();
if (filters.Any())
{
foreach (var dbContextCreateFilter in filters)
{
dbContextCreateFilter.CreateAfter(dbContext);
}
}
var dbContextModel = dbContext.Model;
return dbContext;
}
//public DbContext Create(DbConnection dbConnection,string tail)
//{
// var shardingDbContextOptions =
// new ShardingDbContextOptions(_dbContextOptionsProvider.GetDbContextOptions(dbConnection), tail);
// return Create(shardingDbContextOptions);
//}
public DbContext Create<TShardingDbContext>(ShardingDbContextOptions shardingDbContextOptions) where TShardingDbContext : DbContext, IShardingDbContext
{
return Create(typeof(TShardingDbContext), shardingDbContextOptions);
}
}
}

View File

@ -1,26 +0,0 @@
using System;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage;
namespace ShardingCore.DbContexts.Transactions
{
/*
* @Author: xjm
* @Description:
* @Date: Saturday, 14 August 2021 04:19:53
* @Email: 326308290@qq.com
*/
public interface IShardingTransaction:IDisposable
{
bool IsOpened { get; }
bool IsUsed { get; }
void Use(DbContext dbContext);
void Open();
void Rollback();
Task RollbackAsync();
void Commit();
Task CommitAsync();
IDbContextTransaction GetDbContextTransaction();
}
}

View File

@ -1,102 +0,0 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage;
using ShardingCore.Exceptions;
namespace ShardingCore.DbContexts.Transactions
{
/*
* @Author: xjm
* @Description:
* @Date: Saturday, 14 August 2021 04:20:53
* @Email: 326308290@qq.com
*/
public class ShardingTransaction: IShardingTransaction
{
private IDbContextTransaction _dbTransaction;
private bool _isOpened;
public bool IsOpened => _isOpened;
public bool IsUsed => _dbTransaction != null;
private readonly ISet<DbContext> _dbContextUseTransactions = new HashSet<DbContext>();
public void Use(DbContext dbContext)
{
if (!_isOpened)
throw new ShardingTransactionException($"{nameof(ShardingTransaction)} is not open");
if (!_dbContextUseTransactions.Contains(dbContext))
{
if (!IsUsed)
_dbTransaction = dbContext.Database.BeginTransaction();
else
dbContext.Database.UseTransaction(_dbTransaction.GetDbTransaction());
_dbContextUseTransactions.Add(dbContext);
}
}
public void Open()
{
_isOpened = true;
}
private void Close()
{
_isOpened = false;
_dbContextUseTransactions.Clear();
}
public void Rollback()
{
_dbTransaction?.Rollback();
}
#if EFCORE2
public Task RollbackAsync()
{
_dbTransaction?.Rollback();
return Task.CompletedTask;
}
#endif
#if !EFCORE2
public async Task RollbackAsync()
{
if (_dbTransaction != null)
await _dbTransaction.RollbackAsync();
}
#endif
public void Commit()
{
_dbTransaction?.Commit();
}
#if EFCORE2
public Task CommitAsync()
{
_dbTransaction?.Commit();
return Task.CompletedTask;
}
#endif
#if !EFCORE2
public async Task CommitAsync()
{
if (_dbTransaction != null)
await _dbTransaction.CommitAsync();
}
#endif
public IDbContextTransaction GetDbContextTransaction()
{
return _dbTransaction;
}
public void Dispose()
{
Close();
_dbTransaction?.Dispose();
_dbTransaction = null;
}
}
}

View File

@ -1,23 +0,0 @@
using System;
using System.Data.Common;
using Microsoft.EntityFrameworkCore;
namespace ShardingCore.DbContexts.VirtualDbContexts
{
/*
* @Author: xjm
* @Description:
* @Date: Thursday, 24 December 2020 10:32:07
* @Email: 326308290@qq.com
*/
public interface IDbContextOptionsProvider
{
/// <summary>
/// 创建数据库链接配置
/// </summary>
/// <param name="dbConnection"></param>
/// <returns></returns>
DbContextOptions GetDbContextOptions(DbConnection dbConnection);
}
}

View File

@ -0,0 +1,38 @@
using Microsoft.EntityFrameworkCore;
using ShardingCore.DbContexts.Abstractions;
using ShardingCore.Helpers;
using ShardingCore.Sharding.Abstractions;
using System;
using System.Collections.Generic;
using System.Linq;
using ShardingCore.Core.VirtualRoutes.TableRoutes;
using ShardingCore.DbContexts.ShardingDbContexts;
namespace ShardingCore
{
/*
* @Author: xjm
* @Description:
* @Date: 2021/3/5 17:30:10
* @Ver: 1.0
* @Email: 326308290@qq.com
*/
public class DefaultShardingDbContextCreatorConfig<TShardingDbContext,TActualDbContext> : IShardingDbContextCreatorConfig
where TShardingDbContext : DbContext, IShardingDbContext
where TActualDbContext : DbContext, IShardingTableDbContext
{
private readonly Func<ShardingDbContextOptions, DbContext> _creator;
public DefaultShardingDbContextCreatorConfig(Type actualDbContextType)
{
ActualDbContextType = actualDbContextType;
_creator = ShardingCoreHelper.CreateActivator<TActualDbContext>();
}
public Type ShardingDbContextType => typeof(TShardingDbContext);
public Type ActualDbContextType { get; }
public DbContext Creator(ShardingDbContextOptions shardingDbContextOptions)
{
return _creator(shardingDbContextOptions);
}
}
}

View File

@ -20,8 +20,9 @@ namespace ShardingCore.EFCores
* @Ver: 1.0
* @Email: 326308290@qq.com
*/
public class ShardingModelCustomizer: ModelCustomizer
public class ShardingModelCustomizer<TShardingDbContext>: ModelCustomizer where TShardingDbContext:DbContext,IShardingDbContext
{
private Type _shardingDbContextType => typeof(TShardingDbContext);
public ShardingModelCustomizer(ModelCustomizerDependencies dependencies) : base(dependencies)
{
}
@ -36,7 +37,7 @@ namespace ShardingCore.EFCores
if (!string.IsNullOrWhiteSpace(tail))
{
var virtualTableManager = ShardingContainer.Services.GetService<IVirtualTableManager>();
var typeMap = virtualTableManager.GetAllVirtualTables().Where(o => o.GetTaleAllTails().Contains(tail)).Select(o => o.EntityType).ToHashSet();
var typeMap = virtualTableManager.GetAllVirtualTables(_shardingDbContextType).Where(o => o.GetTaleAllTails().Contains(tail)).Select(o => o.EntityType).ToHashSet();
//设置分表
var mutableEntityTypes = modelBuilder.Model.GetEntityTypes().Where(o => o.ClrType.IsShardingTable() && typeMap.Contains(o.ClrType));

View File

@ -21,6 +21,32 @@ namespace ShardingCore.Extensions
*/
public static class CommonExtension
{
/// <summary>
/// IShardingDbContext
/// </summary>
/// <param name="dbContext"></param>
/// <returns></returns>
public static bool IsShardingDbContext(this DbContext dbContext)
{
if (dbContext == null)
throw new ArgumentNullException(nameof(dbContext));
return dbContext is IShardingDbContext;
}
/// <summary>
/// IShardingDbContext
/// </summary>
/// <param name="dbContextType"></param>
/// <returns></returns>
public static bool IsShardingDbContext(this Type dbContextType)
{
if (dbContextType == null)
throw new ArgumentNullException(nameof(dbContextType));
if (!typeof(DbContext).IsAssignableFrom(dbContextType))
return false;
return typeof(IShardingDbContext).IsAssignableFrom(dbContextType);
}
/// <summary>
/// IShardingTableDbContext
/// </summary>
@ -41,6 +67,8 @@ namespace ShardingCore.Extensions
{
if (dbContextType == null)
throw new ArgumentNullException(nameof(dbContextType));
if (!typeof(DbContext).IsAssignableFrom(dbContextType))
return false;
return typeof(IShardingTableDbContext).IsAssignableFrom(dbContextType);
}
/// <summary>
@ -64,7 +92,7 @@ namespace ShardingCore.Extensions
{
if (entity == null)
throw new ArgumentNullException(nameof(entity));
return typeof(IShardingTable).IsAssignableFrom(entity.GetType());
return entity is IShardingTable;
}
// /// <summary>
// /// 虚拟表转换成对应的db配置
@ -73,7 +101,7 @@ namespace ShardingCore.Extensions
// /// <returns></returns>
// public static List<VirtualTableDbContextConfig> GetVirtualTableDbContextConfigs(this List<IVirtualTable> virtualTables)
// {
// return virtualTables.Select(o => new VirtualTableDbContextConfig(o.EntityType, o.GetOriginalTableName(), o.ShardingConfig.TailPrefix)).ToList();
// return virtualTables.Select(o => new VirtualTableDbContextConfig(o.EntityType, o.GetOriginalTableName(), o.ShardingConfigOption.TailPrefix)).ToList();
// }
/// <summary>
/// 是否是集合contains方法

View File

@ -26,9 +26,7 @@ namespace ShardingCore.Extensions
/// <returns></returns>
public static string GetShardingTableDbContextTail(this IShardingTableDbContext dbContext)
{
if (string.IsNullOrWhiteSpace(dbContext.ModelChangeKey))
throw new ShardingCoreException($"cant found ModelChangeKey in {dbContext.GetType().FullName}");
return dbContext.ModelChangeKey.Replace(ShardingTableDbContextFormat, string.Empty);
return dbContext.ModelChangeKey?.Replace(ShardingTableDbContextFormat, string.Empty)??string.Empty;
}
/// <summary>

View File

@ -6,6 +6,7 @@ using Microsoft.EntityFrameworkCore;
using ShardingCore.DbContexts.ShardingDbContexts;
using ShardingCore.Exceptions;
using ShardingCore.Extensions;
using ShardingCore.Sharding.Abstractions;
namespace ShardingCore.Helpers
{
@ -21,8 +22,10 @@ namespace ShardingCore.Helpers
public static int GetStringHashCode(string value)
{
int h = 0; // 默认值是0
if (value.Length > 0) {
for (int i = 0; i < value.Length; i++) {
if (value.Length > 0)
{
for (int i = 0; i < value.Length; i++)
{
h = 31 * h + value[i]; // val[0]*31^(n-1) + val[1]*31^(n-2) + ... + val[n-1]
}
}
@ -103,8 +106,7 @@ namespace ShardingCore.Helpers
//}
}
public static Func<ShardingDbContextOptions, DbContext> CreateActivator<TContext>() where TContext : DbContext
public static Func<ShardingDbContextOptions, DbContext> CreateActivator<TContext>() where TContext : DbContext, IShardingTableDbContext
{
var constructors
= typeof(TContext).GetTypeInfo().DeclaredConstructors
@ -147,7 +149,7 @@ namespace ShardingCore.Helpers
/// <param name="constructor"></param>
/// <param name="paramType"></param>
/// <returns></returns>
private static Func<ShardingDbContextOptions, DbContext> CreateShardingDbContextOptionsActivator<TContext>(ConstructorInfo constructor,Type paramType) where TContext : DbContext
private static Func<ShardingDbContextOptions, DbContext> CreateShardingDbContextOptionsActivator<TContext>(ConstructorInfo constructor, Type paramType) where TContext : DbContext, IShardingTableDbContext
{
var po = Expression.Parameter(paramType, "o");
var newExpression = Expression.New(constructor, po);
@ -166,7 +168,7 @@ namespace ShardingCore.Helpers
/// <param name="constructor"></param>
/// <param name="paramType"></param>
/// <returns></returns>
private static Func<ShardingDbContextOptions, DbContext> CreateDbContextOptionsGenericActivator<TContext>(ConstructorInfo constructor,Type paramType) where TContext : DbContext
private static Func<ShardingDbContextOptions, DbContext> CreateDbContextOptionsGenericActivator<TContext>(ConstructorInfo constructor, Type paramType) where TContext : DbContext, IShardingTableDbContext
{
var parameterExpression = Expression.Parameter(typeof(ShardingDbContextOptions), "o");
//o.DbContextOptions

View File

@ -1,4 +1,5 @@
using System;
using System.Threading.Tasks;
namespace ShardingCore
{

View File

@ -0,0 +1,37 @@
using System;
using System.Collections.Generic;
using System.Text;
using ShardingCore.Core.VirtualRoutes.TableRoutes;
namespace ShardingCore
{
/*
* @Author: xjm
* @Description:
* @Date: 2021/8/20 6:56:49
* @Ver: 1.0
* @Email: 326308290@qq.com
*/
public interface IShardingConfigOption
{
Type ShardingDbContextType { get;}
Type ActualDbContextType { get;}
void AddShardingTableRoute<TRoute>() where TRoute : IVirtualTableRoute;
Type GetVirtualRouteType(Type entityType);
/// <summary>
/// 如果数据库不存在就创建并且创建表除了分表的
/// </summary>
public bool EnsureCreatedWithOutShardingTable { get; set; }
/// <summary>
/// 是否需要在启动时创建分表
/// </summary>
public bool? CreateShardingTableOnStart { get; set; }
/// <summary>
/// 忽略建表时的错误
/// </summary>
public bool? IgnoreCreateTableError { get; set; }
}
}

View File

@ -1,50 +0,0 @@
using Microsoft.EntityFrameworkCore;
using ShardingCore.DbContexts.Abstractions;
using System;
using System.Collections.Generic;
using ShardingCore.Sharding.Abstractions;
namespace ShardingCore
{
/*
* @Author: xjm
* @Description:
* @Date: 2021/3/4 13:11:16
* @Ver: 1.0
* @Email: 326308290@qq.com
*/
public interface IShardingCoreOptions
{
void UseShardingDbContext<T>(
Action<ShardingDbConfigOptions> func) where T : DbContext, IShardingTableDbContext;
ShardingConfigEntry GetShardingConfig();
ISet<Type> GetVirtualRoutes();
Type GetVirtualRoute(Type entityType);
/// <summary>
/// 如果数据库不存在就创建并且创建表除了分表的
/// </summary>
bool EnsureCreatedWithOutShardingTable { get; set; }
/// <summary>
/// 是否需要在启动时创建分表
/// </summary>
bool? CreateShardingTableOnStart { get; set; }
/// <summary>
/// 添加filter过滤器
/// </summary>
/// <typeparam name="TFilter"></typeparam>
public void AddDbContextCreateFilter<TFilter>() where TFilter : class, IDbContextCreateFilter;
public List<Type> GetFilters();
bool? IgnoreCreateTableError { get; set; }
}
}

View File

@ -0,0 +1,26 @@
using Microsoft.EntityFrameworkCore;
using ShardingCore.DbContexts.Abstractions;
using System;
using System.Collections.Generic;
using ShardingCore.Core.VirtualRoutes.TableRoutes;
using ShardingCore.DbContexts.ShardingDbContexts;
using ShardingCore.Sharding.Abstractions;
namespace ShardingCore
{
/*
* @Author: xjm
* @Description:
* @Date: 2021/3/4 13:11:16
* @Ver: 1.0
* @Email: 326308290@qq.com
*/
public interface IShardingDbContextCreatorConfig
{
Type ShardingDbContextType { get; }
Type ActualDbContextType { get; }
DbContext Creator(ShardingDbContextOptions shardingDbContextOptions);
}
}

View File

@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Text;
using Microsoft.EntityFrameworkCore;
namespace ShardingCore
{
/*
* @Author: xjm
* @Description:
* @Date: 2021/8/20 11:34:55
* @Ver: 1.0
* @Email: 326308290@qq.com
*/
public interface IShardingDbContextOptionsBuilderConfig
{
Type ShardingDbContextType { get; }
DbContextOptionsBuilder UseDbContextOptionsBuilder(DbConnection dbConnection, DbContextOptionsBuilder dbContextOptionsBuilder);
}
}

View File

@ -1,6 +1,7 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@ -30,13 +31,13 @@ namespace ShardingCore.Sharding
/// 分表分库的dbcontext
/// </summary>
/// <typeparam name="T"></typeparam>
public abstract class AbstractShardingDbContext<T> : DbContext, IShardingDbContext where T : DbContext, IShardingTableDbContext
public abstract class AbstractShardingDbContext<T> : DbContext, IShardingTableDbContext<T> where T : DbContext, IShardingTableDbContext
{
private readonly string EMPTY_SHARDING_TAIL_ID = Guid.NewGuid().ToString("n");
private readonly ConcurrentDictionary<string, DbContext> _dbContextCaches = new ConcurrentDictionary<string, DbContext>();
private readonly IVirtualTableManager _virtualTableManager;
private readonly IShardingDbContextFactory _shardingDbContextFactory;
private readonly ShardingConfig<T> _shardingConfig;
private readonly IShardingDbContextOptionsBuilderConfig _shardingDbContextOptionsBuilderConfig;
private DbContextOptions<T> _dbContextOptions;
private readonly object CREATELOCK = new object();
@ -45,10 +46,13 @@ namespace ShardingCore.Sharding
{
_shardingDbContextFactory = ShardingContainer.GetService<IShardingDbContextFactory>();
_virtualTableManager = ShardingContainer.GetService<IVirtualTableManager>();
_shardingConfig = ShardingContainer.GetService<ShardingConfig<T>>();
_shardingDbContextOptionsBuilderConfig = ShardingContainer
.GetService<IEnumerable<IShardingDbContextOptionsBuilderConfig>>()
.FirstOrDefault(o => o.ShardingDbContextType == ShardingDbContextType);
}
public abstract Type ShardingDbContextType { get; }
public Type ActualDbContextType => typeof(T);
@ -64,8 +68,8 @@ namespace ShardingCore.Sharding
{
var dbContextOptionBuilder = CreateDbContextOptionBuilder();
var dbConnection = Database.GetDbConnection();
dbConnection.Open();
return _shardingConfig.ShardingDbContextOptionsCreator(dbConnection, dbContextOptionBuilder);
_shardingDbContextOptionsBuilderConfig.UseDbContextOptionsBuilder(dbConnection, dbContextOptionBuilder);
return dbContextOptionBuilder.Options;
}
private ShardingDbContextOptions CreateSameShardingDbContextOptions(string tail)
@ -87,7 +91,7 @@ namespace ShardingCore.Sharding
{
if (!_dbContextCaches.TryGetValue(tail, out var dbContext))
{
dbContext = _shardingDbContextFactory.Create(CreateSameShardingDbContextOptions(tail == EMPTY_SHARDING_TAIL_ID ? string.Empty : tail));
dbContext = _shardingDbContextFactory.Create(ShardingDbContextType,CreateSameShardingDbContextOptions(tail == EMPTY_SHARDING_TAIL_ID ? string.Empty : tail));
_dbContextCaches.TryAdd(tail, dbContext);
}
@ -101,13 +105,25 @@ namespace ShardingCore.Sharding
var tail = EMPTY_SHARDING_TAIL_ID;
if (entity.IsShardingTable())
{
var physicTable = _virtualTableManager.GetVirtualTable(entity.GetType()).RouteTo(new TableRouteConfig(null, entity as IShardingTable, null))[0];
var physicTable = _virtualTableManager.GetVirtualTable(ShardingDbContextType,entity.GetType()).RouteTo(new TableRouteConfig(null, entity as IShardingTable, null))[0];
tail = physicTable.Tail;
}
return GetDbContext(true, tail);
}
public bool TryOpen()
{
var dbConnection = Database.GetDbConnection();
if (dbConnection.State != ConnectionState.Open)
{
dbConnection.Open();
return true;
}
return false;
}
public override EntityEntry Add(object entity)
{
return CreateGenericDbContext(entity).Add(entity);
@ -380,13 +396,15 @@ namespace ShardingCore.Sharding
finally
{
if (!isBeginTransaction)
{
Database.CurrentTransaction?.Dispose();
foreach (var dbContextCache in _dbContextCaches)
{
dbContextCache.Value.Database.UseTransaction(null);
}
}
}
return i;
}
@ -415,13 +433,14 @@ namespace ShardingCore.Sharding
finally
{
if (!isBeginTransaction)
{
Database.CurrentTransaction?.Dispose();
foreach (var dbContextCache in _dbContextCaches)
{
dbContextCache.Value.Database.UseTransaction(null);
}
}
}
return i;
}
@ -451,13 +470,15 @@ namespace ShardingCore.Sharding
{
if (!isBeginTransaction) { }
if (Database.CurrentTransaction != null)
{
await Database.CurrentTransaction.DisposeAsync();
foreach (var dbContextCache in _dbContextCaches)
{
await dbContextCache.Value.Database.UseTransactionAsync(null, cancellationToken: cancellationToken);
}
}
}
return i;
}
@ -487,6 +508,7 @@ namespace ShardingCore.Sharding
{
if (!isBeginTransaction)
if (Database.CurrentTransaction != null)
{
await Database.CurrentTransaction.DisposeAsync();
foreach (var dbContextCache in _dbContextCaches)
@ -494,6 +516,8 @@ namespace ShardingCore.Sharding
await dbContextCache.Value.Database.UseTransactionAsync(null, cancellationToken: cancellationToken);
}
}
}
return i;
}

View File

@ -13,6 +13,7 @@ namespace ShardingCore.Sharding.Abstractions
*/
public interface IShardingDbContext
{
Type ShardingDbContextType { get; }
/// <summary>
/// 真实的DbContext 类型
/// </summary>
@ -20,7 +21,7 @@ namespace ShardingCore.Sharding.Abstractions
/// <summary>
/// 创建DbContext
/// </summary>
/// <param name="track"></param>
/// <param name="track">true表示创建的dbcontext挂在当前的shardingdbcontext下无需管理生命周期false需要手动释放true not care dbcontext life, false need call dispose()</param>
/// <param name="tail"></param>
/// <returns></returns>
DbContext GetDbContext(bool track,string tail);
@ -33,5 +34,12 @@ namespace ShardingCore.Sharding.Abstractions
DbContext CreateGenericDbContext<T>(T entity) where T : class;
bool TryOpen();
}
public interface IShardingTableDbContext<T> : IShardingDbContext where T : DbContext, IShardingTableDbContext
{
}
}

View File

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.EntityFrameworkCore;
namespace ShardingCore.Sharding.Abstractions
{

View File

@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Text;
using Microsoft.EntityFrameworkCore;
using ShardingCore.Sharding.Abstractions;
namespace ShardingCore.Sharding
{
/*
* @Author: xjm
* @Description:
* @Date: 2021/8/19 20:57:52
* @Ver: 1.0
* @Email: 326308290@qq.com
*/
public class ShardingDbContextOptionsBuilderConfig<TShardingDbContext> : IShardingDbContextOptionsBuilderConfig where TShardingDbContext : DbContext, IShardingDbContext
{
public ShardingDbContextOptionsBuilderConfig(Action<DbConnection, DbContextOptionsBuilder> shardingDbContextOptionsCreator)
{
ShardingDbContextOptionsCreator = shardingDbContextOptionsCreator;
}
public Action<DbConnection, DbContextOptionsBuilder> ShardingDbContextOptionsCreator { get; }
public Type ShardingDbContextType => typeof(TShardingDbContext);
public DbContextOptionsBuilder UseDbContextOptionsBuilder(DbConnection dbConnection, DbContextOptionsBuilder dbContextOptionsBuilder)
{
ShardingDbContextOptionsCreator(dbConnection, dbContextOptionsBuilder);
dbContextOptionsBuilder.UseInnerDbContextSharding<TShardingDbContext>();
return dbContextOptionsBuilder;
}
}
}

View File

@ -1,14 +1,12 @@
using System.Collections.Generic;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using ShardingCore.Core.Internal.StreamMerge.ReWrite;
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.TableRoutes.RoutingRuleEngine;
using ShardingCore.DbContexts;
using ShardingCore.Sharding.Abstractions;
using System.Collections.Generic;
using System.Linq;
namespace ShardingCore.Sharding
@ -21,7 +19,6 @@ namespace ShardingCore.Sharding
*/
public class StreamMergeContext<T>
{
private readonly IShardingParallelDbContextFactory _shardingParallelDbContextFactory;
//private readonly IShardingScopeFactory _shardingScopeFactory;
private readonly IQueryable<T> _source;
private readonly IShardingDbContext _shardingDbContext;
@ -37,10 +34,8 @@ namespace ShardingCore.Sharding
public SelectContext SelectContext { get;}
public GroupByContext GroupByContext { get; }
public StreamMergeContext(IQueryable<T> source,IShardingDbContext shardingDbContext,IRoutingRuleEngineFactory tableRoutingRuleEngineFactory,
IShardingParallelDbContextFactory shardingParallelDbContextFactory,IShardingScopeFactory shardingScopeFactory)
public StreamMergeContext(IQueryable<T> source,IShardingDbContext shardingDbContext,IRoutingRuleEngineFactory tableRoutingRuleEngineFactory)
{
_shardingParallelDbContextFactory = shardingParallelDbContextFactory;
//_shardingScopeFactory = shardingScopeFactory;
_source = source;
_shardingDbContext = shardingDbContext;
@ -69,13 +64,17 @@ namespace ShardingCore.Sharding
// _reWriteSource = reWriteResult.ReWriteQueryable;
//}
public bool TryOpen()
{
return _shardingDbContext.TryOpen();
}
public DbContext CreateDbContext(string tail)
{
return _shardingDbContext.GetDbContext(true,tail);
}
public IEnumerable<RouteResult> GetRouteResults()
{
return _tableRoutingRuleEngineFactory.Route(_source);
return _tableRoutingRuleEngineFactory.Route(_shardingDbContext.GetType(),_source);
}
//public ShardingScope CreateScope()

View File

@ -1,8 +1,6 @@
using System.Linq;
using ShardingCore.Core.ShardingAccessors;
using ShardingCore.Core.VirtualRoutes.TableRoutes.RoutingRuleEngine;
using ShardingCore.DbContexts;
using ShardingCore.Sharding.Abstractions;
using System.Linq;
namespace ShardingCore.Sharding
{
@ -14,21 +12,16 @@ namespace ShardingCore.Sharding
*/
public class StreamMergeContextFactory:IStreamMergeContextFactory
{
private readonly IShardingParallelDbContextFactory _shardingParallelDbContextFactory;
private readonly IShardingScopeFactory _shardingScopeFactory;
private readonly IRoutingRuleEngineFactory _routingRuleEngineFactory;
public StreamMergeContextFactory(IShardingParallelDbContextFactory shardingParallelDbContextFactory,
IShardingScopeFactory shardingScopeFactory,
public StreamMergeContextFactory(
IRoutingRuleEngineFactory routingRuleEngineFactory)
{
_shardingParallelDbContextFactory = shardingParallelDbContextFactory;
_shardingScopeFactory = shardingScopeFactory;
_routingRuleEngineFactory = routingRuleEngineFactory;
}
public StreamMergeContext<T> Create<T>(IQueryable<T> queryable,IShardingDbContext shardingDbContext)
{
return new StreamMergeContext<T>(queryable,shardingDbContext, _routingRuleEngineFactory, _shardingParallelDbContextFactory, _shardingScopeFactory);
return new StreamMergeContext<T>(queryable,shardingDbContext, _routingRuleEngineFactory);
}
}
}

View File

@ -46,6 +46,7 @@ namespace ShardingCore.Sharding.StreamMergeEngines.Abstractions
}
_mergeContext = ShardingContainer.GetService<IStreamMergeContextFactory>().Create(_queryable, shardingDbContext);
_mergeContext.TryOpen();
}
protected abstract IQueryable<TEntity> ProcessSecondExpression(IQueryable<TEntity> queryable, Expression secondExpression);

View File

@ -3,6 +3,7 @@ using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
@ -12,6 +13,7 @@ using ShardingCore.Core.VirtualTables;
using ShardingCore.DbContexts;
using ShardingCore.DbContexts.Abstractions;
using ShardingCore.Extensions;
using ShardingCore.Sharding.Abstractions;
using ShardingCore.TableCreator;
namespace ShardingCore
@ -25,53 +27,42 @@ namespace ShardingCore
public class ShardingBootstrapper : IShardingBootstrapper
{
private readonly IServiceProvider _serviceProvider;
private readonly IShardingCoreOptions _shardingCoreOptions;
private readonly IEnumerable<IShardingConfigOption> _shardingConfigOptions;
private readonly IVirtualTableManager _virtualTableManager;
private readonly IShardingTableCreator _tableCreator;
private readonly ILogger<ShardingBootstrapper> _logger;
private readonly IShardingDbContextFactory _shardingDbContextFactory;
private readonly IDbContextCreateFilterManager _dbContextCreateFilterManager;
public ShardingBootstrapper(IServiceProvider serviceProvider, IShardingCoreOptions shardingCoreOptions,
public ShardingBootstrapper(IServiceProvider serviceProvider, IEnumerable<IShardingConfigOption> shardingConfigOptions,
IVirtualTableManager virtualTableManager
, IShardingTableCreator tableCreator, ILogger<ShardingBootstrapper> logger,
IShardingDbContextFactory shardingDbContextFactory,IDbContextCreateFilterManager dbContextCreateFilterManager)
IShardingDbContextFactory shardingDbContextFactory)
{
ShardingContainer.SetServices(serviceProvider);
_serviceProvider = serviceProvider;
_shardingCoreOptions = shardingCoreOptions;
_shardingConfigOptions = shardingConfigOptions;
_virtualTableManager = virtualTableManager;
_tableCreator = tableCreator;
_logger = logger;
_shardingDbContextFactory = shardingDbContextFactory;
_dbContextCreateFilterManager = dbContextCreateFilterManager;
}
public void Start()
{
foreach (var filter in _shardingCoreOptions.GetFilters())
using (var scope = _serviceProvider.CreateScope())
{
_dbContextCreateFilterManager.RegisterFilter((IDbContextCreateFilter)Activator.CreateInstance(filter));
}
var shardingConfig= _shardingCoreOptions.GetShardingConfig();
using var scope = _serviceProvider.CreateScope();
using var context =(DbContext)scope.ServiceProvider.GetService(shardingConfig.DbContextType);
#if EFCORE5
shardingConfig.ConnectionString = context.Database.GetConnectionString();
#endif
#if !EFCORE5
shardingConfig.ConnectionString = context.Database.GetDbConnection().ConnectionString;
#endif
foreach (var shardingConfigOption in _shardingConfigOptions)
{
using var context =
(DbContext) scope.ServiceProvider.GetService(shardingConfigOption.ShardingDbContextType);
EnsureCreated(context);
foreach (var entity in context.Model.GetEntityTypes())
{
if (entity.ClrType.IsShardingTable())
{
var routeType = shardingConfig.DbConfigOptions.GetVirtualRoute(entity.ClrType);
var routeType = shardingConfigOption.GetVirtualRouteType(entity.ClrType);
var virtualRoute = CreateVirtualRoute(routeType);
var virtualTable = CreateVirtualTable(entity.ClrType, virtualRoute);
@ -83,8 +74,11 @@ namespace ShardingCore
var tableName = context.Model.FindEntityType(virtualTable.EntityType).Relational().TableName;
#endif
virtualTable.SetOriginalTableName(tableName);
_virtualTableManager.AddVirtualTable(virtualTable);
CreateDataTable(virtualTable);
_virtualTableManager.AddVirtualTable(shardingConfigOption.ShardingDbContextType,virtualTable);
CreateDataTable(shardingConfigOption.ShardingDbContextType,virtualTable, shardingConfigOption);
}
}
}
}
}
@ -126,48 +120,49 @@ namespace ShardingCore
private void EnsureCreated(DbContext context)
{
if (_shardingCoreOptions.EnsureCreatedWithOutShardingTable)
if (context is IShardingDbContext shardingDbContext)
{
var modelCacheSyncObject = context.GetModelCacheSyncObject();
var dbContext = shardingDbContext.GetDbContext(true,string.Empty);
var modelCacheSyncObject = dbContext.GetModelCacheSyncObject();
lock (modelCacheSyncObject)
{
context.RemoveDbContextRelationModelThatIsShardingTable();
context.Database.EnsureCreated();
context.RemoveModelCache();
dbContext.RemoveDbContextRelationModelThatIsShardingTable();
dbContext.Database.EnsureCreated();
dbContext.RemoveModelCache();
}
}
}
private bool NeedCreateTable(ShardingTableConfig config)
private bool NeedCreateTable(ShardingTableConfig config, IShardingConfigOption shardingConfigOption)
{
if (config.AutoCreateTable.HasValue)
{
return config.AutoCreateTable.Value;
}
return _shardingCoreOptions.CreateShardingTableOnStart.GetValueOrDefault();
return shardingConfigOption.CreateShardingTableOnStart.GetValueOrDefault();
}
private void CreateDataTable(IVirtualTable virtualTable)
private void CreateDataTable(Type shardingDbContextType,IVirtualTable virtualTable,IShardingConfigOption shardingConfigOption)
{
var shardingConfig = virtualTable.ShardingConfig;
foreach (var tail in virtualTable.GetVirtualRoute().GetAllTails())
{
if (NeedCreateTable(shardingConfig))
if (NeedCreateTable(shardingConfig, shardingConfigOption))
{
try
{
//添加物理表
virtualTable.AddPhysicTable(new DefaultPhysicTable(virtualTable, tail));
_tableCreator.CreateTable(virtualTable.EntityType, tail);
_tableCreator.CreateTable(shardingDbContextType,virtualTable.EntityType, tail);
}
catch (Exception)
catch (Exception e)
{
if (!_shardingCoreOptions.IgnoreCreateTableError.GetValueOrDefault())
if (!shardingConfigOption.IgnoreCreateTableError.GetValueOrDefault())
{
_logger.LogWarning(
$"table :{virtualTable.GetOriginalTableName()}{shardingConfig.TailPrefix}{tail} will created");
$"table :{virtualTable.GetOriginalTableName()}{shardingConfig.TailPrefix}{tail} will created.",e);
}
}
}

View File

@ -1,26 +0,0 @@
using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Text;
using Microsoft.EntityFrameworkCore;
using ShardingCore.Sharding.Abstractions;
namespace ShardingCore
{
/*
* @Author: xjm
* @Description:
* @Date: 2021/8/16 15:18:37
* @Ver: 1.0
* @Email: 326308290@qq.com
*/
public class ShardingConfig<T> where T:DbContext,IShardingTableDbContext
{
public Func<DbConnection, DbContextOptionsBuilder<T>, DbContextOptions<T>> ShardingDbContextOptionsCreator { get; private set; }
public void UseShardingDbContextOptions(Func<DbConnection, DbContextOptionsBuilder<T>, DbContextOptions<T>> shardingDbContextOptions)
{
ShardingDbContextOptionsCreator = shardingDbContextOptions ?? throw new ArgumentNullException(nameof(shardingDbContextOptions));
}
}
}

View File

@ -0,0 +1,83 @@
using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Linq;
using System.Text;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using ShardingCore.Core.VirtualRoutes.TableRoutes;
using ShardingCore.EFCores;
using ShardingCore.Sharding;
using ShardingCore.Sharding.Abstractions;
namespace ShardingCore
{
/*
* @Author: xjm
* @Description:
* @Date: 2021/8/16 15:18:37
* @Ver: 1.0
* @Email: 326308290@qq.com
*/
public class ShardingConfigOption<TShardingDbContext, TActualDbContext> : IShardingConfigOption
where TActualDbContext : DbContext, IShardingTableDbContext
where TShardingDbContext : DbContext, IShardingTableDbContext<TActualDbContext>
{
private readonly Dictionary<Type, Type> _virtualRoutes = new Dictionary<Type, Type>();
public Action<DbConnection, DbContextOptionsBuilder> ShardingDbContextOptionsCreator { get; set; }
public void UseShardingDbContextOptions(Action<DbConnection, DbContextOptionsBuilder> shardingDbContextOptionsCreator)
{
ShardingDbContextOptionsCreator = shardingDbContextOptionsCreator ?? throw new ArgumentNullException(nameof(shardingDbContextOptionsCreator));
}
public Type ShardingDbContextType => typeof(TShardingDbContext);
public Type ActualDbContextType => typeof(TActualDbContext);
/// <summary>
/// 添加分表路由
/// </summary>
/// <typeparam name="TRoute"></typeparam>
public void AddShardingTableRoute<TRoute>() where TRoute : IVirtualTableRoute
{
var routeType = typeof(TRoute);
//获取类型
var genericVirtualRoute = routeType.GetInterfaces().FirstOrDefault(it => it.IsInterface && it.IsGenericType && it.GetGenericTypeDefinition() == typeof(IVirtualTableRoute<>)
&& it.GetGenericArguments().Any());
if (genericVirtualRoute == null)
throw new ArgumentException("add sharding route type error not assignable from IVirtualTableRoute<>.");
var shardingEntityType = genericVirtualRoute.GetGenericArguments()[0];
if (shardingEntityType == null)
throw new ArgumentException("add sharding table route type error not assignable from IVirtualTableRoute<>");
if (!_virtualRoutes.ContainsKey(shardingEntityType))
{
_virtualRoutes.Add(shardingEntityType, routeType);
}
}
public Type GetVirtualRouteType(Type entityType)
{
if (!_virtualRoutes.ContainsKey(entityType))
throw new ArgumentException($"{entityType} not found IVirtualTableRoute");
return _virtualRoutes[entityType];
}
/// <summary>
/// 如果数据库不存在就创建并且创建表除了分表的
/// </summary>
public bool EnsureCreatedWithOutShardingTable { get; set; }
/// <summary>
/// 是否需要在启动时创建分表
/// </summary>
public bool? CreateShardingTableOnStart { get; set; }
/// <summary>
/// 忽略建表时的错误
/// </summary>
public bool? IgnoreCreateTableError { get; set; }
}
}

View File

@ -29,5 +29,9 @@ namespace ShardingCore
{
return Services.GetService<T>();
}
public static object GetService(Type serviceType)
{
return Services.GetService(serviceType);
}
}
}

View File

@ -1,6 +1,8 @@
using System;
using Microsoft.EntityFrameworkCore;
using ShardingCore.Core;
using ShardingCore.Exceptions;
using ShardingCore.Sharding.Abstractions;
namespace ShardingCore.TableCreator
{
@ -20,13 +22,14 @@ namespace ShardingCore.TableCreator
/// </summary>
/// <param name="tail"></param>
/// <typeparam name="T"></typeparam>
void CreateTable<T>(string tail) where T : class, IShardingTable;
void CreateTable<TShardingDbContext,T>(string tail) where T : class, IShardingTable where TShardingDbContext:DbContext,IShardingDbContext;
/// <summary>
/// 创建表
/// </summary>
/// <param name="shardingDbContextType"></param>
/// <param name="shardingEntityType"></param>
/// <param name="tail"></param>
/// <exception cref="ShardingCreateException"></exception>
void CreateTable(Type shardingEntityType,string tail);
void CreateTable(Type shardingDbContextType,Type shardingEntityType,string tail);
}
}

View File

@ -1,5 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage;
using Microsoft.Extensions.DependencyInjection;
@ -7,10 +9,12 @@ using Microsoft.Extensions.Logging;
using ShardingCore.Core;
using ShardingCore.Core.VirtualTables;
using ShardingCore.DbContexts;
using ShardingCore.DbContexts.Abstractions;
using ShardingCore.DbContexts.ShardingDbContexts;
using ShardingCore.DbContexts.VirtualDbContexts;
using ShardingCore.Exceptions;
using ShardingCore.Extensions;
using ShardingCore.Sharding.Abstractions;
namespace ShardingCore.TableCreator
{
@ -26,50 +30,60 @@ namespace ShardingCore.TableCreator
private readonly IShardingDbContextFactory _shardingDbContextFactory;
private readonly IVirtualTableManager _virtualTableManager;
private readonly IServiceProvider _serviceProvider;
private readonly IShardingCoreOptions _shardingCoreOptions;
private readonly IEnumerable<IShardingConfigOption> _shardingConfigOptions;
public ShardingTableCreator(ILogger<ShardingTableCreator> logger, IShardingDbContextFactory shardingDbContextFactory,
IVirtualTableManager virtualTableManager, IServiceProvider serviceProvider,IShardingCoreOptions shardingCoreOptions)
IVirtualTableManager virtualTableManager, IServiceProvider serviceProvider, IEnumerable<IShardingConfigOption> shardingConfigOptions)
{
_logger = logger;
_shardingDbContextFactory = shardingDbContextFactory;
_virtualTableManager = virtualTableManager;
_serviceProvider = serviceProvider;
_shardingCoreOptions = shardingCoreOptions;
_shardingConfigOptions = shardingConfigOptions;
}
public void CreateTable<T>(string tail) where T : class, IShardingTable
public void CreateTable<TShardingDbContext, T>(string tail) where TShardingDbContext : DbContext, IShardingDbContext where T : class, IShardingTable
{
CreateTable(typeof(T), tail);
CreateTable(typeof(TShardingDbContext),typeof(T), tail);
}
/// <summary>
///
/// </summary>
/// <param name="shardingDbContextType"></param>
/// <param name="shardingEntityType"></param>
/// <param name="tail"></param>
/// <exception cref="ShardingCreateException"></exception>
public void CreateTable(Type shardingEntityType, string tail)
public void CreateTable(Type shardingDbContextType,Type shardingEntityType, string tail)
{
if (!shardingDbContextType.IsShardingDbContext())
throw new ShardingCoreException(
$"{shardingDbContextType.FullName} must impl {nameof(IShardingDbContext)}");
var shardingConfigOptions = _shardingConfigOptions.FirstOrDefault(o => o.ShardingDbContextType == shardingDbContextType);
if (shardingConfigOptions == null)
throw new ShardingCoreException(
"not found sharding config options db context is {shardingDbContextType.FullName}");
using (var serviceScope = _serviceProvider.CreateScope())
{
var dbContextOptionsProvider = serviceScope.ServiceProvider.GetService<IDbContextOptionsProvider>();
var virtualTable = _virtualTableManager.GetVirtualTable(shardingEntityType);
var virtualTable = _virtualTableManager.GetVirtualTable(shardingDbContextType, shardingEntityType);
var dbContext = (DbContext)serviceScope.ServiceProvider.GetService(shardingDbContextType);
var shardingDbContext = (IShardingDbContext)dbContext;
var context = shardingDbContext.GetDbContext(true,tail);
using (var dbContext = _shardingDbContextFactory.Create(new ShardingDbContextOptions(dbContextOptionsProvider.GetDbContextOptions(null), tail)))
{
var modelCacheSyncObject = dbContext.GetModelCacheSyncObject();
var modelCacheSyncObject = context.GetModelCacheSyncObject();
lock (modelCacheSyncObject)
{
dbContext.RemoveDbContextRelationModelSaveOnlyThatIsNamedType(shardingEntityType);
var databaseCreator = dbContext.Database.GetService<IDatabaseCreator>() as RelationalDatabaseCreator;
context.RemoveDbContextRelationModelSaveOnlyThatIsNamedType(shardingEntityType);
var databaseCreator = context.Database.GetService<IDatabaseCreator>() as RelationalDatabaseCreator;
try
{
databaseCreator.CreateTables();
}
catch (Exception ex)
{
if (!_shardingCoreOptions.IgnoreCreateTableError.GetValueOrDefault())
if (!shardingConfigOptions.IgnoreCreateTableError.GetValueOrDefault())
{
_logger.LogWarning(
$"create table error maybe table:[{virtualTable.GetOriginalTableName()}{virtualTable.ShardingConfig.TailPrefix}{tail}]");
@ -78,7 +92,7 @@ namespace ShardingCore.TableCreator
}
finally
{
dbContext.RemoveModelCache();
context.RemoveModelCache();
}
}
@ -86,4 +100,3 @@ namespace ShardingCore.TableCreator
}
}
}
}

View File

@ -7,6 +7,7 @@
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.TestHost" Version="5.0.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="5.0.9" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="Xunit.DependencyInjection" Version="7.1.0" />
@ -22,5 +23,8 @@
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\ShardingCore\ShardingCore.csproj" />
</ItemGroup>
</Project>

View File

@ -28,5 +28,7 @@ namespace ShardingCore.Test50
modelBuilder.ApplyConfiguration(new SysUserModMap());
modelBuilder.ApplyConfiguration(new SysUserSalaryMap());
}
public override Type ShardingDbContextType => this.GetType();
}
}

View File

@ -1,17 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using ShardingCore.DbContexts.VirtualDbContexts;
using ShardingCore.Extensions;
using ShardingCore.Sharding;
using ShardingCore.SqlServer;
using ShardingCore.Test50.Domain.Entities;
using ShardingCore.Test50.Shardings;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
#if EFCORE5SQLSERVER
using ShardingCore.SqlServer;
@ -30,6 +27,10 @@ namespace ShardingCore.Test50
*/
public class Startup
{
public static readonly ILoggerFactory efLogger = LoggerFactory.Create(builder =>
{
builder.AddFilter((category, level) => category == DbLoggerCategory.Database.Command.Name && level == LogLevel.Information).AddConsole();
});
// // 自定义 host 构建
public void ConfigureHost(IHostBuilder hostBuilder)
{
@ -47,33 +48,18 @@ namespace ShardingCore.Test50
public void ConfigureServices(IServiceCollection services, HostBuilderContext hostBuilderContext)
{
services.AddShardingSqlServer(o =>
{
o.EnsureCreatedWithOutShardingTable = false;
o.CreateShardingTableOnStart = false;
o.UseShardingDbContext<DefaultDbContext>( dbConfig =>
{
dbConfig.AddShardingTableRoute<SysUserModVirtualTableRoute>();
dbConfig.AddShardingTableRoute<SysUserSalaryVirtualTableRoute>();
});
//o.AddDataSourceVirtualRoute<>();
});
//services.AddShardingSqlServer(o =>
//{
// o.ConnectionString = hostBuilderContext.Configuration.GetSection("SqlServer")["ConnectionString"];
// o.AddSharding<SysUserModVirtualTableRoute>();
// o.AddSharding<SysUserSalaryVirtualTableRoute>();
// o.UseShardingCoreConfig((provider, config) =>
// {
// config.EnsureCreated = true;
// config.CreateShardingTableOnStart = true;
// });
//});
services.AddDbContext<DefaultDbContext>(o =>
o.UseSqlServer(hostBuilderContext.Configuration.GetSection("SqlServer")["ConnectionString"]));
services.AddDbContext<ShardingDefaultDbContext>(o=>
o.UseSqlServer(hostBuilderContext.Configuration.GetSection("SqlServer")["ConnectionString"]).UseSharding());
services.AddShardingDbContext<ShardingDefaultDbContext, DefaultDbContext>(o =>
o.UseSqlServer(hostBuilderContext.Configuration.GetSection("SqlServer")["ConnectionString"]), op =>
{
op.EnsureCreatedWithOutShardingTable = true;
op.CreateShardingTableOnStart = true;
op.UseShardingDbContextOptions((connection, builder) => builder.UseSqlServer(connection).UseLoggerFactory(efLogger));
op.AddShardingTableRoute<SysUserModVirtualTableRoute>();
op.AddShardingTableRoute<SysUserSalaryVirtualTableRoute>();
});
}
// 可以添加要用到的方法参数,会自动从注册的服务中获取服务实例,类似于 asp.net core 里 Configure 方法