完成分库版本支持分页配置

This commit is contained in:
xuejiaming 2021-09-22 17:29:59 +08:00
parent 26f177aebb
commit ce30a09fb6
48 changed files with 980 additions and 190 deletions

View File

@ -12,7 +12,7 @@ namespace Sample.SqlServer.Shardings
public void Configure(PaginationBuilder<SysUserSalary> builder)
{
builder.PaginationSequence(o => o.Id)
.UseTailComparer(Comparer<string>.Default)
.UseRouteComparer(Comparer<string>.Default)
.UseQueryMatch(PaginationMatchEnum.Owner | PaginationMatchEnum.Named | PaginationMatchEnum.PrimaryMatch);
builder.PaginationSequence(o => o.DateOfMonth)
.UseQueryMatch(PaginationMatchEnum.Owner | PaginationMatchEnum.Named | PaginationMatchEnum.PrimaryMatch).UseAppendIfOrderNone(10);

View File

@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace ShardingCore.Core.QueryRouteManagers.Abstractions
{
/*
* @Author: xjm
* @Description:
* @Date: 2021/9/22 7:54:11
* @Ver: 1.0
* @Email: 326308290@qq.com
*/
/// <summary>
/// 路由断言
/// </summary>
public interface IDataSourceRouteAssert
{
/// <summary>
/// 断言路由结果
/// </summary>
/// <param name="allDataSources">所有的路由数据源</param>
/// <param name="resultDataSources">本次查询路由返回结果</param>
void Assert(List<string> allDataSources, List<string> resultDataSources);
}
public interface IDataSourceRouteAssert<T> : IDataSourceRouteAssert where T : class, IShardingDataSource
{
}
}

View File

@ -13,12 +13,12 @@ namespace ShardingCore.Core.QueryRouteManagers.Abstractions
/// <summary>
/// 路由断言
/// </summary>
public interface IRouteAssert
public interface ITableRouteAssert
{
void Assert(List<IPhysicTable> allPhysicTables, List<IPhysicTable> resultPhysicTables);
}
public interface IRouteAssert<T> : IRouteAssert where T : class, IShardingTable
public interface ITableRouteAssert<T> : ITableRouteAssert where T : class,IShardingTable
{
}

View File

@ -16,23 +16,43 @@ namespace ShardingCore.Core.QueryRouteManagers
*/
public class ShardingRouteContext
{
#region
/// <summary>
/// 强制路由直接返回对应的后缀表
/// </summary>
public Dictionary<Type, HashSet<string>> Must { get; }
public Dictionary<Type, HashSet<string>> MustDataSource { get; }
/// <summary>
/// 提示路由会经过断言的强制路由
/// </summary>
public Dictionary<Type, HashSet<string>> Hint { get; }
public Dictionary<Type, HashSet<string>> HintDataSource { get; }
/// <summary>
/// 断言
/// </summary>
public Dictionary<Type, LinkedList<IRouteAssert>> Assert { get; }
public Dictionary<Type, LinkedList<IDataSourceRouteAssert>> AssertDataSource { get; }
#endregion
#region
/// <summary>
/// 强制路由直接返回对应的后缀表
/// </summary>
public Dictionary<Type, HashSet<string>> MustTable { get; }
/// <summary>
/// 提示路由会经过断言的强制路由
/// </summary>
public Dictionary<Type, HashSet<string>> HintTable { get; }
/// <summary>
/// 断言
/// </summary>
public Dictionary<Type, LinkedList<ITableRouteAssert>> AssertTable { get; }
#endregion
private ShardingRouteContext()
{
Must = new Dictionary<Type, HashSet<string>>();
Hint = new Dictionary<Type, HashSet<string>>();
Assert = new Dictionary<Type, LinkedList<IRouteAssert>>();
MustDataSource = new Dictionary<Type, HashSet<string>>();
HintDataSource = new Dictionary<Type, HashSet<string>>();
AssertDataSource = new Dictionary<Type, LinkedList<IDataSourceRouteAssert>>();
MustTable = new Dictionary<Type, HashSet<string>>();
HintTable = new Dictionary<Type, HashSet<string>>();
AssertTable = new Dictionary<Type, LinkedList<ITableRouteAssert>>();
}
public static ShardingRouteContext Create()

View File

@ -22,10 +22,11 @@ namespace ShardingCore.Core.VirtualDatabase.VirtualDataSources
where TShardingDbContext : DbContext, IShardingDbContext
{
string DefaultDataSourceName { get; }
/// <summary>
/// 路由到具体的物理数据源
/// </summary>
/// <param name="entityType"></param>
/// <param name="routeRouteConfig"></param>
/// <returns>data source names</returns>
List<string> RouteTo(Type entityType, ShardingDataSourceRouteConfig routeRouteConfig);

View File

@ -38,9 +38,9 @@ namespace ShardingCore.Core.VirtualDatabase.VirtualDataSources
var virtualDataSourceRoute = GetRoute( entityType);
if (routeRouteConfig.UseQueryable())
return virtualDataSourceRoute.RouteWithWhere(routeRouteConfig.GetQueryable());
return virtualDataSourceRoute.RouteWithPredicate(routeRouteConfig.GetQueryable(), true);
if (routeRouteConfig.UsePredicate())
return virtualDataSourceRoute.RouteWithWhere((IQueryable)Activator.CreateInstance(typeof(EnumerableQuery<>).MakeGenericType(entityType), routeRouteConfig.UsePredicate()));
return virtualDataSourceRoute.RouteWithPredicate((IQueryable)Activator.CreateInstance(typeof(EnumerableQuery<>).MakeGenericType(entityType), routeRouteConfig.UsePredicate()), false);
object shardingKeyValue = null;
if (routeRouteConfig.UseValue())
shardingKeyValue = routeRouteConfig.GetShardingKeyValue();
@ -103,10 +103,10 @@ namespace ShardingCore.Core.VirtualDatabase.VirtualDataSources
public bool AddVirtualDataSourceRoute(IVirtualDataSourceRoute virtualDataSourceRoute)
{
if (!virtualDataSourceRoute.EntityType.IsShardingDataSource())
throw new InvalidOperationException($"{virtualDataSourceRoute.EntityType.FullName} should impl {nameof(IShardingDataSource)}");
if (!virtualDataSourceRoute.ShardingEntityType.IsShardingDataSource())
throw new InvalidOperationException($"{virtualDataSourceRoute.ShardingEntityType.FullName} should impl {nameof(IShardingDataSource)}");
return _dataSourceVirtualRoutes.TryAdd(virtualDataSourceRoute.EntityType, virtualDataSourceRoute);
return _dataSourceVirtualRoutes.TryAdd(virtualDataSourceRoute.ShardingEntityType, virtualDataSourceRoute);
}
}
}

View File

@ -40,6 +40,7 @@ namespace ShardingCore.Core.VirtualTables
/// 分库配置
/// </summary>
public PaginationMetadata PaginationMetadata { get; }
/// <summary>
/// 是否启用智能分页
/// </summary>
@ -54,7 +55,7 @@ namespace ShardingCore.Core.VirtualTables
EntityType = typeof(T);
ShardingConfig = ShardingUtil.Parse(EntityType);
var paginationConfiguration = virtualTableRoute.CreatePaginationConfiguration();
if (paginationConfiguration != null)
if (paginationConfiguration!=null)
{
PaginationMetadata = new PaginationMetadata();
var paginationBuilder = new PaginationBuilder<T>(PaginationMetadata);

View File

@ -0,0 +1,107 @@
using System.Collections.Generic;
using System.Linq;
using ShardingCore.Core.PhysicTables;
using ShardingCore.Core.QueryRouteManagers;
using ShardingCore.Core.QueryRouteManagers.Abstractions;
using ShardingCore.Core.VirtualRoutes.TableRoutes.Abstractions;
using ShardingCore.Exceptions;
using ShardingCore.Extensions;
namespace ShardingCore.Core.VirtualRoutes.DataSourceRoutes.Abstractions
{
/*
* @Author: xjm
* @Description:
* @Date: 2021/8/25 17:23:42
* @Ver: 1.0
* @Email: 326308290@qq.com
*/
/// <summary>
/// 过滤虚拟路由用于处理强制路由、提示路由、路由断言
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="TKey"></typeparam>
public abstract class AbstractShardingFilterVirtualDataSourceRoute<T, TKey> : AbstractVirtualDataSourceRoute<T, TKey> where T : class, IShardingDataSource
{
public ShardingRouteContext CurrentShardingRouteContext =>
ShardingContainer.GetService<IShardingRouteManager>().Current;
/// <summary>
/// 启用提示路由
/// </summary>
protected virtual bool EnableHintRoute => false;
/// <summary>
/// 启用断言路由
/// </summary>
protected virtual bool EnableAssertRoute => false;
public override List<string> RouteWithPredicate(IQueryable queryable,bool isQuery)
{
var allDataSourceNames = GetAllDataSourceNames();
if (!isQuery)
{
//后拦截器
return AfterDataSourceFilter(allDataSourceNames, DoRouteWithPredicate(allDataSourceNames, queryable));
}
//强制路由不经过断言
if (EnableHintRoute)
{
if (CurrentShardingRouteContext != null)
{
if (CurrentShardingRouteContext.TryGetMustDataSource<T>(out HashSet<string> mustDataSources) && mustDataSources.IsNotEmpty())
{
var dataSources = allDataSourceNames.Where(o => mustDataSources.Contains(o)).ToList();
if (dataSources.IsEmpty()||dataSources.Count!=mustDataSources.Count)
throw new ShardingCoreException(
$" sharding data source route must error:[{ShardingEntityType.FullName}]-->[{string.Join(",",mustDataSources)}]");
return dataSources;
}
if (CurrentShardingRouteContext.TryGetHintDataSource<T>(out HashSet<string> hintDataSouces) && hintDataSouces.IsNotEmpty())
{
var dataSources = allDataSourceNames.Where(o => hintDataSouces.Contains(o)).ToList();
if (dataSources.IsEmpty()||dataSources.Count!=hintDataSouces.Count)
throw new ShardingCoreException(
$" sharding data source route hint error:[{ShardingEntityType.FullName}]-->[{string.Join(",",hintDataSouces)}]");
ProcessAssertRoutes(allDataSourceNames, dataSources);
return dataSources;
}
}
}
var filterDataSources = DoRouteWithPredicate(allDataSourceNames, queryable);
//后拦截器
var resultDataSources = AfterDataSourceFilter(allDataSourceNames, filterDataSources);
//最后处理断言
ProcessAssertRoutes(allDataSourceNames, resultDataSources);
return resultDataSources;
}
private void ProcessAssertRoutes(List<string> allDataSources,List<string> filterDataSources)
{
if (EnableAssertRoute)
{
if (CurrentShardingRouteContext != null && CurrentShardingRouteContext.TryGetAssertDataSource<T>(out ICollection<IDataSourceRouteAssert> routeAsserts) && routeAsserts.IsNotEmpty())
{
foreach (var routeAssert in routeAsserts)
{
routeAssert.Assert(allDataSources, filterDataSources);
}
}
}
}
protected abstract List<string> DoRouteWithPredicate(List<string> allDataSourceNames, IQueryable queryable);
/// <summary>
/// 物理表过滤后
/// </summary>
/// <param name="allDataSourceNames">所有的物理表</param>
/// <param name="filterDataSources">过滤后的物理表</param>
/// <returns></returns>
protected virtual List<string> AfterDataSourceFilter(List<string> allDataSourceNames, List<string> filterDataSources)
{
return filterDataSources;
}
}
}

View File

@ -0,0 +1,60 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using ShardingCore.Core.PhysicTables;
using ShardingCore.Exceptions;
using ShardingCore.Extensions;
using ShardingCore.Utils;
namespace ShardingCore.Core.VirtualRoutes.DataSourceRoutes.Abstractions
{
/*
* @Author: xjm
* @Description:
* @Date: Saturday, 19 December 2020 19:55:24
* @Email: 326308290@qq.com
*/
/// <summary>
/// 抽象类型抽象出对应的条件表达式
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="TKey"></typeparam>
public abstract class AbstractShardingOperatorVirtualDataSourceRoute<T, TKey> : AbstractShardingFilterVirtualDataSourceRoute<T, TKey> where T : class, IShardingDataSource
{
protected override List<string> DoRouteWithPredicate(List<string> allDataSourceNames, IQueryable queryable)
{
//获取所有需要路由的表后缀
var filter = ShardingUtil.GetRouteShardingTableFilter(queryable, ShardingUtil.Parse(typeof(T)), ConvertToShardingKey, GetRouteToFilter);
var dataSources = allDataSourceNames.Where(o => filter(o)).ToList();
return dataSources;
}
/// <summary>
/// 如何路由到具体表 shardingKeyValue:分表的值, 返回结果:如果返回true表示返回该表 第一个参数 tail 第二参数是否返回该物理表
/// </summary>
/// <param name="shardingKey">分表的值</param>
/// <param name="shardingOperator">操作</param>
/// <returns>如果返回true表示返回该表 第一个参数 tail 第二参数是否返回该物理表</returns>
protected abstract Expression<Func<string, bool>> GetRouteToFilter(TKey shardingKey, ShardingOperatorEnum shardingOperator);
public override string RouteWithValue(object shardingKey)
{
var allDataSourceNames = GetAllDataSourceNames();
var shardingKeyToDataSource = ShardingKeyToDataSourceName(shardingKey);
var dataSources = allDataSourceNames.Where(o => o== shardingKeyToDataSource).ToList();
if (dataSources.IsEmpty())
{
var routeConfig = ShardingUtil.Parse(typeof(T));
throw new ShardingKeyRouteNotMatchException($"{routeConfig.EntityType} -> [{routeConfig.ShardingTableField}] ->【{shardingKey}】 all data sources ->[{string.Join(",", allDataSourceNames.Select(o=>o))}]");
}
if (dataSources.Count > 1)
throw new ShardingKeyRouteMoreException($"data source:{string.Join(",", dataSources.Select(o => $"[{o}]"))}");
return dataSources[0];
}
}
}

View File

@ -0,0 +1,68 @@
using System;
using System.Collections.Generic;
using System.Linq;
using ShardingCore.Sharding.PaginationConfigurations;
namespace ShardingCore.Core.VirtualRoutes.DataSourceRoutes.Abstractions
{
/*
* @Author: xjm
* @Description:
* @Date: Friday, 18 December 2020 14:33:01
* @Email: 326308290@qq.com
*/
public abstract class AbstractVirtualDataSourceRoute<T, TKey> : IVirtualDataSourceRoute<T> where T : class, IShardingDataSource
{
public void Init()
{
var paginationConfiguration = CreatePaginationConfiguration();
if (paginationConfiguration != null)
{
PaginationMetadata = new PaginationMetadata();
var paginationBuilder = new PaginationBuilder<T>(PaginationMetadata);
paginationConfiguration.Configure(paginationBuilder);
}
}
public virtual IPaginationConfiguration<T> CreatePaginationConfiguration()
{
return null;
}
/// <summary>
/// entity type
/// </summary>
public Type ShardingEntityType => typeof(T);
public new PaginationMetadata PaginationMetadata { get; protected set; }
public bool EnablePagination => PaginationMetadata != null;
/// <summary>
/// 分库字段object类型的如何转成对应的泛型类型how convert sharding key to generic type key value
/// </summary>
/// <param name="shardingKey"></param>
/// <returns></returns>
protected abstract TKey ConvertToShardingKey(object shardingKey);
/// <summary>
/// 分库字段如何转成对应的数据源名称 how convert sharding data source key to data source name
/// </summary>
/// <param name="shardingKey"></param>
/// <returns></returns>
public abstract string ShardingKeyToDataSourceName(object shardingKey);
/// <summary>
/// 根据表达式返回对应的数据源名称 find data source names with queryable
/// </summary>
/// <param name="queryable"></param>
/// <param name="isQuery"></param>
/// <returns></returns>
public abstract List<string> RouteWithPredicate(IQueryable queryable, bool isQuery);
/// <summary>
/// 值如何转成对应的数据源
/// </summary>
/// <param name="shardingKey"></param>
/// <returns></returns>
public abstract string RouteWithValue(object shardingKey);
public abstract List<string> GetAllDataSourceNames();
public abstract bool AddDataSourceName(string dataSourceName);
}
}

View File

@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using ShardingCore.Core.VirtualDatabase.VirtualDataSources.PhysicDataSources;
using ShardingCore.Sharding.PaginationConfigurations;
namespace ShardingCore.Core.VirtualRoutes.DataSourceRoutes
{
@ -13,15 +14,24 @@ namespace ShardingCore.Core.VirtualRoutes.DataSourceRoutes
*/
public interface IVirtualDataSourceRoute
{
Type EntityType { get; }
Type ShardingEntityType { get;}
/// <summary>
/// 分页配置
/// </summary>
PaginationMetadata PaginationMetadata { get; }
/// <summary>
/// 是否启用分页配置
/// </summary>
bool EnablePagination { get; }
string ShardingKeyToDataSourceName(object shardingKeyValue);
/// <summary>
/// 根据查询条件路由返回物理数据源
/// </summary>
/// <param name="queryable"></param>
/// <param name="isQuery"></param>
/// <returns>data source name</returns>
List<string> RouteWithWhere(IQueryable queryable);
List<string> RouteWithPredicate(IQueryable queryable, bool isQuery);
/// <summary>
/// 根据值进行路由
@ -31,10 +41,25 @@ namespace ShardingCore.Core.VirtualRoutes.DataSourceRoutes
string RouteWithValue(object shardingKeyValue);
List<string> GetAllDataSourceNames();
/// <summary>
/// 添加数据源
/// </summary>
/// <param name="dataSourceName"></param>
/// <returns></returns>
bool AddDataSourceName(string dataSourceName);
/// <summary>
/// 初始化
/// </summary>
void Init();
}
public interface IVirtualDataSourceRoute<T> : IVirtualDataSourceRoute where T : class
public interface IVirtualDataSourceRoute<T> : IVirtualDataSourceRoute where T : class, IShardingDataSource
{
/// <summary>
/// 返回null就是表示不开启分页配置
/// </summary>
/// <returns></returns>
IPaginationConfiguration<T> CreatePaginationConfiguration();
}
}

View File

@ -81,7 +81,7 @@ namespace ShardingCore.Core.VirtualRoutes.TableRoutes.Abstractions
{
if (EnableAssertRoute)
{
if (CurrentShardingRouteContext != null && CurrentShardingRouteContext.TryGetAssertTail<T>(out ICollection<IRouteAssert> routeAsserts) && routeAsserts.IsNotEmpty())
if (CurrentShardingRouteContext != null && CurrentShardingRouteContext.TryGetAssertTail<T>(out ICollection<ITableRouteAssert> routeAsserts) && routeAsserts.IsNotEmpty())
{
foreach (var routeAssert in routeAsserts)
{

View File

@ -38,7 +38,7 @@ namespace ShardingCore.Core.VirtualRoutes.TableRoutes.Abstractions
public override IPhysicTable RouteWithValue(List<IPhysicTable> allPhysicTables, object shardingKey)
{
var shardingKeyToTail = ShardingKeyToTail(ConvertToShardingKey(shardingKey));
var shardingKeyToTail = ShardingKeyToTail(shardingKey);
var physicTables = allPhysicTables.Where(o => o.Tail== shardingKeyToTail).ToList();
if (physicTables.IsEmpty())

View File

@ -51,9 +51,9 @@ namespace ShardingCore.Core.VirtualRoutes.TableRoutes.Abstractions
/// 根据值路由
/// </summary>
/// <param name="allPhysicTables"></param>
/// <param name="shardingKeyValue"></param>
/// <param name="shardingKey"></param>
/// <returns></returns>
public abstract IPhysicTable RouteWithValue(List<IPhysicTable> allPhysicTables, object shardingKeyValue);
public abstract IPhysicTable RouteWithValue(List<IPhysicTable> allPhysicTables, object shardingKey);
/// <summary>
/// 返回数据库现有的尾巴
/// </summary>

View File

@ -33,9 +33,9 @@ namespace ShardingCore.Core.VirtualRoutes.TableRoutes
/// 根据值进行路由
/// </summary>
/// <param name="allPhysicTables"></param>
/// <param name="shardingKeyValue"></param>
/// <param name="shardingKey"></param>
/// <returns></returns>
IPhysicTable RouteWithValue(List<IPhysicTable> allPhysicTables, object shardingKeyValue);
IPhysicTable RouteWithValue(List<IPhysicTable> allPhysicTables, object shardingKey);
/// <summary>
/// 获取所有的目前数据库存在的尾巴
/// get all tails in the db

View File

@ -25,5 +25,15 @@ namespace ShardingCore.Extensions.InternalExtensions
{
return condition ? source.OrderByDescending(keySelector, comparer) : source;
}
public static IOrderedEnumerable<TShource> ThenByIf<TShource, TKey>(this IOrderedEnumerable<TShource> source, Func<TShource, TKey> keySelector, bool condition,
IComparer<TKey>? comparer)
{
return condition ? source.ThenBy(keySelector, comparer) : source;
}
public static IOrderedEnumerable<TShource> ThenByDescendingIf<TShource, TKey>(this IOrderedEnumerable<TShource> source, Func<TShource, TKey> keySelector, bool condition,
IComparer<TKey>? comparer)
{
return condition ? source.ThenByDescending(keySelector, comparer) : source;
}
}
}

View File

@ -0,0 +1,201 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ShardingCore.Core;
using ShardingCore.Core.QueryRouteManagers;
using ShardingCore.Core.QueryRouteManagers.Abstractions;
using ShardingCore.Exceptions;
namespace ShardingCore.Extensions
{
/*
* @Author: xjm
* @Description:
* @Date: 2021/8/23 22:19:24
* @Ver: 1.0
* @Email: 326308290@qq.com
*/
public static class ShardingDataSourceRouteExtension
{
/// <summary>
/// 创建或者添加强制路由
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <param name="shardingRouteContext"></param>
/// <param name="dataSources"></param>
/// <returns>任何一个dataSources被添加成功就返回成功</returns>
public static bool TryCreateOrAddMustDataSource<TEntity>(this ShardingRouteContext shardingRouteContext, params string[] dataSources) where TEntity : class, IShardingDataSource
{
return TryCreateOrAddMustDataSource(shardingRouteContext, typeof(TEntity), dataSources);
}
/// <summary>
/// 创建或者添加强制路由
/// </summary>
/// <param name="shardingRouteContext"></param>
/// <param name="entityType"></param>
/// <param name="dataSources"></param>
/// <returns>任何一个dataSources被添加成功就返回成功</returns>
public static bool TryCreateOrAddMustDataSource(this ShardingRouteContext shardingRouteContext, Type entityType, params string[] dataSources)
{
if (shardingRouteContext == null)
{
return false;
}
if (dataSources.IsEmpty())
return false;
if (!entityType.IsShardingDataSource())
throw new ShardingCoreException($"sharding route entity type :{entityType.FullName} must impl {nameof(IShardingDataSource)}");
if (!shardingRouteContext.MustDataSource.TryGetValue(entityType,out HashSet<string> mustDataSources))
{
mustDataSources = new HashSet<string>();
shardingRouteContext.MustDataSource.Add(entityType, mustDataSources);
}
return dataSources.Select(o => mustDataSources.Add(o)).Any(o => o);
}
/// <summary>
/// 创建或者添加提示路由
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <param name="shardingRouteContext"></param>
/// <param name="dataSources"></param>
/// <returns>任何一个dataSources被添加成功就返回成功</returns>
public static bool TryCreateOrAddHintDataSource<TEntity>(this ShardingRouteContext shardingRouteContext, params string[] dataSources) where TEntity : class, IShardingDataSource
{
return TryCreateOrAddHintDataSource(shardingRouteContext, typeof(TEntity), dataSources);
}
/// <summary>
/// 创建或者添加提示路由
/// </summary>
/// <param name="shardingRouteContext"></param>
/// <param name="entityType"></param>
/// <param name="dataSources"></param>
/// <returns>任何一个dataSources被添加成功就返回成功</returns>
public static bool TryCreateOrAddHintDataSource(this ShardingRouteContext shardingRouteContext, Type entityType, params string[] dataSources)
{
if (shardingRouteContext == null)
{
return false;
}
if (dataSources.IsEmpty())
return false;
if (!entityType.IsShardingDataSource())
throw new ShardingCoreException($"sharding route entity type :{entityType.FullName} must impl {nameof(IShardingDataSource)}");
if (!shardingRouteContext.HintDataSource.TryGetValue(entityType, out HashSet<string> hintDataSources))
{
hintDataSources = new HashSet<string>();
shardingRouteContext.HintDataSource.Add(entityType, hintDataSources);
}
return dataSources.Select(o => hintDataSources.Add(o)).Any(o => o);
}
/// <summary>
/// 创建或者添加断言
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <param name="shardingRouteContext"></param>
/// <param name="dataSources"></param>
/// <returns></returns>
public static bool TryCreateOrAddAssertDataSource<TEntity>(this ShardingRouteContext shardingRouteContext, params IDataSourceRouteAssert<TEntity>[] dataSources) where TEntity : class, IShardingDataSource
{
return TryCreateOrAddAssertDataSource(shardingRouteContext, typeof(TEntity), dataSources);
}
public static bool TryCreateOrAddAssertDataSource(this ShardingRouteContext shardingRouteContext, Type entityType, params IDataSourceRouteAssert[] asserts)
{
if (shardingRouteContext == null)
{
return false;
}
if (asserts.IsEmpty())
return false;
if (!entityType.IsShardingDataSource())
throw new ShardingCoreException($"sharding route entity type :{entityType.FullName} must impl {nameof(IShardingDataSource)}");
if (!shardingRouteContext.AssertDataSource.TryGetValue(entityType, out LinkedList<IDataSourceRouteAssert> routeAsserts))
{
routeAsserts = new LinkedList<IDataSourceRouteAssert>();
shardingRouteContext.AssertDataSource.Add(entityType, routeAsserts);
}
foreach (var routeAssert in asserts)
{
routeAsserts.AddLast(routeAssert);
}
return true;
}
public static bool TryGetMustDataSource<TEntity>(this ShardingRouteContext shardingRouteContext, out HashSet<string> dataSources) where TEntity : class, IShardingDataSource
{
return TryGetMustDataSource(shardingRouteContext,typeof(TEntity),out dataSources);
}
public static bool TryGetMustDataSource(this ShardingRouteContext shardingRouteContext,Type entityType, out HashSet<string> dataSources)
{
if (shardingRouteContext == null)
{
dataSources = null;
return false;
}
if (!entityType.IsShardingDataSource())
throw new ShardingCoreException($"sharding route entity type :{entityType.FullName} must impl {nameof(IShardingDataSource)}");
if (!shardingRouteContext.MustDataSource.ContainsKey(entityType))
{
dataSources = null;
return false;
}
dataSources = shardingRouteContext.MustDataSource[entityType];
return true;
}
public static bool TryGetHintDataSource<TEntity>(this ShardingRouteContext shardingRouteContext, out HashSet<string> dataSources) where TEntity : class,IShardingDataSource
{
return TryGetHintDataSource(shardingRouteContext,typeof(TEntity),out dataSources);
}
public static bool TryGetHintDataSource(this ShardingRouteContext shardingRouteContext,Type entityType, out HashSet<string> dataSources)
{
if (shardingRouteContext == null)
{
dataSources = null;
return false;
}
if (!entityType.IsShardingDataSource())
throw new ShardingCoreException($"sharding route entity type :{entityType.FullName} must impl {nameof(IShardingDataSource)}");
if (!shardingRouteContext.HintDataSource.ContainsKey(entityType))
{
dataSources = null;
return false;
}
dataSources = shardingRouteContext.HintDataSource[entityType];
return true;
}
public static bool TryGetAssertDataSource<TEntity>(this ShardingRouteContext shardingRouteContext, out ICollection<IDataSourceRouteAssert> dataSources)where TEntity : class,IShardingDataSource
{
return TryGetAssertDataSource(shardingRouteContext,typeof(TEntity), out dataSources);
}
public static bool TryGetAssertDataSource(this ShardingRouteContext shardingRouteContext,Type entityType, out ICollection<IDataSourceRouteAssert> dataSources)
{
if (shardingRouteContext == null)
{
dataSources = null;
return false;
}
if (!entityType.IsShardingDataSource())
throw new ShardingCoreException($"sharding route entity type :{entityType.FullName} must impl {nameof(IShardingDataSource)}");
if (!shardingRouteContext.AssertDataSource.ContainsKey(entityType))
{
dataSources = null;
return false;
}
dataSources = shardingRouteContext.AssertDataSource[entityType];
return true;
}
}
}

View File

@ -16,7 +16,7 @@ namespace ShardingCore.Extensions
* @Ver: 1.0
* @Email: 326308290@qq.com
*/
public static class ShardingRouteExtension
public static class ShardingTableRouteExtension
{
/// <summary>
/// 创建或者添加强制路由
@ -47,10 +47,10 @@ namespace ShardingCore.Extensions
return false;
if (!entityType.IsShardingTable())
throw new ShardingCoreException($"sharding route entity type :{entityType.FullName} must impl {nameof(IShardingTable)}");
if (!shardingRouteContext.Must.TryGetValue(entityType,out HashSet<string> mustTails))
if (!shardingRouteContext.MustTable.TryGetValue(entityType,out HashSet<string> mustTails))
{
mustTails = new HashSet<string>();
shardingRouteContext.Must.Add(entityType, mustTails);
shardingRouteContext.MustTable.Add(entityType, mustTails);
}
return tails.Select(o => mustTails.Add(o)).Any(o => o);
@ -84,10 +84,10 @@ namespace ShardingCore.Extensions
return false;
if (!entityType.IsShardingTable())
throw new ShardingCoreException($"sharding route entity type :{entityType.FullName} must impl {nameof(IShardingTable)}");
if (!shardingRouteContext.Hint.TryGetValue(entityType, out HashSet<string> hintTails))
if (!shardingRouteContext.HintTable.TryGetValue(entityType, out HashSet<string> hintTails))
{
hintTails = new HashSet<string>();
shardingRouteContext.Hint.Add(entityType, hintTails);
shardingRouteContext.HintTable.Add(entityType, hintTails);
}
return tails.Select(o => hintTails.Add(o)).Any(o => o);
@ -99,11 +99,11 @@ namespace ShardingCore.Extensions
/// <param name="shardingRouteContext"></param>
/// <param name="tails"></param>
/// <returns></returns>
public static bool TryCreateOrAddAssertTail<TEntity>(this ShardingRouteContext shardingRouteContext, params IRouteAssert<TEntity>[] tails) where TEntity : class, IShardingTable
public static bool TryCreateOrAddAssertTail<TEntity>(this ShardingRouteContext shardingRouteContext, params ITableRouteAssert<TEntity>[] tails) where TEntity : class, IShardingTable
{
return TryCreateOrAddAssertTail(shardingRouteContext, typeof(TEntity), tails);
}
public static bool TryCreateOrAddAssertTail(this ShardingRouteContext shardingRouteContext, Type entityType, params IRouteAssert[] asserts)
public static bool TryCreateOrAddAssertTail(this ShardingRouteContext shardingRouteContext, Type entityType, params ITableRouteAssert[] asserts)
{
if (shardingRouteContext == null)
{
@ -114,10 +114,10 @@ namespace ShardingCore.Extensions
return false;
if (!entityType.IsShardingTable())
throw new ShardingCoreException($"sharding route entity type :{entityType.FullName} must impl {nameof(IShardingTable)}");
if (!shardingRouteContext.Assert.TryGetValue(entityType, out LinkedList<IRouteAssert> routeAsserts))
if (!shardingRouteContext.AssertTable.TryGetValue(entityType, out LinkedList<ITableRouteAssert> routeAsserts))
{
routeAsserts = new LinkedList<IRouteAssert>();
shardingRouteContext.Assert.Add(entityType, routeAsserts);
routeAsserts = new LinkedList<ITableRouteAssert>();
shardingRouteContext.AssertTable.Add(entityType, routeAsserts);
}
foreach (var routeAssert in asserts)
{
@ -142,13 +142,13 @@ namespace ShardingCore.Extensions
}
if (!entityType.IsShardingTable())
throw new ShardingCoreException($"sharding route entity type :{entityType.FullName} must impl {nameof(IShardingTable)}");
if (!shardingRouteContext.Must.ContainsKey(entityType))
if (!shardingRouteContext.MustTable.ContainsKey(entityType))
{
tail = null;
return false;
}
tail = shardingRouteContext.Must[entityType];
tail = shardingRouteContext.MustTable[entityType];
return true;
}
public static bool TryGetHintTail<TEntity>(this ShardingRouteContext shardingRouteContext, out HashSet<string> tail) where TEntity : class,IShardingTable
@ -164,21 +164,21 @@ namespace ShardingCore.Extensions
}
if (!entityType.IsShardingTable())
throw new ShardingCoreException($"sharding route entity type :{entityType.FullName} must impl {nameof(IShardingTable)}");
if (!shardingRouteContext.Hint.ContainsKey(entityType))
if (!shardingRouteContext.HintTable.ContainsKey(entityType))
{
tail = null;
return false;
}
tail = shardingRouteContext.Hint[entityType];
tail = shardingRouteContext.HintTable[entityType];
return true;
}
public static bool TryGetAssertTail<TEntity>(this ShardingRouteContext shardingRouteContext, out ICollection<IRouteAssert> tail)where TEntity : class,IShardingTable
public static bool TryGetAssertTail<TEntity>(this ShardingRouteContext shardingRouteContext, out ICollection<ITableRouteAssert> tail)where TEntity : class,IShardingTable
{
return TryGetAssertTail(shardingRouteContext,typeof(TEntity), out tail);
}
public static bool TryGetAssertTail(this ShardingRouteContext shardingRouteContext,Type entityType, out ICollection<IRouteAssert> tail)
public static bool TryGetAssertTail(this ShardingRouteContext shardingRouteContext,Type entityType, out ICollection<ITableRouteAssert> tail)
{
if (shardingRouteContext == null)
{
@ -187,13 +187,13 @@ namespace ShardingCore.Extensions
}
if (!entityType.IsShardingTable())
throw new ShardingCoreException($"sharding route entity type :{entityType.FullName} must impl {nameof(IShardingTable)}");
if (!shardingRouteContext.Assert.ContainsKey(entityType))
if (!shardingRouteContext.AssertTable.ContainsKey(entityType))
{
tail = null;
return false;
}
tail = shardingRouteContext.Assert[entityType];
tail = shardingRouteContext.AssertTable[entityType];
return true;
}

View File

@ -19,19 +19,45 @@ namespace ShardingCore.Extensions
/// <param name="streamMergeContext"></param>
/// <typeparam name="TEntity"></typeparam>
/// <returns></returns>
public static bool IsShardingQuery<TEntity>(this StreamMergeContext<TEntity> streamMergeContext)
public static bool IsNormalQuery<TEntity>(this StreamMergeContext<TEntity> streamMergeContext)
{
return streamMergeContext.TableRouteResults.Count() > 1;
return streamMergeContext.QueryEntities.Any(o=>!o.IsShardingDataSource()&&!o.IsShardingTable());
}
/// <summary>
/// 单路由查询
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <param name="streamMergeContext"></param>
/// <returns></returns>
public static bool IsSingleRouteQuery<TEntity>(this StreamMergeContext<TEntity> streamMergeContext)
{
return streamMergeContext.DataSourceRouteResult.IntersectDataSources.Count==1&&streamMergeContext.TableRouteResults.Count()==1;
}
/// <summary>
/// 单表查询
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <param name="streamMergeContext"></param>
/// <returns></returns>
public static bool IsSingleShardingTableQuery<TEntity>(this StreamMergeContext<TEntity> streamMergeContext)
{
return streamMergeContext.TableRouteResults.First().ReplaceTables.Count(o => o.EntityType.IsShardingTable()) == 1;
}
public static IVirtualTableManager GetVirtualTableManager<TEntity>(this StreamMergeContext<TEntity> streamMergeContext)
/// <summary>
/// 本次查询仅包含一个对象的分表分库
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <param name="streamMergeContext"></param>
/// <returns></returns>
public static bool IsSingleShardingQuery<TEntity>(this StreamMergeContext<TEntity> streamMergeContext)
{
return (IVirtualTableManager)ShardingContainer.GetService(
typeof(IVirtualTableManager<>).GetGenericType0(streamMergeContext.GetShardingDbContext().GetType()));
return streamMergeContext.GetOriginalQueryable().ParseQueryableRoute().Count(o=>o.IsShardingTable()||o.IsShardingDataSource())==1;
}
public static bool IsSupportPaginationQuery<TEntity>(this StreamMergeContext<TEntity> streamMergeContext)
{
var queryEntities = streamMergeContext.GetOriginalQueryable().ParseQueryableRoute();
//仅一个对象支持分库或者分表的组合
return queryEntities.Count(o=>(o.IsShardingDataSource()&&!o.IsShardingTable()) ||(o.IsShardingDataSource()&& o.IsShardingTable())|| (!o.IsShardingDataSource() && o.IsShardingTable())) ==1;
}
}
}

View File

@ -12,7 +12,7 @@ namespace ShardingCore.Sharding.PaginationConfigurations
* @Ver: 1.0
* @Email: 326308290@qq.com
*/
public interface IPaginationConfiguration<TEntity> where TEntity : class,IShardingTable
public interface IPaginationConfiguration<TEntity> where TEntity : class
{
void Configure(PaginationBuilder<TEntity> builder);
}

View File

@ -23,12 +23,12 @@ namespace ShardingCore.Sharding.PaginationConfigurations
/// <summary>
/// 使用哪个后缀比较
/// </summary>
/// <param name="tailComparer"></param>
/// <param name="routeComparer"></param>
/// <returns></returns>
public PaginationOrderPropertyBuilder UseTailComparer(IComparer<string> tailComparer)
public PaginationOrderPropertyBuilder UseRouteComparer(IComparer<string> routeComparer)
{
_paginationSequenceConfig.TailComparer= tailComparer ?? throw new ArgumentException(nameof(tailComparer));
_paginationSequenceConfig.RouteComparer= routeComparer ?? throw new ArgumentException(nameof(routeComparer));
return this;
}
/// <summary>
@ -45,10 +45,12 @@ namespace ShardingCore.Sharding.PaginationConfigurations
/// 如果查询没发现排序就将当前配置追加上去
/// </summary>
/// <param name="order">大于等于0生效,越大优先级越高</param>
/// <param name="defAsc">默认asc还是desc</param>
/// <returns></returns>
public PaginationOrderPropertyBuilder UseAppendIfOrderNone(int order=0)
public PaginationOrderPropertyBuilder UseAppendIfOrderNone(int order=0,bool defAsc=true)
{
_paginationSequenceConfig.AppendOrder = order;
_paginationSequenceConfig.AppendAsc = defAsc;
return this;
}
}

View File

@ -17,16 +17,16 @@ namespace ShardingCore.Sharding.PaginationConfigurations
*/
public class PaginationSequenceConfig
{
public PaginationSequenceConfig(LambdaExpression orderPropertyExpression, PaginationMatchEnum paginationMatchEnum= PaginationMatchEnum.Owner, IComparer<string> tailComparer=null)
public PaginationSequenceConfig(LambdaExpression orderPropertyExpression, PaginationMatchEnum paginationMatchEnum= PaginationMatchEnum.Owner, IComparer<string> routeComparer=null)
{
OrderPropertyInfo = orderPropertyExpression.GetPropertyAccess();
PropertyName = OrderPropertyInfo.Name;
PaginationMatchEnum = paginationMatchEnum;
TailComparer = tailComparer ?? Comparer<string>.Default;
RouteComparer = routeComparer ?? Comparer<string>.Default;
SequenceTails = new HashSet<string>();
}
public IComparer<string> TailComparer { get; set; }
public IComparer<string> RouteComparer { get; set; }
public PaginationMatchEnum PaginationMatchEnum { get; set; }
public PropertyInfo OrderPropertyInfo { get; set; }
@ -38,6 +38,8 @@ namespace ShardingCore.Sharding.PaginationConfigurations
/// 大于等于0表示需要
/// </summary>
public int AppendOrder { get; set; } = -1;
public bool AppendAsc { get; set; } = true;
public string PropertyName { get;}
public ISet<string> SequenceTails { get; }

View File

@ -138,8 +138,8 @@ namespace ShardingCore.Sharding.ShardingQueryExecutors
var streamMergeContext = streamMergeContextMethod.MakeGenericMethod(new Type[] { queryEntityType }).Invoke(streamMergeContextFactory, new[] { queryable, shardingDbContext });
Type streamMergeEngineType = typeof(AsyncEnumerableStreamMergeEngine<>);
streamMergeEngineType = streamMergeEngineType.MakeGenericType(queryEntityType);
Type streamMergeEngineType = typeof(AsyncEnumerableStreamMergeEngine<,>);
streamMergeEngineType = streamMergeEngineType.MakeGenericType(shardingDbContext.GetType(), queryEntityType);
return (TResult)Activator.CreateInstance(streamMergeEngineType, streamMergeContext);
}

View File

@ -4,10 +4,15 @@ using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using ShardingCore.Core.Internal.Visitors;
using ShardingCore.Core.ShardingPage.Abstractions;
using ShardingCore.Core.VirtualDatabase.VirtualDataSources;
using ShardingCore.Core.VirtualDatabase.VirtualTables;
using ShardingCore.Core.VirtualRoutes.DataSourceRoutes;
using ShardingCore.Core.VirtualTables;
using ShardingCore.Exceptions;
using ShardingCore.Extensions;
using ShardingCore.Extensions.InternalExtensions;
using ShardingCore.Sharding.Abstractions;
@ -25,89 +30,192 @@ namespace ShardingCore.Sharding.ShardingQueryExecutors
* @Ver: 1.0
* @Email: 326308290@qq.com
*/
public class EnumeratorShardingQueryExecutor<TEntity>
public class EnumeratorShardingQueryExecutor<TShardingDbContext, TEntity>
where TShardingDbContext : DbContext, IShardingDbContext
{
private readonly StreamMergeContext<TEntity> _streamMergeContext;
private readonly IShardingPageManager _shardingPageManager;
private readonly IVirtualTableManager _virtualTableManager;
private readonly IVirtualTableManager<TShardingDbContext> _virtualTableManager;
private readonly IVirtualDataSource<TShardingDbContext> _virtualDataSource;
public EnumeratorShardingQueryExecutor(StreamMergeContext<TEntity> streamMergeContext)
{
_streamMergeContext = streamMergeContext;
_shardingPageManager = ShardingContainer.GetService<IShardingPageManager>();
_virtualTableManager = streamMergeContext.GetVirtualTableManager();
_virtualTableManager = ShardingContainer.GetService<IVirtualTableManager<TShardingDbContext>>();
_virtualDataSource = ShardingContainer.GetService<IVirtualDataSource<TShardingDbContext>>();
}
public IEnumeratorStreamMergeEngine<TEntity> ExecuteAsync(CancellationToken cancellationToken = new CancellationToken())
{
//操作单表
if (!_streamMergeContext.IsShardingQuery())
//操作单表或者单分库分表之类的
if (_streamMergeContext.IsNormalQuery()||_streamMergeContext.IsSingleRouteQuery())
{
return new SingleQueryEnumeratorAsyncStreamMergeEngine<TEntity>(_streamMergeContext);
return new SingleQueryEnumeratorAsyncStreamMergeEngine<TShardingDbContext, TEntity>(_streamMergeContext);
}
//未开启系统分表或者本次查询涉及多张分表
if (_streamMergeContext.IsPaginationQuery() && _streamMergeContext.IsSingleShardingTableQuery() && _shardingPageManager.Current != null)
if (_streamMergeContext.IsPaginationQuery() && _streamMergeContext.IsSupportPaginationQuery() && _shardingPageManager.Current != null)
{
//获取虚拟表判断是否启用了分页配置
var shardingEntityType = _streamMergeContext.TableRouteResults.First().ReplaceTables.First().EntityType;
var virtualTable = _virtualTableManager.GetVirtualTable(shardingEntityType);
if (virtualTable.EnablePagination)
var shardingEntityType = _streamMergeContext.QueryEntities.FirstOrDefault(o => o.IsShardingDataSource() || o.IsShardingTable());
if (shardingEntityType == null)
throw new ShardingCoreException($"query not found sharding data source or sharding table entity");
if (_streamMergeContext.Orders.IsEmpty())
{
var paginationMetadata = virtualTable.PaginationMetadata;
//判断本次查询的排序是否包含order如果不包含就获取默认添加的排序
if (_streamMergeContext.Orders.IsEmpty())
{
//除了判断属性名还要判断所属关系
var appendPaginationConfig = paginationMetadata.PaginationConfigs.OrderByDescending(o => o.AppendOrder)
.FirstOrDefault(o => o.AppendIfOrderNone && typeof(TEntity).ContainPropertyName(o.PropertyName) && PaginationMatch(o));
if (appendPaginationConfig != null)
{
return new AppenOrderSequenceEnumeratorAsyncStreamMergeEngine<TEntity>(_streamMergeContext, appendPaginationConfig, _shardingPageManager.Current.RouteQueryResults);
}
}
else
{
var orderCount = _streamMergeContext.Orders.Count();
var primaryOrder = _streamMergeContext.Orders.First();
if (orderCount == 1)
{
var sequenceFullMatchOrderConfig = paginationMetadata.PaginationConfigs.Where(o => !o.PaginationMatchEnum.HasFlag(PaginationMatchEnum.PrimaryMatch)).FirstOrDefault(o => PaginationPrimaryMatch(o, primaryOrder));
if (sequenceFullMatchOrderConfig != null)
{
return new SequenceEnumeratorAsyncStreamMergeEngine<TEntity>(_streamMergeContext, sequenceFullMatchOrderConfig, _shardingPageManager.Current.RouteQueryResults, primaryOrder.IsAsc);
}
}
//自动添加属性顺序排序
//除了判断属性名还要判断所属关系
var mergeEngine = DoNoOrderAppendEnumeratorStreamMergeEngine(shardingEntityType);
if (mergeEngine != null)
return mergeEngine;
}
else
{
var mergeEngine = DoOrderSequencePaginationEnumeratorStreamMergeEngine(shardingEntityType);
var sequencePrimaryMatchOrderConfig = paginationMetadata.PaginationConfigs.Where(o => o.PaginationMatchEnum.HasFlag(PaginationMatchEnum.PrimaryMatch)).FirstOrDefault(o => PaginationPrimaryMatch(o, primaryOrder));
if (sequencePrimaryMatchOrderConfig != null)
{
return new SequenceEnumeratorAsyncStreamMergeEngine<TEntity>(_streamMergeContext, sequencePrimaryMatchOrderConfig, _shardingPageManager.Current.RouteQueryResults, primaryOrder.IsAsc);
}
if (mergeEngine != null)
return mergeEngine;
//skip过大reserve skip
if (paginationMetadata.EnableReverseShardingPage && _streamMergeContext.Take.GetValueOrDefault() > 0)
{
var total = _shardingPageManager.Current.RouteQueryResults.Sum(o => o.QueryResult);
if (paginationMetadata.IsUseReverse(_streamMergeContext.Skip.GetValueOrDefault(), total))
{
return new ReverseShardingEnumeratorAsyncStreamMergeEngine<TEntity>( _streamMergeContext, total);
}
}
//if (paginationMetadata.EnableUnevenShardingPage)
//{
// if (paginationMetadata.IsUseUneven(_shardingPageManager.Current.RouteQueryResults, _streamMergeContext.Skip.GetValueOrDefault()))
// {
//if (paginationMetadata.EnableUnevenShardingPage)
//{
// if (paginationMetadata.IsUseUneven(_shardingPageManager.Current.RouteQueryResults, _streamMergeContext.Skip.GetValueOrDefault()))
// {
// }
//}
}
// }
//}
}
}
return new DefaultShardingEnumeratorAsyncStreamMergeEngine<TEntity>(_streamMergeContext);
return new DefaultShardingEnumeratorAsyncStreamMergeEngine<TShardingDbContext, TEntity>(_streamMergeContext);
}
private IEnumeratorStreamMergeEngine<TEntity> DoNoOrderAppendEnumeratorStreamMergeEngine(Type shardingEntityType)
{
var isShardingDataSource = shardingEntityType.IsShardingDataSource();
var isShardingTable = shardingEntityType.IsShardingTable();
PaginationSequenceConfig dataSourceSequenceOrderConfig = null;
PaginationSequenceConfig tableSequenceOrderConfig = null;
if (isShardingDataSource)
{
var virtualDataSourceRoute = _virtualDataSource.GetRoute(shardingEntityType);
if (virtualDataSourceRoute.EnablePagination)
{
dataSourceSequenceOrderConfig = virtualDataSourceRoute.PaginationMetadata.PaginationConfigs.OrderByDescending(o => o.AppendOrder)
.FirstOrDefault(o => o.AppendIfOrderNone && typeof(TEntity).ContainPropertyName(o.PropertyName) && PaginationMatch(o));
}
}
if (isShardingTable)
{
var virtualTable = _virtualTableManager.GetVirtualTable(shardingEntityType);
if (virtualTable.EnablePagination)
{
tableSequenceOrderConfig = virtualTable.PaginationMetadata.PaginationConfigs.OrderByDescending(o => o.AppendOrder)
.FirstOrDefault(o => o.AppendIfOrderNone && typeof(TEntity).ContainPropertyName(o.PropertyName) && PaginationMatch(o));
}
}
if (dataSourceSequenceOrderConfig != null || tableSequenceOrderConfig != null)
{
return new AppenOrderSequenceEnumeratorAsyncStreamMergeEngine<TShardingDbContext, TEntity>(_streamMergeContext, dataSourceSequenceOrderConfig, tableSequenceOrderConfig, _shardingPageManager.Current.RouteQueryResults);
}
return null;
}
private IEnumeratorStreamMergeEngine<TEntity> DoOrderSequencePaginationEnumeratorStreamMergeEngine(Type shardingEntityType)
{
var orderCount = _streamMergeContext.Orders.Count();
var primaryOrder = _streamMergeContext.Orders.First();
var isShardingDataSource = shardingEntityType.IsShardingDataSource();
var isShardingTable = shardingEntityType.IsShardingTable();
PaginationSequenceConfig dataSourceSequenceOrderConfig = null;
PaginationSequenceConfig tableSequenceOrderConfig = null;
IVirtualDataSourceRoute virtualDataSourceRoute = null;
IVirtualTable virtualTable = null;
bool dataSourceUseReverse = true;
bool tableUseReverse = true;
if (isShardingDataSource)
{
virtualDataSourceRoute = _virtualDataSource.GetRoute(shardingEntityType);
if (virtualDataSourceRoute.EnablePagination)
{
dataSourceSequenceOrderConfig = orderCount == 1 ? GetPaginationFullMatch(virtualDataSourceRoute.PaginationMetadata.PaginationConfigs, primaryOrder) : GetPaginationPrimaryMatch(virtualDataSourceRoute.PaginationMetadata.PaginationConfigs, primaryOrder);
}
}
if (isShardingTable)
{
virtualTable = _virtualTableManager.GetVirtualTable(shardingEntityType);
if (virtualTable.EnablePagination)
{
tableSequenceOrderConfig = orderCount == 1 ? GetPaginationFullMatch(virtualTable.PaginationMetadata.PaginationConfigs, primaryOrder) : GetPaginationPrimaryMatch(virtualTable.PaginationMetadata.PaginationConfigs, primaryOrder);
}
}
if (dataSourceSequenceOrderConfig != null || tableSequenceOrderConfig != null)
{
return new SequenceEnumeratorAsyncStreamMergeEngine<TShardingDbContext, TEntity>(_streamMergeContext, dataSourceSequenceOrderConfig, tableSequenceOrderConfig, _shardingPageManager.Current.RouteQueryResults, primaryOrder.IsAsc);
}
var total = _shardingPageManager.Current.RouteQueryResults.Sum(o => o.QueryResult);
if (isShardingDataSource&& virtualDataSourceRoute.EnablePagination)
{
dataSourceUseReverse =
EntityDataSourceUseReverseShardingPage(virtualDataSourceRoute, total);
}
if (isShardingTable && virtualTable.EnablePagination)
{
tableUseReverse =
EntityTableReverseShardingPage(virtualTable, total);
}
//skip过大reserve skip
if (dataSourceUseReverse && tableUseReverse)
{
return new ReverseShardingEnumeratorAsyncStreamMergeEngine<TEntity>(_streamMergeContext, total);
}
return null;
}
private bool EntityDataSourceUseReverseShardingPage( IVirtualDataSourceRoute virtualDataSourceRoute,long total)
{
if (virtualDataSourceRoute.PaginationMetadata.EnableReverseShardingPage && _streamMergeContext.Take.GetValueOrDefault() > 0)
{
if (virtualDataSourceRoute.PaginationMetadata.IsUseReverse(_streamMergeContext.Skip.GetValueOrDefault(), total))
{
return true;
}
}
return false;
}
private bool EntityTableReverseShardingPage( IVirtualTable virtualTable, long total)
{
if (virtualTable.PaginationMetadata.EnableReverseShardingPage && _streamMergeContext.Take.GetValueOrDefault() > 0)
{
if (virtualTable.PaginationMetadata.IsUseReverse(_streamMergeContext.Skip.GetValueOrDefault(), total))
{
return true;
}
}
return false;
}
private PaginationSequenceConfig GetPaginationFullMatch(ISet<PaginationSequenceConfig> paginationSequenceConfigs, PropertyOrder primaryOrder)
{
return paginationSequenceConfigs.Where(o => !o.PaginationMatchEnum.HasFlag(PaginationMatchEnum.PrimaryMatch)).FirstOrDefault(o => PaginationPrimaryMatch(o, primaryOrder));
}
private PaginationSequenceConfig GetPaginationPrimaryMatch(ISet<PaginationSequenceConfig> paginationSequenceConfigs, PropertyOrder primaryOrder)
{
return paginationSequenceConfigs.Where(o => o.PaginationMatchEnum.HasFlag(PaginationMatchEnum.PrimaryMatch)).FirstOrDefault(o => PaginationPrimaryMatch(o, primaryOrder));
}
private bool PaginationMatch(PaginationSequenceConfig paginationSequenceConfig)

View File

@ -1,3 +1,4 @@
using System;
using Microsoft.EntityFrameworkCore;
using ShardingCore.Core.Internal.StreamMerge.ReWrite;
using ShardingCore.Core.Internal.Visitors;
@ -39,6 +40,10 @@ namespace ShardingCore.Sharding
public GroupByContext GroupByContext { get; }
public IEnumerable<TableRouteResult> TableRouteResults { get; }
public DataSourceRouteResult DataSourceRouteResult { get; }
/// <summary>
/// 本次查询涉及的对象
/// </summary>
public ISet<Type> QueryEntities { get; }
public StreamMergeContext(IQueryable<T> source,IShardingDbContext shardingDbContext,
DataSourceRouteResult dataSourceRouteResult,
@ -56,6 +61,7 @@ namespace ShardingCore.Sharding
SelectContext = reWriteResult.SelectContext;
GroupByContext = reWriteResult.GroupByContext;
_reWriteSource = reWriteResult.ReWriteQueryable;
QueryEntities = source.ParseQueryableRoute();
DataSourceRouteResult = dataSourceRouteResult;
TableRouteResults= tableRouteResults;
//RouteResults = _tableTableRouteRuleEngineFactory.Route(_shardingDbContext.ShardingDbContextType, _source);

View File

@ -2,6 +2,8 @@ using ShardingCore.Sharding.ShardingQueryExecutors;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using Microsoft.EntityFrameworkCore;
using ShardingCore.Sharding.Abstractions;
namespace ShardingCore.Sharding.StreamMergeEngines
{
@ -11,7 +13,8 @@ namespace ShardingCore.Sharding.StreamMergeEngines
* @Date: Saturday, 14 August 2021 22:07:28
* @Email: 326308290@qq.com
*/
public class AsyncEnumerableStreamMergeEngine<T> : IAsyncEnumerable<T>, IEnumerable<T>
public class AsyncEnumerableStreamMergeEngine<TShardingDbContext,T> : IAsyncEnumerable<T>, IEnumerable<T>
where TShardingDbContext:DbContext,IShardingDbContext
{
private readonly StreamMergeContext<T> _mergeContext;
@ -24,7 +27,7 @@ namespace ShardingCore.Sharding.StreamMergeEngines
#if !EFCORE2
public IAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = new CancellationToken())
{
return new EnumeratorShardingQueryExecutor<T>(_mergeContext).ExecuteAsync(cancellationToken)
return new EnumeratorShardingQueryExecutor<TShardingDbContext,T>(_mergeContext).ExecuteAsync(cancellationToken)
.GetAsyncEnumerator(cancellationToken);
}
#endif
@ -32,7 +35,7 @@ namespace ShardingCore.Sharding.StreamMergeEngines
#if EFCORE2
IAsyncEnumerator<T> IAsyncEnumerable<T>.GetEnumerator()
{
return ((IAsyncEnumerable<T>)new EnumeratorShardingQueryExecutor<T>(_mergeContext).ExecuteAsync())
return ((IAsyncEnumerable<T>)new EnumeratorShardingQueryExecutor<TShardingDbContext,T>(_mergeContext).ExecuteAsync())
.GetEnumerator();
}
#endif
@ -41,7 +44,7 @@ namespace ShardingCore.Sharding.StreamMergeEngines
public IEnumerator<T> GetEnumerator()
{
return ((IEnumerable<T>)new EnumeratorShardingQueryExecutor<T>(_mergeContext).ExecuteAsync())
return ((IEnumerable<T>)new EnumeratorShardingQueryExecutor<TShardingDbContext,T>(_mergeContext).ExecuteAsync())
.GetEnumerator();
}

View File

@ -3,9 +3,12 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using ShardingCore.Core.Internal.Visitors;
using ShardingCore.Exceptions;
using ShardingCore.Extensions;
using ShardingCore.Extensions.InternalExtensions;
using ShardingCore.Sharding.Abstractions;
using ShardingCore.Sharding.Enumerators;
using ShardingCore.Sharding.Enumerators.StreamMergeAsync;
using ShardingCore.Sharding.PaginationConfigurations;
@ -21,13 +24,16 @@ namespace ShardingCore.Sharding.StreamMergeEngines.EnumeratorStreamMergeEngines.
* @Ver: 1.0
* @Email: 326308290@qq.com
*/
public class AppenOrderSequenceEnumeratorAsyncStreamMergeEngine<TEntity> : AbstractEnumeratorAsyncStreamMergeEngine<TEntity>
public class AppenOrderSequenceEnumeratorAsyncStreamMergeEngine<TShardingDbContext,TEntity> : AbstractEnumeratorAsyncStreamMergeEngine<TEntity>
where TShardingDbContext : DbContext, IShardingDbContext
{
private readonly PaginationSequenceConfig _appendPaginationSequenceConfig;
private readonly PaginationSequenceConfig _dataSourceSequenceOrderConfig;
private readonly PaginationSequenceConfig _tableSequenceOrderConfig;
private readonly ICollection<RouteQueryResult<long>> _routeQueryResults;
public AppenOrderSequenceEnumeratorAsyncStreamMergeEngine(StreamMergeContext<TEntity> streamMergeContext, PaginationSequenceConfig appendPaginationSequenceConfig, ICollection<RouteQueryResult<long>> routeQueryResults) : base(streamMergeContext)
public AppenOrderSequenceEnumeratorAsyncStreamMergeEngine(StreamMergeContext<TEntity> streamMergeContext, PaginationSequenceConfig dataSourceSequenceOrderConfig, PaginationSequenceConfig tableSequenceOrderConfig, ICollection<RouteQueryResult<long>> routeQueryResults) : base(streamMergeContext)
{
_appendPaginationSequenceConfig = appendPaginationSequenceConfig;
_dataSourceSequenceOrderConfig = dataSourceSequenceOrderConfig;
_tableSequenceOrderConfig = tableSequenceOrderConfig;
_routeQueryResults = routeQueryResults;
}
@ -44,17 +50,60 @@ namespace ShardingCore.Sharding.StreamMergeEngines.EnumeratorStreamMergeEngines.
var sortRouteResults = _routeQueryResults.Select(o => new
{
DataSourceName=o.DataSourceName,
Tail = o.TableRouteResult.ReplaceTables.First().Tail,
RouteQueryResult = o
}).OrderBy(o => o.Tail, _appendPaginationSequenceConfig.TailComparer).ToList();
var skipCount = skip;
});
//分库是主要排序
var dataSourceOrderMain = _dataSourceSequenceOrderConfig != null;
var reSetOrders = new List<PropertyOrder>();
if (dataSourceOrderMain)
{
//if sharding data source
var appendAsc = _dataSourceSequenceOrderConfig.AppendAsc;
//if sharding table
var useThenBy = dataSourceOrderMain && _tableSequenceOrderConfig != null;
if (appendAsc)
{
sortRouteResults = sortRouteResults.OrderBy(o => o.DataSourceName,
_dataSourceSequenceOrderConfig.RouteComparer)
.ThenByIf(o => o.Tail, useThenBy&& _tableSequenceOrderConfig.AppendAsc, _tableSequenceOrderConfig.RouteComparer)
.ThenByDescendingIf(o => o.Tail, useThenBy&& !_tableSequenceOrderConfig.AppendAsc, _tableSequenceOrderConfig.RouteComparer);
}
else
{
sortRouteResults = sortRouteResults.OrderByDescending(o => o.DataSourceName,
_dataSourceSequenceOrderConfig.RouteComparer).ThenByDescendingIf(o => o.Tail, useThenBy, _tableSequenceOrderConfig.RouteComparer);
}
reSetOrders.Add(new PropertyOrder(_dataSourceSequenceOrderConfig.PropertyName, _dataSourceSequenceOrderConfig.AppendAsc));
if (useThenBy)
{
reSetOrders.Add(new PropertyOrder(_tableSequenceOrderConfig.PropertyName, _tableSequenceOrderConfig.AppendAsc));
}
}
else
{
var appendAsc = _tableSequenceOrderConfig.AppendAsc;
if (appendAsc)
{
sortRouteResults = sortRouteResults.OrderBy(o => o.Tail, _tableSequenceOrderConfig.RouteComparer);
}
else
{
sortRouteResults =
sortRouteResults.OrderByDescending(o => o.Tail, _tableSequenceOrderConfig.RouteComparer);
}
reSetOrders.Add(new PropertyOrder(_tableSequenceOrderConfig.PropertyName, _tableSequenceOrderConfig.AppendAsc));
}
var sequenceResults = new SequencePaginationList(sortRouteResults.Select(o=>o.RouteQueryResult)).Skip(skip).Take(take).ToList();
StreamMergeContext.ReSetOrders(new [] { new PropertyOrder(_appendPaginationSequenceConfig.PropertyName, true) });
StreamMergeContext.ReSetOrders(reSetOrders);
var enumeratorTasks = sequenceResults.Select(sequenceResult =>
{
var newQueryable = CreateAsyncExecuteQueryable(sequenceResult.DSName,noPaginationQueryable, sequenceResult);
var newQueryable = CreateAsyncExecuteQueryable(sequenceResult.DSName,noPaginationQueryable, sequenceResult, reSetOrders);
return AsyncQueryEnumerator(newQueryable,async);
}).ToArray();
@ -62,11 +111,11 @@ namespace ShardingCore.Sharding.StreamMergeEngines.EnumeratorStreamMergeEngines.
return streamEnumerators;
}
private IQueryable<TEntity> CreateAsyncExecuteQueryable(string dsname,IQueryable<TEntity> noPaginationQueryable, SequenceResult sequenceResult)
private IQueryable<TEntity> CreateAsyncExecuteQueryable(string dsname,IQueryable<TEntity> noPaginationQueryable, SequenceResult sequenceResult,IEnumerable<PropertyOrder> reSetOrders)
{
var shardingDbContext = StreamMergeContext.CreateDbContext(dsname,sequenceResult.TableRouteResult);
DbContextQueryStore.TryAdd(sequenceResult.TableRouteResult, shardingDbContext);
var newQueryable = (IQueryable<TEntity>)(noPaginationQueryable.Skip(sequenceResult.Skip).Take(sequenceResult.Take).OrderWithExpression(new PropertyOrder[]{new PropertyOrder(_appendPaginationSequenceConfig.PropertyName,true)}))
var newQueryable = (IQueryable<TEntity>)(noPaginationQueryable.Skip(sequenceResult.Skip).Take(sequenceResult.Take).OrderWithExpression(reSetOrders))
.ReplaceDbContextQueryable(shardingDbContext);
return newQueryable;
}

View File

@ -1,8 +1,10 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using ShardingCore.Core.VirtualRoutes.TableRoutes.RoutingRuleEngine;
using ShardingCore.Extensions;
using ShardingCore.Sharding.Abstractions;
using ShardingCore.Sharding.Enumerators;
using ShardingCore.Sharding.Enumerators.StreamMergeAsync;
using ShardingCore.Sharding.StreamMergeEngines.EnumeratorStreamMergeEngines.Abstractions;
@ -16,7 +18,8 @@ namespace ShardingCore.Sharding.StreamMergeEngines.EnumeratorStreamMergeEngines.
* @Ver: 1.0
* @Email: 326308290@qq.com
*/
public class DefaultShardingEnumeratorAsyncStreamMergeEngine<TEntity>:AbstractEnumeratorAsyncStreamMergeEngine<TEntity>
public class DefaultShardingEnumeratorAsyncStreamMergeEngine<TShardingDbContext,TEntity> :AbstractEnumeratorAsyncStreamMergeEngine<TEntity>
where TShardingDbContext : DbContext, IShardingDbContext
{
public DefaultShardingEnumeratorAsyncStreamMergeEngine(StreamMergeContext<TEntity> streamMergeContext) : base(streamMergeContext)
{

View File

@ -2,10 +2,12 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using ShardingCore.Core.Internal.Visitors;
using ShardingCore.Core.VirtualRoutes.TableRoutes.RoutingRuleEngine;
using ShardingCore.Exceptions;
using ShardingCore.Extensions;
using ShardingCore.Sharding.Abstractions;
using ShardingCore.Sharding.Enumerators;
using ShardingCore.Sharding.Enumerators.StreamMergeAsync;
using ShardingCore.Sharding.StreamMergeEngines.EnumeratorStreamMergeEngines.Abstractions;

View File

@ -2,9 +2,11 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using ShardingCore.Exceptions;
using ShardingCore.Extensions;
using ShardingCore.Extensions.InternalExtensions;
using ShardingCore.Sharding.Abstractions;
using ShardingCore.Sharding.Enumerators;
using ShardingCore.Sharding.Enumerators.StreamMergeAsync;
using ShardingCore.Sharding.PaginationConfigurations;
@ -20,14 +22,17 @@ namespace ShardingCore.Sharding.StreamMergeEngines.EnumeratorStreamMergeEngines.
* @Ver: 1.0
* @Email: 326308290@qq.com
*/
public class SequenceEnumeratorAsyncStreamMergeEngine<TEntity> : AbstractEnumeratorAsyncStreamMergeEngine<TEntity>
public class SequenceEnumeratorAsyncStreamMergeEngine<TShardingDbContext,TEntity> : AbstractEnumeratorAsyncStreamMergeEngine<TEntity>
where TShardingDbContext : DbContext, IShardingDbContext
{
private readonly PaginationSequenceConfig _orderPaginationSequenceConfig;
private readonly PaginationSequenceConfig _dataSourceSequenceMatchOrderConfig;
private readonly PaginationSequenceConfig _tableSequenceMatchOrderConfig;
private readonly ICollection<RouteQueryResult<long>> _routeQueryResults;
private readonly bool _isAsc;
public SequenceEnumeratorAsyncStreamMergeEngine(StreamMergeContext<TEntity> streamMergeContext, PaginationSequenceConfig orderPaginationSequenceConfig, ICollection<RouteQueryResult<long>> routeQueryResults, bool isAsc) : base(streamMergeContext)
public SequenceEnumeratorAsyncStreamMergeEngine(StreamMergeContext<TEntity> streamMergeContext, PaginationSequenceConfig dataSourceSequenceMatchOrderConfig, PaginationSequenceConfig tableSequenceMatchOrderConfig, ICollection<RouteQueryResult<long>> routeQueryResults, bool isAsc) : base(streamMergeContext)
{
_orderPaginationSequenceConfig = orderPaginationSequenceConfig;
_dataSourceSequenceMatchOrderConfig = dataSourceSequenceMatchOrderConfig;
_tableSequenceMatchOrderConfig = tableSequenceMatchOrderConfig;
_routeQueryResults = routeQueryResults;
_isAsc = isAsc;
}
@ -42,13 +47,43 @@ namespace ShardingCore.Sharding.StreamMergeEngines.EnumeratorStreamMergeEngines.
var take = StreamMergeContext.Take;
if (take.HasValue && take.Value <= 0)
throw new ShardingCoreException("take must gt 0");
//分库是主要排序
var dataSourceOrderMain = _dataSourceSequenceMatchOrderConfig != null;
var sortRouteResults = _routeQueryResults.Select(o => new
{
DataSourceName=o.DataSourceName,
Tail = o.TableRouteResult.ReplaceTables.First().Tail,
RouteQueryResult = o
}).OrderByIf(o => o.Tail, _isAsc, _orderPaginationSequenceConfig.TailComparer)
.OrderByDescendingIf(o => o.Tail, !_isAsc, _orderPaginationSequenceConfig.TailComparer).ToList();
});
if (dataSourceOrderMain)
{
//是否有两级排序
var useThenBy = dataSourceOrderMain && _tableSequenceMatchOrderConfig != null;
if (_isAsc)
{
sortRouteResults = sortRouteResults.OrderBy(o => o.DataSourceName,
_dataSourceSequenceMatchOrderConfig.RouteComparer).ThenByIf(o=>o.Tail, useThenBy, _tableSequenceMatchOrderConfig.RouteComparer);
}
else
{
sortRouteResults = sortRouteResults.OrderByDescending(o => o.DataSourceName,
_dataSourceSequenceMatchOrderConfig.RouteComparer).ThenByDescendingIf(o => o.Tail, useThenBy, _tableSequenceMatchOrderConfig.RouteComparer);
}
}
else
{
if (_isAsc)
{
sortRouteResults =
sortRouteResults.OrderBy(o => o.Tail, _tableSequenceMatchOrderConfig.RouteComparer);
}
else
{
sortRouteResults =
sortRouteResults.OrderByDescending(o => o.Tail, _tableSequenceMatchOrderConfig.RouteComparer);
}
}
var sequenceResults = new SequencePaginationList(sortRouteResults.Select(o => o.RouteQueryResult)).Skip(skip).Take(take).ToList();

View File

@ -1,6 +1,8 @@
using System.Linq;
using Microsoft.EntityFrameworkCore;
using ShardingCore.Exceptions;
using ShardingCore.Extensions;
using ShardingCore.Sharding.Abstractions;
using ShardingCore.Sharding.Enumerators;
using ShardingCore.Sharding.StreamMergeEngines.EnumeratorStreamMergeEngines.Abstractions;
@ -12,7 +14,8 @@ namespace ShardingCore.Sharding.StreamMergeEngines.EnumeratorStreamMergeEngines.
* @Date: Thursday, 02 September 2021 20:58:10
* @Email: 326308290@qq.com
*/
public class SingleQueryEnumeratorAsyncStreamMergeEngine<TEntity> : AbstractEnumeratorAsyncStreamMergeEngine<TEntity>
public class SingleQueryEnumeratorAsyncStreamMergeEngine<TShardingDbContext, TEntity> : AbstractEnumeratorAsyncStreamMergeEngine<TEntity>
where TShardingDbContext : DbContext, IShardingDbContext
{
public SingleQueryEnumeratorAsyncStreamMergeEngine(StreamMergeContext<TEntity> streamMergeContext) : base(streamMergeContext)
{
@ -41,7 +44,7 @@ namespace ShardingCore.Sharding.StreamMergeEngines.EnumeratorStreamMergeEngines.
public override IStreamMergeAsyncEnumerator<TEntity> GetStreamMergeAsyncEnumerator(IStreamMergeAsyncEnumerator<TEntity>[] streamsAsyncEnumerators)
{
if (streamsAsyncEnumerators.Length != 1)
throw new ShardingCoreException($"{nameof(SingleQueryEnumeratorAsyncStreamMergeEngine<TEntity>)} has more {nameof(IStreamMergeAsyncEnumerator<TEntity>)}");
throw new ShardingCoreException($"{nameof(SingleQueryEnumeratorAsyncStreamMergeEngine<TShardingDbContext,TEntity>)} has more {nameof(IStreamMergeAsyncEnumerator<TEntity>)}");
return streamsAsyncEnumerators[0];
}
}

View File

@ -77,6 +77,7 @@ namespace ShardingCore
{
var routeType = _shardingConfigOption.GetVirtualDataSourceRouteType(entityType);
var virtualRoute = CreateVirtualDataSourceRoute(routeType);
virtualRoute.Init();
virtualDataSource.AddVirtualDataSourceRoute(virtualRoute);
}
if (entityType.IsShardingTable())

View File

@ -1,32 +1,45 @@
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using ShardingCore.Core;
using ShardingCore.Core.VirtualRoutes;
using ShardingCore.Core.VirtualRoutes.TableRoutes;
using ShardingCore.Core.VirtualRoutes.TableRoutes.Abstractions;
namespace ShardingCore.VirtualRoutes.Abstractions
{
/*
* @Author: xjm
* @Description:
* @Date: Wednesday, 27 January 2021 12:29:19
* @Email: 326308290@qq.com
*/
public abstract class AbstractShardingTimeKeyDateTimeVirtualTableRoute<T>:AbstractShardingOperatorVirtualTableRoute<T,DateTime> where T:class,IShardingTable
/*
* @Author: xjm
* @Description:sharding table route by date time
* @Date: Wednesday, 27 January 2021 12:29:19
* @Email: 326308290@qq.com
*/
/// <summary>
/// time type is date time
/// </summary>
/// <typeparam name="T"></typeparam>
public abstract class AbstractShardingTimeKeyDateTimeVirtualTableRoute<T> : AbstractShardingOperatorVirtualTableRoute<T, DateTime> where T : class, IShardingTable
{
/// <summary>
/// how convert object to date time
/// </summary>
/// <param name="shardingKey"></param>
/// <returns></returns>
protected override DateTime ConvertToShardingKey(object shardingKey)
{
return Convert.ToDateTime(shardingKey);
}
/// <summary>
/// how convert sharding key to tail
/// </summary>
/// <param name="shardingKey"></param>
/// <returns></returns>
public override string ShardingKeyToTail(object shardingKey)
{
var time = ConvertToShardingKey(shardingKey);
return TimeFormatToTail(time);
}
/// <summary>
/// how format date time to tail
/// </summary>
/// <param name="time"></param>
/// <returns></returns>
protected abstract string TimeFormatToTail(DateTime time);
}

View File

@ -1,31 +1,44 @@
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using ShardingCore.Core;
using ShardingCore.Core.VirtualRoutes;
using ShardingCore.Core.VirtualRoutes.TableRoutes;
using ShardingCore.Core.VirtualRoutes.TableRoutes.Abstractions;
namespace ShardingCore.VirtualRoutes.Abstractions
{
/*
* @Author: xjm
* @Description:
* @Description: sharding table route by time stamp (ms)
* @Date: Wednesday, 27 January 2021 13:06:01
* @Email: 326308290@qq.com
*/
/// <summary>
/// sharding table route by time stamp (ms)
/// </summary>
/// <typeparam name="T">entity</typeparam>
public abstract class AbstractShardingTimeKeyLongVirtualTableRoute<T> : AbstractShardingOperatorVirtualTableRoute<T, long> where T : class, IShardingTable
{
/// <summary>
/// how convert object to long
/// </summary>
/// <param name="shardingKey"></param>
/// <returns></returns>
protected override long ConvertToShardingKey(object shardingKey)
{
return (long)shardingKey;
}
/// <summary>
/// how convert sharding key to tail
/// </summary>
/// <param name="shardingKey"></param>
/// <returns></returns>
public override string ShardingKeyToTail(object shardingKey)
{
var time = ConvertToShardingKey(shardingKey);
return TimeFormatToTail(time);
}
/// <summary>
/// how format long time to tail
/// </summary>
/// <param name="time"></param>
/// <returns></returns>
protected abstract string TimeFormatToTail(long time);
}

View File

@ -1,9 +1,9 @@
using ShardingCore.Core;
using ShardingCore.Core.VirtualRoutes;
using ShardingCore.VirtualRoutes.Abstractions;
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using ShardingCore.Core;
using ShardingCore.Core.VirtualRoutes;
using ShardingCore.VirtualRoutes.Abstractions;
namespace ShardingCore.VirtualRoutes.Days
{
@ -15,7 +15,15 @@ namespace ShardingCore.VirtualRoutes.Days
*/
public abstract class AbstractSimpleShardingDayKeyDateTimeVirtualTableRoute<T>:AbstractShardingTimeKeyDateTimeVirtualTableRoute<T> where T:class,IShardingTable
{
/// <summary>
/// begin time use fixed time eg.new DateTime(20xx,xx,xx)
/// </summary>
/// <returns></returns>
public abstract DateTime GetBeginTime();
/// <summary>
/// return all tails in database
/// </summary>
/// <returns></returns>
public override List<string> GetAllTails()
{
var beginTime = GetBeginTime();
@ -24,7 +32,7 @@ namespace ShardingCore.VirtualRoutes.Days
//提前创建表
var nowTimeStamp = DateTime.Now.AddDays(1).Date;
if (beginTime > nowTimeStamp)
throw new ArgumentException("起始时间不正确无法生成正确的表名");
throw new ArgumentException("begin time error");
var currentTimeStamp = beginTime;
while (currentTimeStamp <= nowTimeStamp)
{

View File

@ -26,7 +26,7 @@ namespace ShardingCore.VirtualRoutes.Days
//提前创建表
var nowTimeStamp = DateTime.Now.AddDays(1).Date;
if (beginTime > nowTimeStamp)
throw new ArgumentException("起始时间不正确无法生成正确的表名");
throw new ArgumentException("begin time error");
var currentTimeStamp = beginTime;
while (currentTimeStamp <= nowTimeStamp)
{

View File

@ -4,7 +4,6 @@ using System.Linq;
using System.Linq.Expressions;
using ShardingCore.Core;
using ShardingCore.Core.VirtualRoutes;
using ShardingCore.Core.VirtualRoutes.TableRoutes;
using ShardingCore.Core.VirtualRoutes.TableRoutes.Abstractions;
namespace ShardingCore.VirtualRoutes.Mods
@ -19,7 +18,7 @@ namespace ShardingCore.VirtualRoutes.Mods
/// 分表字段为int的取模分表
/// </summary>
/// <typeparam name="T"></typeparam>
public abstract class AbstractSimpleShardingModKeyIntVirtualTableRoute<T>:AbstractShardingOperatorVirtualTableRoute<T,int> where T:class,IShardingTable
public abstract class AbstractSimpleShardingModKeyIntVirtualTableRoute<T>: AbstractShardingOperatorVirtualTableRoute<T,int> where T:class,IShardingTable
{
protected readonly int Mod;
protected readonly int TailLength;

View File

@ -4,7 +4,6 @@ using System.Linq;
using System.Linq.Expressions;
using ShardingCore.Core;
using ShardingCore.Core.VirtualRoutes;
using ShardingCore.Core.VirtualRoutes.TableRoutes;
using ShardingCore.Core.VirtualRoutes.TableRoutes.Abstractions;
using ShardingCore.Helpers;
@ -20,7 +19,7 @@ namespace ShardingCore.VirtualRoutes.Mods
/// 分表字段为string的取模分表
/// </summary>
/// <typeparam name="T"></typeparam>
public abstract class AbstractSimpleShardingModKeyStringVirtualTableRoute<T>:AbstractShardingOperatorVirtualTableRoute<T,string> where T:class,IShardingTable
public abstract class AbstractSimpleShardingModKeyStringVirtualTableRoute<T>: AbstractShardingOperatorVirtualTableRoute<T,string> where T:class,IShardingTable
{
protected readonly int Mod;
protected readonly int TailLength;

View File

@ -25,7 +25,7 @@ namespace ShardingCore.VirtualRoutes.Months
//提前创建表
var nowTimeStamp =ShardingCoreHelper.GetNextMonthFirstDay(DateTime.Now);
if (beginTime > nowTimeStamp)
throw new ArgumentException("起始时间不正确无法生成正确的表名");
throw new ArgumentException("begin time error");
var currentTimeStamp = beginTime;
while (currentTimeStamp <= nowTimeStamp)
{

View File

@ -25,7 +25,7 @@ namespace ShardingCore.VirtualRoutes.Months
//提前创建表
var nowTimeStamp =ShardingCoreHelper.GetNextMonthFirstDay(DateTime.Now);
if (beginTime > nowTimeStamp)
throw new ArgumentException("起始时间不正确无法生成正确的表名");
throw new ArgumentException("begin time error");
var currentTimeStamp = beginTime;
while (currentTimeStamp <= nowTimeStamp)
{

View File

@ -25,7 +25,7 @@ namespace ShardingCore.VirtualRoutes.Weeks
//提前创建表
var nowTimeStamp = DateTime.Now.AddDays(7).Date;
if (beginTime > nowTimeStamp)
throw new ArgumentException("起始时间不正确无法生成正确的表名");
throw new ArgumentException("begin time error");
var currentTimeStamp = beginTime;
while (currentTimeStamp <= nowTimeStamp)
{

View File

@ -25,7 +25,7 @@ namespace ShardingCore.VirtualRoutes.Weeks
//提前创建表
var nowTimeStamp = DateTime.Now.AddDays(7).Date;
if (beginTime > nowTimeStamp)
throw new ArgumentException("起始时间不正确无法生成正确的表名");
throw new ArgumentException("begin time error");
var currentTimeStamp = beginTime;
while (currentTimeStamp <= nowTimeStamp)
{

View File

@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.Linq.Expressions;
using ShardingCore.Core;
using ShardingCore.Core.VirtualRoutes;
using ShardingCore.Helpers;
using ShardingCore.VirtualRoutes.Abstractions;
namespace ShardingCore.VirtualRoutes.Years
@ -25,7 +24,7 @@ namespace ShardingCore.VirtualRoutes.Years
//提前创建表
var nowTimeStamp = DateTime.Now.AddYears(1).Date;
if (beginTime > nowTimeStamp)
throw new ArgumentException("起始时间不正确无法生成正确的表名");
throw new ArgumentException("begin time error");
var currentTimeStamp = beginTime;
while (currentTimeStamp <= nowTimeStamp)
{

View File

@ -25,7 +25,7 @@ namespace ShardingCore.VirtualRoutes.Years
//提前创建表
var nowTimeStamp = DateTime.Now.AddYears(1).Date;
if (beginTime > nowTimeStamp)
throw new ArgumentException("起始时间不正确无法生成正确的表名");
throw new ArgumentException("begin time error");
var currentTimeStamp = beginTime;
while (currentTimeStamp <= nowTimeStamp)
{

View File

@ -52,7 +52,7 @@ namespace ShardingCore.Test50
{
using (_shardingRouteManager.CreateScope())
{
_shardingRouteManager.Current.Must.TryAdd(typeof(SysUserMod), new HashSet<string>() { "00" });
_shardingRouteManager.Current.MustTable.TryAdd(typeof(SysUserMod), new HashSet<string>() { "00" });
var mod00s = await _virtualDbContext.Set<SysUserMod>().ToListAsync();
Assert.Equal(333, mod00s.Count);

View File

@ -1,19 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using ShardingCore.Core.VirtualRoutes;
using ShardingCore.Test50.Domain.Entities;
using ShardingCore.VirtualRoutes;
using ShardingCore.VirtualRoutes.Mods;
namespace ShardingCore.Test50.Shardings
{
/*
* @Author: xjm
* @Description:
* @Date: Thursday, 14 January 2021 15:39:27
* @Email: 326308290@qq.com
*/
/*
* @Author: xjm
* @Description:
* @Date: Thursday, 14 January 2021 15:39:27
* @Email: 326308290@qq.com
*/
public class SysUserModVirtualTableRoute : AbstractSimpleShardingModKeyStringVirtualTableRoute<SysUserMod>
{
protected override bool EnableHintRoute => true;

View File

@ -48,7 +48,7 @@ namespace ShardingCore.Test50_2x
{
using (_shardingRouteManager.CreateScope())
{
_shardingRouteManager.Current.Must.TryAdd(typeof(SysUserMod), new HashSet<string>() { "00" });
_shardingRouteManager.Current.MustTable.TryAdd(typeof(SysUserMod), new HashSet<string>() { "00" });
var mod00s = await _virtualDbContext.Set<SysUserMod>().ToListAsync();
Assert.Equal(333, mod00s.Count);

View File

@ -48,7 +48,7 @@ namespace ShardingCore.Test50_3x
{
using (_shardingRouteManager.CreateScope())
{
_shardingRouteManager.Current.Must.TryAdd(typeof(SysUserMod), new HashSet<string>() { "00" });
_shardingRouteManager.Current.MustTable.TryAdd(typeof(SysUserMod), new HashSet<string>() { "00" });
var mod00s = await _virtualDbContext.Set<SysUserMod>().ToListAsync();
Assert.Equal(333, mod00s.Count);