虽然不能编译但是我还是要提交
This commit is contained in:
parent
817fa249aa
commit
9530e1bb85
|
@ -0,0 +1,16 @@
|
|||
using System;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace ShardingCore.Core.DataSourceAccessors
|
||||
{
|
||||
/*
|
||||
* @Author: xjm
|
||||
* @Description:
|
||||
* @Date: Thursday, 25 February 2021 20:19:44
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
public interface IDataSourceAccessor
|
||||
{
|
||||
DbContext CreateDbContext();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
using System;
|
||||
|
||||
namespace ShardingCore.Core
|
||||
{
|
||||
/*
|
||||
* @Author: xjm
|
||||
* @Description:
|
||||
* @Date: Friday, 05 February 2021 12:52:55
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
/// <summary>
|
||||
/// 分库接口
|
||||
/// </summary>
|
||||
public interface IShardingDataSource
|
||||
{
|
||||
|
||||
}
|
||||
}
|
|
@ -29,6 +29,7 @@ namespace ShardingCore.Core.Internal.RoutingRuleEngines
|
|||
public IEnumerable<RouteResult> Route<T>(RouteRuleContext<T> routeRuleContext)
|
||||
{
|
||||
Dictionary<IVirtualTable, ISet<IPhysicTable>> routeMaps = new Dictionary<IVirtualTable, ISet<IPhysicTable>>();
|
||||
var queryEntities = routeRuleContext.Queryable.ParseQueryableRoute();
|
||||
//先添加手动路由到当前上下文,之后将不再手动路由里面的自动路由添加到当前上下文
|
||||
foreach (var kv in routeRuleContext.ManualTails)
|
||||
{
|
||||
|
@ -38,7 +39,8 @@ namespace ShardingCore.Core.Internal.RoutingRuleEngines
|
|||
if (!routeMaps.ContainsKey(virtualTable))
|
||||
{
|
||||
routeMaps.Add(virtualTable,physicTables.ToHashSet());
|
||||
} else
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var physicTable in physicTables)
|
||||
{
|
||||
|
@ -66,7 +68,7 @@ namespace ShardingCore.Core.Internal.RoutingRuleEngines
|
|||
|
||||
if (routeRuleContext.AutoParseRoute)
|
||||
{
|
||||
var shardingEntities = routeRuleContext.Queryable.ParseQueryableRoute();
|
||||
var shardingEntities = queryEntities.Where(o => o.IsShardingEntity());
|
||||
foreach (var shardingEntity in shardingEntities)
|
||||
{
|
||||
var virtualTable = _virtualTableManager.GetVirtualTable(shardingEntity);
|
||||
|
|
|
@ -18,8 +18,8 @@ namespace ShardingCore.Core.Internal.RoutingRuleEngines
|
|||
|
||||
public RouteRuleContext(IQueryable<T> queryable, IVirtualTableManager virtualTableManager)
|
||||
{
|
||||
_virtualTableManager = virtualTableManager;
|
||||
Queryable = queryable;
|
||||
_virtualTableManager = virtualTableManager;
|
||||
}
|
||||
|
||||
public IQueryable<T> Queryable { get; }
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace ShardingCore.Core.Internal
|
||||
{
|
||||
/*
|
||||
* @Author: xjm
|
||||
* @Description:
|
||||
* @Date: Friday, 05 February 2021 13:34:29
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
public class ShardingEntityBaseType
|
||||
{
|
||||
/// <summary>
|
||||
/// 数据源
|
||||
/// </summary>
|
||||
public Type EntityType { get; set; }
|
||||
/// <summary>
|
||||
/// 是否多数据源
|
||||
/// </summary>
|
||||
public bool IsMultiDataSourceMapping { get; set; }
|
||||
/// <summary>
|
||||
/// 是否分表
|
||||
/// </summary>
|
||||
public bool IsMultiTableMapping { get;set; }
|
||||
/// <summary>
|
||||
/// 分库字段
|
||||
/// </summary>
|
||||
public string ShardingDataSourceField { get;set; }
|
||||
/// <summary>
|
||||
/// 分表字段
|
||||
/// </summary>
|
||||
public string ShardingTableField { get; set; }
|
||||
/// <summary>
|
||||
/// 分表的原表名 original table name in db exclude tail
|
||||
/// </summary>
|
||||
public string ShardingOriginalTableName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 启动时是否建表 auto create table when start app
|
||||
/// </summary>
|
||||
public bool? AutoCreateTable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 分表尾巴后缀 table sharding tail prefix
|
||||
/// </summary>
|
||||
public string TailPrefix { get; set; } = "_";
|
||||
}
|
||||
}
|
|
@ -15,14 +15,14 @@ namespace ShardingCore.Core.Internal.Visitors
|
|||
* @Date: Monday, 28 December 2020 22:09:39
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
public class QueryableRouteDiscoverVisitor<TKey> : ExpressionVisitor
|
||||
public class QueryableRouteShardingTableDiscoverVisitor<TKey> : ExpressionVisitor
|
||||
{
|
||||
private readonly ShardingEntityConfig _shardingConfig;
|
||||
private readonly Func<object, TKey> _shardingKeyConvert;
|
||||
private readonly Func<TKey, ShardingOperatorEnum, Expression<Func<string, bool>>> _keyToTailWithFilter;
|
||||
private Expression<Func<string, bool>> _where = x => true;
|
||||
|
||||
public QueryableRouteDiscoverVisitor(ShardingEntityConfig shardingConfig, Func<object, TKey> shardingKeyConvert, Func<TKey, ShardingOperatorEnum, Expression<Func<string, bool>>> keyToTailWithFilter)
|
||||
public QueryableRouteShardingTableDiscoverVisitor(ShardingEntityConfig shardingConfig, Func<object, TKey> shardingKeyConvert, Func<TKey, ShardingOperatorEnum, Expression<Func<string, bool>>> keyToTailWithFilter)
|
||||
{
|
||||
_shardingConfig = shardingConfig;
|
||||
_shardingKeyConvert = shardingKeyConvert;
|
||||
|
|
|
@ -0,0 +1,251 @@
|
|||
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;
|
||||
|
||||
namespace ShardingCore.Core.Internal.Visitors
|
||||
{
|
||||
/*
|
||||
* @Author: xjm
|
||||
* @Description:
|
||||
* @Date: Saturday, 06 February 2021 09:38:22
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
public class QueryableRouteShardingDataSourceDiscoverVisitor<TKey> : ExpressionVisitor
|
||||
{
|
||||
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;
|
||||
|
||||
public QueryableRouteShardingDataSourceDiscoverVisitor(ShardingEntityBaseType shardingEntityBaseType, Func<object, TKey> shardingKeyConvert, Func<TKey, ShardingOperatorEnum, Expression<Func<IPhysicDataSource, bool>>> keyToDataSourceWithFilter)
|
||||
{
|
||||
_shardingEntityBaseType = shardingEntityBaseType;
|
||||
_shardingKeyConvert = shardingKeyConvert;
|
||||
_keyToDataSourceWithFilter = keyToDataSourceWithFilter;
|
||||
}
|
||||
|
||||
public Func<IPhysicDataSource, bool> GetDataSourceFilter()
|
||||
{
|
||||
return _where.Compile();
|
||||
}
|
||||
|
||||
private bool IsShardingKey(Expression expression)
|
||||
{
|
||||
return expression is MemberExpression member
|
||||
&& member.Expression.Type == _shardingEntityBaseType.EntityType
|
||||
&& member.Member.Name == _shardingEntityBaseType.ShardingDataSourceField;
|
||||
}
|
||||
/// <summary>
|
||||
/// 方法是否包含shardingKey
|
||||
/// </summary>
|
||||
/// <param name="methodCallExpression"></param>
|
||||
/// <returns></returns>
|
||||
private bool IsMethodWrapShardingKey(MethodCallExpression methodCallExpression)
|
||||
{
|
||||
if (methodCallExpression.Arguments.IsNotEmpty())
|
||||
{
|
||||
for (int i = 0; i < methodCallExpression.Arguments.Count; i++)
|
||||
{
|
||||
var isShardingKey = methodCallExpression.Arguments[i] is MemberExpression member
|
||||
&& member.Expression.Type == _shardingEntityBaseType.EntityType
|
||||
&& member.Member.Name == _shardingEntityBaseType.ShardingTableField;
|
||||
if (isShardingKey) return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
private bool IsConstantOrMember(Expression expression)
|
||||
{
|
||||
return expression is ConstantExpression
|
||||
|| (expression is MemberExpression member && (member.Expression is ConstantExpression || member.Expression is MemberExpression || member.Expression is MemberExpression));
|
||||
}
|
||||
|
||||
private object GetFieldValue(Expression expression)
|
||||
{
|
||||
if (expression is ConstantExpression)
|
||||
return (expression as ConstantExpression).Value;
|
||||
if (expression is UnaryExpression)
|
||||
{
|
||||
UnaryExpression unary = expression as UnaryExpression;
|
||||
LambdaExpression lambda = Expression.Lambda(unary.Operand);
|
||||
Delegate fn = lambda.Compile();
|
||||
return fn.DynamicInvoke(null);
|
||||
}
|
||||
|
||||
if (expression is MemberExpression member1Expression)
|
||||
{
|
||||
return Expression.Lambda(member1Expression).Compile().DynamicInvoke();
|
||||
}
|
||||
|
||||
throw new ShardingKeyGetValueException("cant get value " + expression);
|
||||
}
|
||||
|
||||
protected override Expression VisitMethodCall(MethodCallExpression node)
|
||||
{
|
||||
if (node.Method.Name == nameof(Queryable.Where))
|
||||
{
|
||||
if (node.Arguments[1] is UnaryExpression unaryExpression)
|
||||
{
|
||||
if (unaryExpression.Operand is LambdaExpression lambdaExpression)
|
||||
{
|
||||
var newWhere = Resolve(lambdaExpression);
|
||||
_where = _where.And(newWhere);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return base.VisitMethodCall(node);
|
||||
}
|
||||
|
||||
|
||||
private Expression<Func<IPhysicDataSource, bool>> Resolve(Expression expression)
|
||||
{
|
||||
if (expression is LambdaExpression)
|
||||
{
|
||||
LambdaExpression lambda = expression as LambdaExpression;
|
||||
expression = lambda.Body;
|
||||
return Resolve(expression);
|
||||
}
|
||||
|
||||
if (expression is BinaryExpression binaryExpression) //解析二元运算符
|
||||
{
|
||||
return ParseGetWhere(binaryExpression);
|
||||
}
|
||||
|
||||
if (expression is UnaryExpression) //解析一元运算符
|
||||
{
|
||||
UnaryExpression unary = expression as UnaryExpression;
|
||||
if (unary.Operand is MethodCallExpression methodCall1Expression)
|
||||
{
|
||||
// return ResolveLinqToObject(unary.Operand, false);
|
||||
return ResolveInFunc(methodCall1Expression, unary.NodeType != ExpressionType.Not);
|
||||
}
|
||||
}
|
||||
|
||||
if (expression is MethodCallExpression methodCallExpression) //解析扩展方法
|
||||
{
|
||||
return ResolveInFunc(methodCallExpression, true);
|
||||
}
|
||||
return o => true;
|
||||
}
|
||||
|
||||
private Expression<Func<IPhysicDataSource, bool>> ResolveInFunc(MethodCallExpression methodCallExpression, bool @in)
|
||||
{
|
||||
if (methodCallExpression.IsEnumerableContains(methodCallExpression.Method.Name) && IsMethodWrapShardingKey(methodCallExpression))
|
||||
{
|
||||
object arrayObject = null;
|
||||
if (methodCallExpression.Object != null)
|
||||
{
|
||||
if (methodCallExpression.Object is MemberExpression member1Expression)
|
||||
{
|
||||
arrayObject = Expression.Lambda(member1Expression).Compile().DynamicInvoke();
|
||||
}
|
||||
else if (methodCallExpression.Object is ListInitExpression member2Expression)
|
||||
{
|
||||
arrayObject = Expression.Lambda(member2Expression).Compile().DynamicInvoke();
|
||||
}
|
||||
}
|
||||
else if (methodCallExpression.Arguments[0] is MemberExpression member2Expression)
|
||||
{
|
||||
arrayObject = Expression.Lambda(member2Expression).Compile().DynamicInvoke();
|
||||
}
|
||||
else if (methodCallExpression.Arguments[0] is NewArrayExpression member3Expression)
|
||||
{
|
||||
arrayObject = Expression.Lambda(member3Expression).Compile().DynamicInvoke();
|
||||
}
|
||||
|
||||
if (arrayObject != null)
|
||||
{
|
||||
var enumerable = (IEnumerable) arrayObject;
|
||||
Expression<Func<IPhysicDataSource, bool>> contains = x => false;
|
||||
if (!@in)
|
||||
contains = x => true;
|
||||
foreach (var item in enumerable)
|
||||
{
|
||||
var keyValue = _shardingKeyConvert(item);
|
||||
var eq = _keyToDataSourceWithFilter(keyValue, @in ? ShardingOperatorEnum.Equal : ShardingOperatorEnum.NotEqual);
|
||||
if (@in)
|
||||
contains = contains.Or(eq);
|
||||
else
|
||||
contains = contains.And(eq);
|
||||
}
|
||||
|
||||
return contains;
|
||||
}
|
||||
}
|
||||
|
||||
return x => true;
|
||||
}
|
||||
|
||||
private Expression<Func<IPhysicDataSource, bool>> ParseGetWhere(BinaryExpression binaryExpression)
|
||||
{
|
||||
Expression<Func<IPhysicDataSource, bool>> left = x => true;
|
||||
Expression<Func<IPhysicDataSource, bool>> right = x => true;
|
||||
|
||||
//递归获取
|
||||
if (binaryExpression.Left is BinaryExpression)
|
||||
left = ParseGetWhere(binaryExpression.Left as BinaryExpression);
|
||||
if (binaryExpression.Left is MethodCallExpression methodCallExpression)
|
||||
left = Resolve(methodCallExpression);
|
||||
|
||||
if (binaryExpression.Left is UnaryExpression unaryExpression)
|
||||
left = Resolve(unaryExpression);
|
||||
|
||||
if (binaryExpression.Right is BinaryExpression)
|
||||
right = ParseGetWhere(binaryExpression.Right as BinaryExpression);
|
||||
|
||||
//组合
|
||||
if (binaryExpression.NodeType == ExpressionType.AndAlso)
|
||||
{
|
||||
return left.And(right);
|
||||
}
|
||||
else if (binaryExpression.NodeType == ExpressionType.OrElse)
|
||||
{
|
||||
return left.Or(right);
|
||||
}
|
||||
//单个
|
||||
else
|
||||
{
|
||||
bool paramterAtLeft;
|
||||
object value = null;
|
||||
|
||||
if (IsShardingKey(binaryExpression.Left) && IsConstantOrMember(binaryExpression.Right))
|
||||
{
|
||||
paramterAtLeft = true;
|
||||
value = GetFieldValue(binaryExpression.Right);
|
||||
}
|
||||
else if (IsConstantOrMember(binaryExpression.Left) && IsShardingKey(binaryExpression.Right))
|
||||
{
|
||||
paramterAtLeft = false;
|
||||
value = GetFieldValue(binaryExpression.Left);
|
||||
}
|
||||
else
|
||||
return x => true;
|
||||
|
||||
var op = binaryExpression.NodeType switch
|
||||
{
|
||||
ExpressionType.GreaterThan => paramterAtLeft ? ShardingOperatorEnum.GreaterThan : ShardingOperatorEnum.LessThan,
|
||||
ExpressionType.GreaterThanOrEqual => paramterAtLeft ? ShardingOperatorEnum.GreaterThanOrEqual : ShardingOperatorEnum.LessThanOrEqual,
|
||||
ExpressionType.LessThan => paramterAtLeft ? ShardingOperatorEnum.LessThan : ShardingOperatorEnum.GreaterThan,
|
||||
ExpressionType.LessThanOrEqual => paramterAtLeft ? ShardingOperatorEnum.LessThanOrEqual : ShardingOperatorEnum.GreaterThanOrEqual,
|
||||
ExpressionType.Equal => ShardingOperatorEnum.Equal,
|
||||
ExpressionType.NotEqual => ShardingOperatorEnum.NotEqual,
|
||||
_ => ShardingOperatorEnum.UnKnown
|
||||
};
|
||||
|
||||
if (value == null)
|
||||
return x => true;
|
||||
|
||||
|
||||
var keyValue = _shardingKeyConvert(value);
|
||||
return _keyToDataSourceWithFilter(keyValue, op);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,200 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq.Expressions;
|
||||
using Microsoft.EntityFrameworkCore.Query;
|
||||
using ShardingCore.Extensions;
|
||||
|
||||
namespace ShardingCore.Core.Internal.Visitors.Querys
|
||||
{
|
||||
/*
|
||||
* @Author: xjm
|
||||
* @Description:
|
||||
* @Date: Saturday, 20 February 2021 11:14:35
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
#if !EFCORE5
|
||||
/// <summary>
|
||||
/// 获取分表类型
|
||||
/// </summary>
|
||||
internal class QueryEntitiesVisitor : ExpressionVisitor
|
||||
{
|
||||
private readonly ISet<Type> _shardingEntities = new HashSet<Type>();
|
||||
|
||||
|
||||
public ISet<Type> GetQueryEntities()
|
||||
{
|
||||
return _shardingEntities;
|
||||
}
|
||||
protected override Expression VisitConstant(ConstantExpression node)
|
||||
{
|
||||
if (node.Value is IQueryable queryable)
|
||||
{
|
||||
_shardingEntities.Add(queryable.ElementType);
|
||||
}
|
||||
|
||||
return base.VisitConstant(node);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if EFCORE5
|
||||
/// <summary>
|
||||
/// 获取分表类型
|
||||
/// </summary>
|
||||
internal class QueryEntitiesVisitor : ExpressionVisitor
|
||||
{
|
||||
private readonly ISet<Type> _shardingEntities = new HashSet<Type>();
|
||||
|
||||
|
||||
public ISet<Type> GetQueryEntities()
|
||||
{
|
||||
return _shardingEntities;
|
||||
}
|
||||
|
||||
protected override Expression VisitExtension(Expression node)
|
||||
{
|
||||
if (node is QueryRootExpression queryRootExpression)
|
||||
{
|
||||
_shardingEntities.Add(queryRootExpression.EntityType.ClrType);
|
||||
}
|
||||
return base.VisitExtension(node);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
// internal class ShardingEntitiesVisitor : ExpressionVisitor
|
||||
// {
|
||||
// private readonly IVirtualTableManager _virtualTableManager;
|
||||
// private readonly ISet<Type> _shardingEntities = new HashSet<Type>();
|
||||
//
|
||||
// public ShardingEntitiesVisitor(IVirtualTableManager virtualTableManager)
|
||||
// {
|
||||
// _virtualTableManager = virtualTableManager;
|
||||
// }
|
||||
//
|
||||
// public ISet<Type> GetShardingEntities()
|
||||
// {
|
||||
// return _shardingEntities;
|
||||
// }
|
||||
//
|
||||
// private bool IsShardingKey(Expression expression, out Type shardingEntity)
|
||||
// {
|
||||
// if (expression is MemberExpression member
|
||||
// && _virtualTableManager.IsShardingKey(member.Expression.Type, member.Member.Name))
|
||||
// {
|
||||
// shardingEntity = member.Expression.Type;
|
||||
// return true;
|
||||
// }
|
||||
//
|
||||
// shardingEntity = null;
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// private bool IsMethodShardingKey(MethodCallExpression methodCallExpression, out Type shardingEntity)
|
||||
// {
|
||||
// if (methodCallExpression.Arguments.IsNotEmpty())
|
||||
// {
|
||||
// for (int i = 0; i < methodCallExpression.Arguments.Count; i++)
|
||||
// {
|
||||
// if (methodCallExpression.Arguments[i] is MemberExpression member
|
||||
// && _virtualTableManager.IsShardingKey(member.Expression.Type, member.Member.Name))
|
||||
// {
|
||||
// shardingEntity = member.Expression.Type;
|
||||
// return true;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// shardingEntity = null;
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// protected override Expression VisitMethodCall(MethodCallExpression node)
|
||||
// {
|
||||
// var methodName = node.Method.Name;
|
||||
// switch (methodName)
|
||||
// {
|
||||
// case nameof(Queryable.Where):
|
||||
// ResolveWhere(node);
|
||||
// break;
|
||||
// }
|
||||
//
|
||||
//
|
||||
// return base.VisitMethodCall(node);
|
||||
// }
|
||||
//
|
||||
// private void ResolveWhere(MethodCallExpression node)
|
||||
// {
|
||||
// if (node.Arguments[1] is UnaryExpression unaryExpression)
|
||||
// {
|
||||
// if (unaryExpression.Operand is LambdaExpression lambdaExpression)
|
||||
// {
|
||||
// Resolve(lambdaExpression);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//
|
||||
// private void Resolve(Expression expression)
|
||||
// {
|
||||
// if (expression is LambdaExpression)
|
||||
// {
|
||||
// LambdaExpression lambda = expression as LambdaExpression;
|
||||
// expression = lambda.Body;
|
||||
// Resolve(expression);
|
||||
// }
|
||||
//
|
||||
// if (expression is BinaryExpression binaryExpression) //解析二元运算符
|
||||
// {
|
||||
// ParseGetWhere(binaryExpression);
|
||||
// }
|
||||
//
|
||||
// if (expression is UnaryExpression) //解析一元运算符
|
||||
// {
|
||||
// UnaryExpression unary = expression as UnaryExpression;
|
||||
// if (unary.Operand is MethodCallExpression methodCall1Expression)
|
||||
// {
|
||||
// ResolveInFunc(methodCall1Expression, unary.NodeType != ExpressionType.Not);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if (expression is MethodCallExpression methodCallExpression) //解析扩展方法
|
||||
// {
|
||||
// ResolveInFunc(methodCallExpression, true);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private void ResolveInFunc(MethodCallExpression methodCallExpression, bool @in)
|
||||
// {
|
||||
// if (methodCallExpression.IsEnumerableContains(methodCallExpression.Method.Name) && IsMethodShardingKey(methodCallExpression, out var shardingEntity))
|
||||
// {
|
||||
// _shardingEntities.Add(shardingEntity);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private void ParseGetWhere(BinaryExpression binaryExpression)
|
||||
// {
|
||||
// //递归获取
|
||||
// if (binaryExpression.Left is BinaryExpression)
|
||||
// ParseGetWhere(binaryExpression.Left as BinaryExpression);
|
||||
// if (binaryExpression.Left is MethodCallExpression methodCallExpression)
|
||||
// {
|
||||
// Resolve(methodCallExpression);
|
||||
// }
|
||||
//
|
||||
// if (binaryExpression.Left is UnaryExpression unaryExpression)
|
||||
// Resolve(unaryExpression);
|
||||
//
|
||||
// if (binaryExpression.Right is BinaryExpression)
|
||||
// ParseGetWhere(binaryExpression.Right as BinaryExpression);
|
||||
//
|
||||
// if (IsShardingKey(binaryExpression.Left, out var shardingEntity1))
|
||||
// {
|
||||
// _shardingEntities.Add(shardingEntity1);
|
||||
// }
|
||||
// else if (IsShardingKey(binaryExpression.Right, out var shardingEntity2))
|
||||
// {
|
||||
// _shardingEntities.Add(shardingEntity2);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
|
@ -62,140 +62,4 @@ namespace ShardingCore.Core.Internal.Visitors
|
|||
}
|
||||
}
|
||||
#endif
|
||||
// internal class ShardingEntitiesVisitor : ExpressionVisitor
|
||||
// {
|
||||
// private readonly IVirtualTableManager _virtualTableManager;
|
||||
// private readonly ISet<Type> _shardingEntities = new HashSet<Type>();
|
||||
//
|
||||
// public ShardingEntitiesVisitor(IVirtualTableManager virtualTableManager)
|
||||
// {
|
||||
// _virtualTableManager = virtualTableManager;
|
||||
// }
|
||||
//
|
||||
// public ISet<Type> GetShardingEntities()
|
||||
// {
|
||||
// return _shardingEntities;
|
||||
// }
|
||||
//
|
||||
// private bool IsShardingKey(Expression expression, out Type shardingEntity)
|
||||
// {
|
||||
// if (expression is MemberExpression member
|
||||
// && _virtualTableManager.IsShardingKey(member.Expression.Type, member.Member.Name))
|
||||
// {
|
||||
// shardingEntity = member.Expression.Type;
|
||||
// return true;
|
||||
// }
|
||||
//
|
||||
// shardingEntity = null;
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// private bool IsMethodShardingKey(MethodCallExpression methodCallExpression, out Type shardingEntity)
|
||||
// {
|
||||
// if (methodCallExpression.Arguments.IsNotEmpty())
|
||||
// {
|
||||
// for (int i = 0; i < methodCallExpression.Arguments.Count; i++)
|
||||
// {
|
||||
// if (methodCallExpression.Arguments[i] is MemberExpression member
|
||||
// && _virtualTableManager.IsShardingKey(member.Expression.Type, member.Member.Name))
|
||||
// {
|
||||
// shardingEntity = member.Expression.Type;
|
||||
// return true;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// shardingEntity = null;
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// protected override Expression VisitMethodCall(MethodCallExpression node)
|
||||
// {
|
||||
// var methodName = node.Method.Name;
|
||||
// switch (methodName)
|
||||
// {
|
||||
// case nameof(Queryable.Where):
|
||||
// ResolveWhere(node);
|
||||
// break;
|
||||
// }
|
||||
//
|
||||
//
|
||||
// return base.VisitMethodCall(node);
|
||||
// }
|
||||
//
|
||||
// private void ResolveWhere(MethodCallExpression node)
|
||||
// {
|
||||
// if (node.Arguments[1] is UnaryExpression unaryExpression)
|
||||
// {
|
||||
// if (unaryExpression.Operand is LambdaExpression lambdaExpression)
|
||||
// {
|
||||
// Resolve(lambdaExpression);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//
|
||||
// private void Resolve(Expression expression)
|
||||
// {
|
||||
// if (expression is LambdaExpression)
|
||||
// {
|
||||
// LambdaExpression lambda = expression as LambdaExpression;
|
||||
// expression = lambda.Body;
|
||||
// Resolve(expression);
|
||||
// }
|
||||
//
|
||||
// if (expression is BinaryExpression binaryExpression) //解析二元运算符
|
||||
// {
|
||||
// ParseGetWhere(binaryExpression);
|
||||
// }
|
||||
//
|
||||
// if (expression is UnaryExpression) //解析一元运算符
|
||||
// {
|
||||
// UnaryExpression unary = expression as UnaryExpression;
|
||||
// if (unary.Operand is MethodCallExpression methodCall1Expression)
|
||||
// {
|
||||
// ResolveInFunc(methodCall1Expression, unary.NodeType != ExpressionType.Not);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if (expression is MethodCallExpression methodCallExpression) //解析扩展方法
|
||||
// {
|
||||
// ResolveInFunc(methodCallExpression, true);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private void ResolveInFunc(MethodCallExpression methodCallExpression, bool @in)
|
||||
// {
|
||||
// if (methodCallExpression.IsEnumerableContains(methodCallExpression.Method.Name) && IsMethodShardingKey(methodCallExpression, out var shardingEntity))
|
||||
// {
|
||||
// _shardingEntities.Add(shardingEntity);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private void ParseGetWhere(BinaryExpression binaryExpression)
|
||||
// {
|
||||
// //递归获取
|
||||
// if (binaryExpression.Left is BinaryExpression)
|
||||
// ParseGetWhere(binaryExpression.Left as BinaryExpression);
|
||||
// if (binaryExpression.Left is MethodCallExpression methodCallExpression)
|
||||
// {
|
||||
// Resolve(methodCallExpression);
|
||||
// }
|
||||
//
|
||||
// if (binaryExpression.Left is UnaryExpression unaryExpression)
|
||||
// Resolve(unaryExpression);
|
||||
//
|
||||
// if (binaryExpression.Right is BinaryExpression)
|
||||
// ParseGetWhere(binaryExpression.Right as BinaryExpression);
|
||||
//
|
||||
// if (IsShardingKey(binaryExpression.Left, out var shardingEntity1))
|
||||
// {
|
||||
// _shardingEntities.Add(shardingEntity1);
|
||||
// }
|
||||
// else if (IsShardingKey(binaryExpression.Right, out var shardingEntity2))
|
||||
// {
|
||||
// _shardingEntities.Add(shardingEntity2);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
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));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
using System;
|
||||
|
||||
namespace ShardingCore.Core
|
||||
{
|
||||
/*
|
||||
* @Author: xjm
|
||||
* @Description:用户数据库分数据源时进行判断
|
||||
* @Date: Friday, 05 February 2021 12:53:46
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
/// <summary>
|
||||
/// 数据源分库规则字段
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]
|
||||
public class ShardingDataSourceKeyAttribute
|
||||
{
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace ShardingCore.Core.ShardingDataSources
|
||||
{
|
||||
/*
|
||||
* @Author: xjm
|
||||
* @Description:
|
||||
* @Date: Thursday, 18 February 2021 17:12:22
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
/// <summary>
|
||||
/// 分库数据源管理
|
||||
/// </summary>
|
||||
public interface IShardingDataSourceManager
|
||||
{
|
||||
/// <summary>
|
||||
/// 添加对象数据源
|
||||
/// </summary>
|
||||
/// <param name="connectKey"></param>
|
||||
/// <param name="connectionString"></param>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <typeparam name="TDbContext"></typeparam>
|
||||
void AddDataSource<T, TDbContext>(string connectKey,string connectionString) where T : IShardingDataSource
|
||||
where TDbContext : DbContext;
|
||||
|
||||
/// <summary>
|
||||
/// 是否需要分数据库
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
bool IsShardingDataSource();
|
||||
|
||||
public IEnumerable<ShardingDataSourceDbEntry> FilterDataSources(ISet<Type> queryEntities);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
using System;
|
||||
|
||||
namespace ShardingCore.Core.ShardingDataSources
|
||||
{
|
||||
/*
|
||||
* @Author: xjm
|
||||
* @Description:
|
||||
* @Date: Saturday, 20 February 2021 09:13:56
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
public class ShardingDataSourceDbEntry
|
||||
{
|
||||
public ShardingDataSourceDbEntry(string connectKey, Type dbContextType, string connectionString)
|
||||
{
|
||||
ConnectKey = connectKey;
|
||||
DbContextType = dbContextType;
|
||||
ConnectionString = connectionString;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 连接标识
|
||||
/// </summary>
|
||||
public string ConnectKey { get; }
|
||||
|
||||
/// <summary>
|
||||
/// dbcontext类型
|
||||
/// </summary>
|
||||
public Type DbContextType { 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 ShardingDataSourceDbEntry))
|
||||
return false;
|
||||
|
||||
if (ReferenceEquals(this, obj))
|
||||
return true;
|
||||
|
||||
ShardingDataSourceDbEntry item = (ShardingDataSourceDbEntry) obj;
|
||||
|
||||
return item.ConnectKey == this.ConnectKey;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace ShardingCore.Core.ShardingDataSources
|
||||
{
|
||||
/*
|
||||
* @Author: xjm
|
||||
* @Description:
|
||||
* @Date: Thursday, 18 February 2021 17:13:16
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
/// <summary>
|
||||
/// 分库对象
|
||||
/// </summary>
|
||||
public class ShardingDataSourceEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="entityType"></param>
|
||||
/// <param name="dataSourceDbEntry"></param>
|
||||
public ShardingDataSourceEntry(Type entityType,ShardingDataSourceDbEntry dataSourceDbEntry)
|
||||
{
|
||||
EntityType = entityType;
|
||||
DataSourceDbEntry = dataSourceDbEntry;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 分库类型
|
||||
/// </summary>
|
||||
public Type EntityType { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 分库对应的数据库对象
|
||||
/// </summary>
|
||||
public ShardingDataSourceDbEntry DataSourceDbEntry { get; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace ShardingCore.Core.ShardingDataSources
|
||||
{
|
||||
/*
|
||||
* @Author: xjm
|
||||
* @Description:
|
||||
* @Date: Friday, 19 February 2021 08:07:27
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
public class ShardingDataSourceManager : IShardingDataSourceManager
|
||||
{
|
||||
private readonly Dictionary<Type, List<ShardingDataSourceEntry>> _entityMaps = new Dictionary<Type, List<ShardingDataSourceEntry>>();
|
||||
private readonly Dictionary<ShardingDataSourceDbEntry, List<ShardingDataSourceEntry>> _dbContextMaps = new Dictionary<ShardingDataSourceDbEntry, List<ShardingDataSourceEntry>>();
|
||||
|
||||
/// <summary>
|
||||
/// 添加数据源
|
||||
/// </summary>
|
||||
/// <param name="connectKey"></param>
|
||||
/// <param name="connectionString"></param>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <typeparam name="TDbContext"></typeparam>
|
||||
public void AddDataSource<T, TDbContext>(string connectKey, string connectionString) where T : IShardingDataSource where TDbContext : DbContext
|
||||
{
|
||||
var entityType = typeof(T);
|
||||
var dbContextType = typeof(TDbContext);
|
||||
var dataSourceDbEntry = new ShardingDataSourceDbEntry(connectKey, dbContextType, connectionString);
|
||||
if (!_entityMaps.ContainsKey(entityType))
|
||||
{
|
||||
_entityMaps.Add(dbContextType, new List<ShardingDataSourceEntry>());
|
||||
}
|
||||
|
||||
if (!_dbContextMaps.ContainsKey(dataSourceDbEntry))
|
||||
{
|
||||
_dbContextMaps.Add(dataSourceDbEntry, new List<ShardingDataSourceEntry>());
|
||||
}
|
||||
|
||||
_entityMaps[entityType].Add(new ShardingDataSourceEntry(entityType, dataSourceDbEntry));
|
||||
_dbContextMaps[dataSourceDbEntry].Add(new ShardingDataSourceEntry(entityType, dataSourceDbEntry));
|
||||
}
|
||||
|
||||
public bool IsShardingDataSource()
|
||||
{
|
||||
return _dbContextMaps.Count > 1;
|
||||
}
|
||||
|
||||
public IEnumerable<ShardingDataSourceDbEntry> FilterDataSources(ISet<Type> queryEntities)
|
||||
{
|
||||
var list = _entityMaps.Where(o => queryEntities.Contains(o.Key)).Select(o => o.Value.Select(o => o.DataSourceDbEntry).ToList()).ToList();
|
||||
if (list.Count <= 0)
|
||||
return new List<ShardingDataSourceDbEntry>(0);
|
||||
if (list.Count == 1)
|
||||
return list[0];
|
||||
return list.Aggregate((pre, next) => pre.Except(next).ToList());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
using System;
|
||||
|
||||
namespace ShardingCore.Core
|
||||
{
|
||||
/*
|
||||
* @Author: xjm
|
||||
* @Description:
|
||||
* @Date: Friday, 05 February 2021 13:07:31
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
/// <summary>
|
||||
/// 数据源类型
|
||||
/// </summary>
|
||||
public enum DataSourceEnum
|
||||
{
|
||||
/// <summary>
|
||||
/// SqlServer 1
|
||||
/// </summary>
|
||||
SqlServer = 1,
|
||||
|
||||
/// <summary>
|
||||
/// MySql 2
|
||||
/// </summary>
|
||||
MySql = 1 << 1
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using ShardingCore.Core.PhysicDataSources;
|
||||
using ShardingCore.Core.PhysicTables;
|
||||
using ShardingCore.Core.VirtualRoutes;
|
||||
using ShardingCore.Core.VirtualRoutes.DataSourceRoutes;
|
||||
|
||||
namespace ShardingCore.Core.VirtualDataSources
|
||||
{
|
||||
/*
|
||||
* @Author: xjm
|
||||
* @Description:
|
||||
* @Date: Friday, 05 February 2021 13:01:39
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
/// <summary>
|
||||
/// 虚拟数据源 连接所有的实际数据源
|
||||
/// </summary>
|
||||
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);
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前数据源的路由
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
IVirtualDataSourceRoute GetRoute();
|
||||
}
|
||||
public interface IVirtualDataSource<T> : IVirtualDataSource where T : class, IShardingDataSource
|
||||
{
|
||||
new IVirtualDataSourceRoute<T> GetRoute();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using ShardingCore.Core.PhysicDataSources;
|
||||
|
||||
namespace ShardingCore.Core.VirtualDataSources
|
||||
{
|
||||
/*
|
||||
* @Author: xjm
|
||||
* @Description:
|
||||
* @Date: Saturday, 06 February 2021 14:24:01
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
public interface IVirtualDataSourceManager
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取所有的虚拟连接 get all virtual table
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
List<IVirtualDataSource> GetAllVirtualDataSources();
|
||||
/// <summary>
|
||||
/// 获取虚拟表 get virtual table by sharding entity type
|
||||
/// </summary>
|
||||
/// <param name="shardingEntityType"></param>
|
||||
/// <returns></returns>
|
||||
IVirtualDataSource GetVirtualDataSource(Type shardingEntityType);
|
||||
/// <summary>
|
||||
/// 获取虚拟表 get virtual table by sharding entity type
|
||||
/// </summary>
|
||||
/// <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);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using ShardingCore.Core.PhysicDataSources;
|
||||
using ShardingCore.Core.VirtualRoutes.DataSourceRoutes;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using ShardingCore.Core.Internal;
|
||||
using ShardingCore.Core.PhysicTables;
|
||||
using ShardingCore.Extensions;
|
||||
using ShardingCore.Utils;
|
||||
|
||||
namespace ShardingCore.Core.VirtualDataSources
|
||||
{
|
||||
/*
|
||||
* @Author: xjm
|
||||
* @Description:
|
||||
* @Date: Friday, 05 February 2021 15:21:04
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
public class VirtualDataSource<T>:IVirtualDataSource<T> where T:class,IShardingDataSource
|
||||
{
|
||||
private readonly List<IPhysicDataSource> _physicDataSources;
|
||||
private readonly IVirtualDataSourceRoute<T> _virtualDataSourceRoute;
|
||||
public ShardingEntityBaseType ShardingEntityType { get; }
|
||||
|
||||
public Type EntityType { get; }
|
||||
|
||||
public VirtualDataSource(IServiceProvider serviceProvider)
|
||||
{
|
||||
_physicDataSources = new List<IPhysicDataSource>();
|
||||
_virtualDataSourceRoute = serviceProvider.GetService<IVirtualDataSourceRoute<T>>() ?? throw new ArgumentNullException($"{typeof(T)}");
|
||||
EntityType = typeof(T);
|
||||
ShardingEntityType = ShardingUtil.Parse(EntityType);
|
||||
}
|
||||
|
||||
public List<IPhysicDataSource> GetAllDataSources()
|
||||
{
|
||||
return _physicDataSources;
|
||||
}
|
||||
|
||||
public List<IPhysicDataSource> RouteTo(VirutalDataSourceConfig routeConfig)
|
||||
{
|
||||
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()));
|
||||
object shardingKeyValue = null;
|
||||
if (routeConfig.UseValue())
|
||||
shardingKeyValue = routeConfig.GetShardingKeyValue();
|
||||
|
||||
if (routeConfig.UseEntity())
|
||||
shardingKeyValue = routeConfig.GetShardingDataSource().GetPropertyValue(ShardingEntityType.ShardingDataSourceField);
|
||||
|
||||
if (shardingKeyValue != null)
|
||||
{
|
||||
var routeWithValue = _virtualDataSourceRoute.RouteWithValue(_physicDataSources, shardingKeyValue);
|
||||
return new List<IPhysicDataSource>(1) {routeWithValue};
|
||||
}
|
||||
|
||||
throw new NotImplementedException(nameof(VirutalDataSourceConfig));
|
||||
}
|
||||
|
||||
public void AddDataSource(IPhysicDataSource physicTable)
|
||||
{
|
||||
if (_physicDataSources.Any(o => o.GetConnectionString() == physicTable.GetConnectionString()))
|
||||
return;
|
||||
_physicDataSources.Add(physicTable);
|
||||
}
|
||||
|
||||
IVirtualDataSourceRoute<T> IVirtualDataSource<T>.GetRoute()
|
||||
{
|
||||
return _virtualDataSourceRoute;
|
||||
}
|
||||
|
||||
public IVirtualDataSourceRoute GetRoute()
|
||||
{
|
||||
return _virtualDataSourceRoute;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using ShardingCore.Core.PhysicDataSources;
|
||||
using ShardingCore.Exceptions;
|
||||
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
|
||||
{
|
||||
private readonly ConcurrentDictionary<Type, IVirtualDataSource> _virtualDataSources = new ConcurrentDictionary<Type, IVirtualDataSource>();
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
public List<IVirtualDataSource> GetAllVirtualDataSources()
|
||||
{
|
||||
return _virtualDataSources.Select(o => o.Value).ToList();
|
||||
}
|
||||
|
||||
public IVirtualDataSource GetVirtualDataSource(Type shardingEntityType)
|
||||
{
|
||||
if (!_virtualDataSources.TryGetValue(shardingEntityType, out var virtualTable) || virtualTable == null)
|
||||
throw new VirtualDataSourceNotFoundException($"{shardingEntityType}");
|
||||
return virtualTable;
|
||||
}
|
||||
|
||||
public IVirtualDataSource<T> GetVirtualDataSource<T>() where T : class, IShardingDataSource
|
||||
{
|
||||
return (IVirtualDataSource<T>)GetVirtualDataSource(typeof(T));
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace ShardingCore.Core.VirtualDataSources
|
||||
{
|
||||
/*
|
||||
* @Author: xjm
|
||||
* @Description:
|
||||
* @Date: Saturday, 06 February 2021 11:28:33
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
public class VirutalDataSourceConfig
|
||||
{
|
||||
|
||||
private readonly IQueryable _queryable;
|
||||
private readonly IShardingDataSource _shardingDataSource;
|
||||
private readonly object _shardingKeyValue;
|
||||
private readonly Expression _predicate;
|
||||
|
||||
|
||||
public VirutalDataSourceConfig(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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -20,7 +20,7 @@ namespace ShardingCore.Core.VirtualRoutes.Abstractions
|
|||
protected override List<IPhysicTable> DoRouteWithWhere(List<IPhysicTable> allPhysicTables, IQueryable queryable)
|
||||
{
|
||||
//获取所有需要路由的表后缀
|
||||
var filter = ShardingKeyUtil.GetRouteObjectOperatorFilter(queryable, ShardingKeyUtil.Parse(typeof(T)), ConvertToShardingKey, GetRouteToFilter);
|
||||
var filter = ShardingKeyUtil.GetRouteShardingTableFilter(queryable, ShardingKeyUtil.Parse(typeof(T)), ConvertToShardingKey, GetRouteToFilter);
|
||||
var physicTables = allPhysicTables.Where(o => filter(o.Tail)).ToList();
|
||||
return physicTables;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using ShardingCore.Core.PhysicDataSources;
|
||||
|
||||
namespace ShardingCore.Core.VirtualRoutes.DataSourceRoutes
|
||||
{
|
||||
/*
|
||||
* @Author: xjm
|
||||
* @Description:
|
||||
* @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 Type ShardingEntityType => typeof(T);
|
||||
public abstract IPhysicDataSource RouteWithValue(List<IPhysicDataSource> allPhysicDataSources, object shardingKey);
|
||||
|
||||
|
||||
protected abstract TKey ConvertToShardingKey(object shardingKey);
|
||||
/// <summary>
|
||||
/// 对外路由方法
|
||||
/// </summary>
|
||||
/// <param name="allPhysicDataSources"></param>
|
||||
/// <param name="queryable"></param>
|
||||
/// <returns></returns>
|
||||
public List<IPhysicDataSource> RouteWithWhere(List<IPhysicDataSource> allPhysicDataSources, IQueryable queryable)
|
||||
{
|
||||
return AfterFilter(allPhysicDataSources,DoRouteWithWhere(allPhysicDataSources,queryable));
|
||||
}
|
||||
/// <summary>
|
||||
/// 实际路由
|
||||
/// </summary>
|
||||
/// <param name="allPhysicDataSources"></param>
|
||||
/// <param name="queryable"></param>
|
||||
/// <returns></returns>
|
||||
protected abstract List<IPhysicDataSource> DoRouteWithWhere(List<IPhysicDataSource> allPhysicDataSources, 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)
|
||||
{
|
||||
return filterPhysicDataSources;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
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;
|
||||
|
||||
namespace ShardingCore.Core.VirtualRoutes.DataSourceRoutes
|
||||
{
|
||||
/*
|
||||
* @Author: xjm
|
||||
* @Description:
|
||||
* @Date: Friday, 05 February 2021 17:21:48
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
public abstract class AbstractShardingDataSourceOperatorVirtualRoute<T, TKey> : AbstractDataSourceVirtualRoute<T, TKey> where T : class, IShardingDataSource
|
||||
{
|
||||
/// <summary>
|
||||
/// 如何路由到具体表 shardingKeyValue:分表的值, 返回结果:如果返回true表示返回该表 第一个参数 tail 第二参数是否返回该物理表
|
||||
/// </summary>
|
||||
/// <param name="shardingKey">分表的值</param>
|
||||
/// <param name="shardingOperator">操作</param>
|
||||
/// <returns>如果返回true表示返回该表 第一个参数 tail 第二参数是否返回该物理表</returns>
|
||||
protected abstract Expression<Func<IPhysicDataSource, bool>> GetRouteToFilter(TKey shardingKey, ShardingOperatorEnum shardingOperator);
|
||||
/// <summary>
|
||||
/// 通过iqueryable来解析本次路由到的具体数据源
|
||||
/// </summary>
|
||||
/// <param name="allPhysicDataSources"></param>
|
||||
/// <param name="queryable"></param>
|
||||
/// <returns></returns>
|
||||
protected override List<IPhysicDataSource> DoRouteWithWhere(List<IPhysicDataSource> allPhysicDataSources, IQueryable queryable)
|
||||
{
|
||||
//获取所有需要路由的表后缀
|
||||
var filter = ShardingUtil.GetRouteDataSourceFilter(queryable, ShardingUtil.Parse(typeof(T)), ConvertToShardingKey, GetRouteToFilter);
|
||||
var physicTables = allPhysicDataSources.Where(o => filter(o)).ToList();
|
||||
return physicTables;
|
||||
}
|
||||
/// <summary>
|
||||
/// 根据具体值路由到对应的数据源
|
||||
/// </summary>
|
||||
/// <param name="allPhysicDataSources"></param>
|
||||
/// <param name="shardingKey"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="ShardingDataSourceRouteNotMatchException"></exception>
|
||||
/// <exception cref="ShardingDataSourceRouteMatchMoreException"></exception>
|
||||
public override IPhysicDataSource RouteWithValue(List<IPhysicDataSource> allPhysicDataSources, object shardingKey)
|
||||
{
|
||||
var filter = GetRouteToFilter(ConvertToShardingKey(shardingKey), ShardingOperatorEnum.Equal).Compile();
|
||||
|
||||
var physicDataSources = allPhysicDataSources.Where(o => filter(o)).ToList();
|
||||
if (physicDataSources.IsEmpty())
|
||||
{
|
||||
var shardingEntityBaseType = ShardingUtil.Parse(typeof(T));
|
||||
throw new ShardingDataSourceRouteNotMatchException($"{shardingEntityBaseType.EntityType} -> [{shardingEntityBaseType.ShardingDataSourceField}] ->【{shardingKey}】");
|
||||
}
|
||||
|
||||
if (physicDataSources.Count > 1)
|
||||
throw new ShardingDataSourceRouteMatchMoreException($"data source :{string.Join(",", physicDataSources.Select(o => $"[{o.GetDataSourceType()}]"))}");
|
||||
return physicDataSources[0];
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using ShardingCore.Core.PhysicDataSources;
|
||||
|
||||
namespace ShardingCore.Core.VirtualRoutes.DataSourceRoutes
|
||||
{
|
||||
/*
|
||||
* @Author: xjm
|
||||
* @Description:
|
||||
* @Date: Friday, 05 February 2021 13:03:58
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
public interface IVirtualDataSourceRoute
|
||||
{
|
||||
Type ShardingEntityType { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 根据查询条件路由返回物理表
|
||||
/// </summary>
|
||||
/// <param name="allPhysicDataSources"></param>
|
||||
/// <param name="queryable"></param>
|
||||
/// <returns></returns>
|
||||
List<IPhysicDataSource> RouteWithWhere(List<IPhysicDataSource> allPhysicDataSources,IQueryable queryable);
|
||||
|
||||
/// <summary>
|
||||
/// 根据值进行路由
|
||||
/// </summary>
|
||||
/// <param name="allPhysicDataSources"></param>
|
||||
/// <param name="shardingKeyValue"></param>
|
||||
/// <returns></returns>
|
||||
IPhysicDataSource RouteWithValue(List<IPhysicDataSource> allPhysicDataSources, object shardingKeyValue);
|
||||
|
||||
}
|
||||
|
||||
public interface IVirtualDataSourceRoute<T> : IVirtualDataSourceRoute where T : class, IShardingDataSource
|
||||
{
|
||||
}
|
||||
}
|
|
@ -29,7 +29,6 @@ namespace ShardingCore.Core.VirtualTables
|
|||
/// <summary>
|
||||
/// 获取虚拟表 get virtual table by sharding entity type
|
||||
/// </summary>
|
||||
/// <param name="shardingEntityType"></param>
|
||||
/// <returns></returns>
|
||||
IVirtualTable<T> GetVirtualTable<T>() where T:class,IShardingEntity;
|
||||
|
||||
|
|
|
@ -60,7 +60,7 @@ namespace ShardingCore.Core.VirtualTables
|
|||
return new List<IPhysicTable>(1) {routeWithValue};
|
||||
}
|
||||
|
||||
throw new NotImplementedException(nameof(routeConfig));
|
||||
throw new NotImplementedException(nameof(RouteConfig));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
using System;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace ShardingCore.DbContexts.Abstractions
|
||||
{
|
||||
/*
|
||||
* @Author: xjm
|
||||
* @Description:
|
||||
* @Date: Sunday, 07 February 2021 15:24:41
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
public class AbstractionShardingDbContext:DbContext
|
||||
{
|
||||
public AbstractionShardingDbContext(ShardingDbContextOptionBuilder<AbstractionShardingDbContext> optionBuilder)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
{
|
||||
base.OnModelCreating(modelBuilder);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
using System;
|
||||
|
||||
namespace ShardingCore.DbContexts.Abstractions
|
||||
{
|
||||
/*
|
||||
* @Author: xjm
|
||||
* @Description:
|
||||
* @Date: Thursday, 18 February 2021 14:29:28
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
public interface IShardingDbSource
|
||||
{
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
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>();
|
||||
}
|
||||
|
||||
public ShardingDbContextOptionBuilder UseLoggerFactory(ILoggerFactory loggerFactory)
|
||||
{
|
||||
_builder.UseLoggerFactory(loggerFactory);
|
||||
return this;
|
||||
}
|
||||
|
||||
public DbContextOptionsBuilder GetOptionsBuilder()
|
||||
{
|
||||
return _builder;
|
||||
}
|
||||
}
|
||||
public class ShardingDbContextOptionBuilder<T>:ShardingDbContextOptionBuilder where T:DbContext
|
||||
{
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
using ShardingCore.DbContexts.ShardingDbContexts;
|
||||
using ShardingCore.DbContexts.ShardingTableDbContexts;
|
||||
|
||||
namespace ShardingCore.DbContexts
|
||||
{
|
||||
|
@ -10,6 +10,6 @@ namespace ShardingCore.DbContexts
|
|||
*/
|
||||
public interface IShardingDbContextFactory
|
||||
{
|
||||
ShardingDbContext Create(ShardingDbContextOptions shardingDbContextOptions);
|
||||
ShardingTableDbContext Create(ShardingTableDbContextOptions shardingDbContextOptions);
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
using ShardingCore.DbContexts.ShardingDbContexts;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace ShardingCore.DbContexts
|
||||
{
|
||||
|
@ -10,6 +10,6 @@ namespace ShardingCore.DbContexts
|
|||
*/
|
||||
public interface IShardingParallelDbContextFactory
|
||||
{
|
||||
ShardingDbContext Create(string tail);
|
||||
DbContext Create(string tail);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
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);
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
using ShardingCore.DbContexts.ShardingDbContexts;
|
||||
using ShardingCore.DbContexts.ShardingTableDbContexts;
|
||||
|
||||
namespace ShardingCore.DbContexts
|
||||
{
|
||||
|
@ -10,7 +11,7 @@ namespace ShardingCore.DbContexts
|
|||
*/
|
||||
public class ShardingDbContextFactory:IShardingDbContextFactory
|
||||
{
|
||||
public ShardingDbContext Create(ShardingDbContextOptions shardingDbContextOptions)
|
||||
public ShardingTableDbContext Create(ShardingTableDbContextOptions shardingDbContextOptions)
|
||||
{
|
||||
return new ShardingDbContext(shardingDbContextOptions);
|
||||
}
|
||||
|
|
|
@ -1,95 +1,109 @@
|
|||
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)});
|
||||
}
|
||||
}
|
||||
|
||||
// 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.GetPropertyCommentBySummary(entityType.ClrType) ?? new Dictionary<string, string>();
|
||||
// var comments = XmlHelper.GetProperyCommentBySummary(entityType.ClrType) ?? new Dictionary<string, string>();
|
||||
// foreach (var property in entityType.GetProperties())
|
||||
// {
|
||||
// if (comments.ContainsKey(property.Name))
|
||||
|
@ -98,50 +112,36 @@ namespace ShardingCore.DbContexts.ShardingDbContexts
|
|||
// }
|
||||
// }
|
||||
// }
|
||||
// #endif
|
||||
// }
|
||||
//
|
||||
#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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// /// <summary>
|
||||
// /// 构建类型
|
||||
// /// </summary>
|
||||
// public void BuildEntityTypeConfigurationCaches()
|
||||
// {
|
||||
// if (!_entityTypeConfigurationTypeCaches.Any())
|
||||
// {
|
||||
// lock (buildEntityTypeConfigurationLock)
|
||||
// {
|
||||
// if (!_entityTypeConfigurationTypeCaches.Any())
|
||||
// {
|
||||
// var typesToRegister = AssemblyHelper.CurrentDomain.GetAssemblies().SelectMany(o => o.GetTypes())
|
||||
// .Where(type => !String.IsNullOrEmpty(type.Namespace))
|
||||
// //获取类型namespce不是空的所有接口是范型的当前范型是IEntityTypeConfiguration<>的进行fluent api 映射
|
||||
// .Where(type => !type.IsAbstract && type.GetInterfaces()
|
||||
// .Any(it => it.IsInterface && it.IsGenericType && it.GetGenericTypeDefinition() == typeof(IEntityTypeConfiguration<>)
|
||||
// && it.GetGenericArguments().Any())
|
||||
// ).ToDictionary(o => o.GetInterfaces().FirstOrDefault(it => it.IsInterface && it.IsGenericType && it.GetGenericTypeDefinition() == typeof(IEntityTypeConfiguration<>)
|
||||
// && it.GetGenericArguments().Any())
|
||||
// ?.GetGenericArguments()[0], o => o);
|
||||
// foreach (var type in typesToRegister)
|
||||
// {
|
||||
// _entityTypeConfigurationTypeCaches.TryAdd(type.Key, type.Value);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
|
@ -1,28 +1,28 @@
|
|||
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, bool removeShardingEntity=false)
|
||||
// {
|
||||
// DbContextOptions = dbContextOptions;
|
||||
// Tail = tail;
|
||||
// VirtualTableDbContextConfigs = virtualTableDbContextConfigs;
|
||||
// RemoveShardingEntity = removeShardingEntity;
|
||||
// }
|
||||
//
|
||||
// public DbContextOptions DbContextOptions { get; }
|
||||
// public string Tail { get; }
|
||||
// public List<VirtualTableDbContextConfig> VirtualTableDbContextConfigs { get; }
|
||||
// public bool RemoveShardingEntity { get;}
|
||||
// }
|
||||
// }
|
|
@ -1,34 +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; }
|
||||
// }
|
||||
// }
|
|
@ -0,0 +1,21 @@
|
|||
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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace ShardingCore.DbContexts.ShardingTableDbContexts
|
||||
{
|
||||
/*
|
||||
* @Author: xjm
|
||||
* @Description: 用于分表使用 分表比较特殊必须使用规定的dbcontext
|
||||
* @Date: Thursday, 18 February 2021 15:06:46
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public abstract class ShardingTableDbContext:DbContext
|
||||
{
|
||||
public string Tail { get; }
|
||||
public Dictionary<Type,VirtualTableDbContextConfig> VirtualTableConfigs { get; }
|
||||
public bool RemoveRemoveShardingEntity { get; }
|
||||
|
||||
public ShardingTableDbContext(ShardingTableDbContextOptions options)
|
||||
{
|
||||
Tail = options.Tail;
|
||||
VirtualTableConfigs = options.VirtualTableDbContextConfigs.ToDictionary(o=>o.ShardingEntityType,o=>o);
|
||||
RemoveRemoveShardingEntity = options.RemoveShardingEntity;
|
||||
}
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
{
|
||||
base.OnModelCreating(modelBuilder);
|
||||
OnModelCreatingAfter(modelBuilder);
|
||||
}
|
||||
|
||||
protected virtual void OnModelCreatingAfter(ModelBuilder modelBuilder)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(Tail))
|
||||
{
|
||||
var mutableEntityTypes = modelBuilder.Model.GetEntityTypes().Where(o=>VirtualTableConfigs.ContainsKey(o.ClrType));
|
||||
foreach (var entityType in mutableEntityTypes)
|
||||
{
|
||||
var virtualTableConfig = VirtualTableConfigs[entityType.ClrType];
|
||||
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}: not found original table name。");
|
||||
#if DEBUG
|
||||
Console.WriteLine($"映射表:[tableName]-->[{tableName}{tailPrefix}{Tail}]");
|
||||
#endif
|
||||
entity.ToTable($"{tableName}{tailPrefix}{Tail}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
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;}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
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; }
|
||||
}
|
||||
}
|
|
@ -8,7 +8,7 @@ using Microsoft.EntityFrameworkCore;
|
|||
using ShardingCore.Core;
|
||||
using ShardingCore.Core.VirtualRoutes;
|
||||
using ShardingCore.Core.VirtualTables;
|
||||
using ShardingCore.DbContexts.ShardingDbContexts;
|
||||
using ShardingCore.DbContexts.ShardingTableDbContexts;
|
||||
using ShardingCore.DbContexts.Transactions;
|
||||
using ShardingCore.Exceptions;
|
||||
using ShardingCore.Extensions;
|
||||
|
@ -311,7 +311,7 @@ namespace ShardingCore.DbContexts.VirtualDbContexts
|
|||
return new ShardingBatchDeleteEntry<T>(where,dbContexts);
|
||||
}
|
||||
|
||||
private ShardingDbContext CreateGenericDbContext<T>(T entity) where T : class
|
||||
private DbContext CreateGenericDbContext<T>(T entity) where T : class
|
||||
{
|
||||
var tail = EMPTY_SHARDING_TAIL_ID;
|
||||
if (entity.IsShardingEntity())
|
||||
|
@ -341,12 +341,12 @@ namespace ShardingCore.DbContexts.VirtualDbContexts
|
|||
throw new QueryableRouteNotMatchException($"{typeof(T)} -> {nameof(queryable)}");
|
||||
}
|
||||
|
||||
private ShardingDbContext GetOrCreateShardingDbContext(string tail)
|
||||
private DbContext GetOrCreateShardingDbContext(string tail)
|
||||
{
|
||||
if (!_dbContextCaches.TryGetValue(tail, out var shardingDbContext))
|
||||
{
|
||||
var virtualTableConfigs = _virtualTableManager.GetAllVirtualTables().GetVirtualTableDbContextConfigs();
|
||||
shardingDbContext = _shardingDbContextFactory.Create(new ShardingDbContextOptions(DbContextOptionsProvider.GetDbContextOptions(), tail == EMPTY_SHARDING_TAIL_ID ? string.Empty : tail, virtualTableConfigs));
|
||||
shardingDbContext = _shardingDbContextFactory.Create(new ShardingTableDbContextOptions(DbContextOptionsProvider.GetDbContextOptions(), tail == EMPTY_SHARDING_TAIL_ID ? string.Empty : tail, virtualTableConfigs));
|
||||
_dbContextCaches.TryAdd(tail, shardingDbContext);
|
||||
}
|
||||
|
||||
|
@ -355,7 +355,7 @@ namespace ShardingCore.DbContexts.VirtualDbContexts
|
|||
_dbTransaction.Use(shardingDbContext);
|
||||
}
|
||||
|
||||
return (ShardingDbContext) shardingDbContext;
|
||||
return shardingDbContext;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace ShardingCore.Exceptions
|
||||
{
|
||||
/*
|
||||
* @Author: xjm
|
||||
* @Description:
|
||||
* @Date: Saturday, 06 February 2021 09:08:49
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
public class ShardingDataSourceRouteMatchMoreException:Exception
|
||||
{
|
||||
public ShardingDataSourceRouteMatchMoreException()
|
||||
{
|
||||
}
|
||||
|
||||
protected ShardingDataSourceRouteMatchMoreException(SerializationInfo info, StreamingContext context) : base(info, context)
|
||||
{
|
||||
}
|
||||
|
||||
public ShardingDataSourceRouteMatchMoreException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public ShardingDataSourceRouteMatchMoreException(string message, Exception innerException) : base(message, innerException)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace ShardingCore.Exceptions
|
||||
{
|
||||
/*
|
||||
* @Author: xjm
|
||||
* @Description:
|
||||
* @Date: Saturday, 06 February 2021 09:07:39
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
public class ShardingDataSourceRouteNotMatchException:Exception
|
||||
{
|
||||
public ShardingDataSourceRouteNotMatchException()
|
||||
{
|
||||
}
|
||||
|
||||
protected ShardingDataSourceRouteNotMatchException(SerializationInfo info, StreamingContext context) : base(info, context)
|
||||
{
|
||||
}
|
||||
|
||||
public ShardingDataSourceRouteNotMatchException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public ShardingDataSourceRouteNotMatchException(string message, Exception innerException) : base(message, innerException)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace ShardingCore.Exceptions
|
||||
{
|
||||
/*
|
||||
* @Author: xjm
|
||||
* @Description:
|
||||
* @Date: Saturday, 06 February 2021 15:41:19
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
public class VirtualDataSourceNotFoundException:Exception
|
||||
{
|
||||
public VirtualDataSourceNotFoundException()
|
||||
{
|
||||
}
|
||||
|
||||
protected VirtualDataSourceNotFoundException(SerializationInfo info, StreamingContext context) : base(info, context)
|
||||
{
|
||||
}
|
||||
|
||||
public VirtualDataSourceNotFoundException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public VirtualDataSourceNotFoundException(string message, Exception innerException) : base(message, innerException)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
|
@ -19,7 +19,18 @@ namespace ShardingCore.Extensions
|
|||
public static class CommonExtension
|
||||
{
|
||||
/// <summary>
|
||||
/// 是否基继承至ShardingEntity
|
||||
/// 是否基继承至IShardingDataSource
|
||||
/// </summary>
|
||||
/// <param name="entityType"></param>
|
||||
/// <returns></returns>
|
||||
public static bool IsShardingDataSource(this Type entityType)
|
||||
{
|
||||
if (entityType == null)
|
||||
throw new ArgumentNullException(nameof(entityType));
|
||||
return typeof(IShardingDataSource).IsAssignableFrom(entityType);
|
||||
}
|
||||
/// <summary>
|
||||
/// 是否基继承至IShardingEntity
|
||||
/// </summary>
|
||||
/// <param name="entityType"></param>
|
||||
/// <returns></returns>
|
||||
|
@ -62,7 +73,7 @@ namespace ShardingCore.Extensions
|
|||
}
|
||||
public static ISet<Type> ParseQueryableRoute(this IQueryable queryable)
|
||||
{
|
||||
return ShardingKeyUtil.GetShardingEntitiesFilter(queryable);
|
||||
return ShardingKeyUtil.GetQueryEntitiesFilter(queryable);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,7 +6,7 @@ using Microsoft.Extensions.Logging;
|
|||
using ShardingCore.Core.PhysicTables;
|
||||
using ShardingCore.Core.VirtualTables;
|
||||
using ShardingCore.DbContexts;
|
||||
using ShardingCore.DbContexts.ShardingDbContexts;
|
||||
using ShardingCore.DbContexts.ShardingTableDbContexts;
|
||||
using ShardingCore.DbContexts.VirtualDbContexts;
|
||||
using ShardingCore.Extensions;
|
||||
using ShardingCore.TableCreator;
|
||||
|
@ -47,7 +47,7 @@ namespace ShardingCore
|
|||
var virtualTables = _virtualTableManager.GetAllVirtualTables();
|
||||
using var scope = _serviceProvider.CreateScope();
|
||||
var dbContextOptionsProvider = scope.ServiceProvider.GetService<IDbContextOptionsProvider>();
|
||||
using var context = _shardingDbContextFactory.Create(new ShardingDbContextOptions(dbContextOptionsProvider.GetDbContextOptions(), string.Empty, virtualTables.GetVirtualTableDbContextConfigs()));
|
||||
using var context = _shardingDbContextFactory.Create(new ShardingTableDbContextOptions(dbContextOptionsProvider.GetDbContextOptions(), string.Empty, virtualTables.GetVirtualTableDbContextConfigs()));
|
||||
|
||||
foreach (var virtualTable in virtualTables)
|
||||
{
|
||||
|
@ -69,7 +69,7 @@ namespace ShardingCore
|
|||
{
|
||||
using var scope = _serviceProvider.CreateScope();
|
||||
var dbContextOptionsProvider = scope.ServiceProvider.GetService<IDbContextOptionsProvider>();
|
||||
using var context = _shardingDbContextFactory.Create(new ShardingDbContextOptions(dbContextOptionsProvider.GetDbContextOptions(), string.Empty, new List<VirtualTableDbContextConfig>(), true));
|
||||
using var context = _shardingDbContextFactory.Create(new ShardingTableDbContextOptions(dbContextOptionsProvider.GetDbContextOptions(), string.Empty, new List<VirtualTableDbContextConfig>(), true));
|
||||
context.Database.EnsureCreated();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,5 +16,7 @@ namespace ShardingCore
|
|||
/// 是否需要在启动时创建分表
|
||||
/// </summary>
|
||||
public bool? CreateShardingTableOnStart { get; set; }
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -6,6 +6,7 @@ using System.Linq.Expressions;
|
|||
using System.Reflection;
|
||||
using ShardingCore.Core;
|
||||
using ShardingCore.Core.Internal.Visitors;
|
||||
using ShardingCore.Core.Internal.Visitors.Querys;
|
||||
using ShardingCore.Core.VirtualRoutes;
|
||||
using ShardingCore.Core.VirtualTables;
|
||||
|
||||
|
@ -56,9 +57,9 @@ namespace ShardingCore.Utils
|
|||
return shardingEntityConfig;
|
||||
}
|
||||
|
||||
public static Func<string, bool> GetRouteObjectOperatorFilter<TKey>(IQueryable queryable, ShardingEntityConfig shardingConfig, Func<object, TKey> shardingKeyConvert, Func<TKey, ShardingOperatorEnum, Expression<Func<string, bool>>> keyToTailExpression)
|
||||
public static Func<string, bool> GetRouteShardingTableFilter<TKey>(IQueryable queryable, ShardingEntityConfig shardingConfig, Func<object, TKey> shardingKeyConvert, Func<TKey, ShardingOperatorEnum, Expression<Func<string, bool>>> keyToTailExpression)
|
||||
{
|
||||
QueryableRouteDiscoverVisitor<TKey> visitor = new QueryableRouteDiscoverVisitor<TKey>(shardingConfig, shardingKeyConvert, keyToTailExpression);
|
||||
QueryableRouteShardingTableDiscoverVisitor<TKey> visitor = new QueryableRouteShardingTableDiscoverVisitor<TKey>(shardingConfig, shardingKeyConvert, keyToTailExpression);
|
||||
|
||||
visitor.Visit(queryable.Expression);
|
||||
|
||||
|
@ -74,6 +75,14 @@ namespace ShardingCore.Utils
|
|||
|
||||
return visitor.GetShardingEntities();
|
||||
}
|
||||
public static ISet<Type> GetQueryEntitiesFilter(IQueryable queryable)
|
||||
{
|
||||
QueryEntitiesVisitor visitor = new QueryEntitiesVisitor();
|
||||
|
||||
visitor.Visit(queryable.Expression);
|
||||
|
||||
return visitor.GetQueryEntities();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
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
|
||||
{
|
||||
/*
|
||||
* @Author: xjm
|
||||
* @Description:
|
||||
* @Date: Saturday, 06 February 2021 08:28:07
|
||||
* @Email: 326308290@qq.com
|
||||
*/
|
||||
public class ShardingUtil
|
||||
{
|
||||
private static readonly ConcurrentDictionary<Type, ShardingEntityBaseType> _caches = new ConcurrentDictionary<Type, ShardingEntityBaseType>();
|
||||
|
||||
private ShardingUtil()
|
||||
{
|
||||
}
|
||||
|
||||
public static ShardingEntityBaseType Parse(Type entityType)
|
||||
{
|
||||
if (_caches.TryGetValue(entityType, out var baseType))
|
||||
{
|
||||
return baseType;
|
||||
}
|
||||
|
||||
var isShardingDataSource = entityType.IsShardingDataSource();
|
||||
var isShardingTable = entityType.IsShardingEntity();
|
||||
baseType = new ShardingEntityBaseType()
|
||||
{
|
||||
EntityType = entityType,
|
||||
IsMultiDataSourceMapping = isShardingDataSource,
|
||||
IsMultiTableMapping = isShardingTable
|
||||
};
|
||||
|
||||
|
||||
if (!isShardingDataSource && isShardingTable)
|
||||
throw new NotSupportedException(entityType.ToString());
|
||||
|
||||
PropertyInfo[] shardingProperties = entityType.GetProperties();
|
||||
|
||||
|
||||
if (isShardingTable)
|
||||
{
|
||||
var shardingTables = shardingProperties.SelectMany(p => p.GetCustomAttributes(true).Where(o => o.GetType() == typeof(ShardingKeyAttribute))).ToList();
|
||||
if (shardingTables.Count != 1)
|
||||
throw new NotSupportedException($"{entityType} From IShardingEntity should use single attribute [ShardingKey]");
|
||||
}
|
||||
|
||||
var shardingDataSourceCount = 0;
|
||||
var shardingTableCount = 0;
|
||||
foreach (var shardingProperty in shardingProperties)
|
||||
{
|
||||
var attributes = shardingProperty.GetCustomAttributes(true);
|
||||
if (isShardingDataSource)
|
||||
{
|
||||
if (attributes.FirstOrDefault(x => x.GetType() == typeof(ShardingDataSourceKeyAttribute)) is ShardingDataSourceKeyAttribute shardingDataSourceKey)
|
||||
{
|
||||
if (shardingDataSourceCount > 1)
|
||||
throw new NotSupportedException($"{entityType} From IShardingDataSource should use single attribute [{nameof(ShardingDataSourceKeyAttribute)}]");
|
||||
|
||||
baseType.ShardingDataSourceField = shardingProperty.Name;
|
||||
shardingDataSourceCount++;
|
||||
}
|
||||
}
|
||||
|
||||
if (isShardingTable)
|
||||
{
|
||||
if (attributes.FirstOrDefault(x => x.GetType() == typeof(ShardingKeyAttribute)) is ShardingKeyAttribute shardingKey)
|
||||
{
|
||||
if (shardingTableCount > 1)
|
||||
throw new NotSupportedException($"{entityType} From IShardingEntity should use single attribute [{nameof(ShardingKeyAttribute)}]");
|
||||
|
||||
baseType.ShardingTableField = shardingProperty.Name;
|
||||
baseType.AutoCreateTable = shardingKey.AutoCreateTableOnStart == ShardingKeyAutoCreateTableEnum.UnKnown ? (bool?) null : (shardingKey.AutoCreateTableOnStart == ShardingKeyAutoCreateTableEnum.Create);
|
||||
baseType.TailPrefix = shardingKey.TailPrefix;
|
||||
shardingTableCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_caches.TryAdd(entityType, baseType);
|
||||
|
||||
return baseType;
|
||||
}
|
||||
|
||||
|
||||
public static Func<IPhysicDataSource, bool> GetRouteDataSourceFilter<TKey>(IQueryable queryable, ShardingEntityBaseType shardingEntityBaseType, Func<object, TKey> shardingKeyConvert, Func<TKey, ShardingOperatorEnum, Expression<Func<IPhysicDataSource, bool>>> keyToTailExpression)
|
||||
{
|
||||
QueryableRouteShardingDataSourceDiscoverVisitor<TKey> visitor = new QueryableRouteShardingDataSourceDiscoverVisitor<TKey>(shardingEntityBaseType, shardingKeyConvert, keyToTailExpression);
|
||||
|
||||
visitor.Visit(queryable.Expression);
|
||||
|
||||
return visitor.GetDataSourceFilter();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue