support route must

This commit is contained in:
xuejiaming 2021-08-24 10:05:47 +08:00
parent 635b509811
commit fdbeef0343
18 changed files with 378 additions and 21 deletions

View File

@ -1,8 +1,8 @@
:start
::定义版本
set EFCORE2=2.2.0.09
set EFCORE3=3.2.0.09
set EFCORE5=5.2.0.09
set EFCORE2=2.2.0.10-pre
set EFCORE3=3.2.0.10-pre
set EFCORE5=5.2.0.10-pre
::删除所有bin与obj下的文件
@echo off

View File

@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace ShardingCore.Core.QueryRouteManagers.Abstractions
{
/*
* @Author: xjm
* @Description:
* @Date: 2021/8/23 16:54:19
* @Ver: 1.0
* @Email: 326308290@qq.com
*/
public interface IShardingRouteAccessor
{
ShardingRouteContext ShardingRouteContext { get; set; }
}
}

View File

@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace ShardingCore.Core.QueryRouteManagers.Abstractions
{
/*
* @Author: xjm
* @Description:
* @Date: 2021/8/23 16:53:05
* @Ver: 1.0
* @Email: 326308290@qq.com
*/
public interface IShardingRouteManager
{
ShardingRouteContext Current { get; }
/// <summary>
/// 创建路由scope
/// </summary>
/// <returns></returns>
ShardingRouteScope CreateScope();
}
}

View File

@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using ShardingCore.Core.QueryRouteManagers.Abstractions;
namespace ShardingCore.Core.QueryRouteManagers
{
/*
* @Author: xjm
* @Description:
* @Date: 2021/8/23 17:10:00
* @Ver: 1.0
* @Email: 326308290@qq.com
*/
public class ShardingRouteAccessor: IShardingRouteAccessor
{
private static AsyncLocal<ShardingRouteContext> _shardingRouteContext = new AsyncLocal<ShardingRouteContext>();
/// <inheritdoc />
public ShardingRouteContext ShardingRouteContext
{
get => _shardingRouteContext.Value;
set => _shardingRouteContext.Value = value;
}
}
}

View File

@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using System.Text;
using ShardingCore.Exceptions;
using ShardingCore.Extensions;
namespace ShardingCore.Core.QueryRouteManagers
{
/*
* @Author: xjm
* @Description:
* @Date: 2021/8/23 16:55:33
* @Ver: 1.0
* @Email: 326308290@qq.com
*/
public class ShardingRouteContext
{
public Dictionary<Type, HashSet<string>> Must { get; }
public Dictionary<Type, HashSet<string>> Should { get; }
public Dictionary<Type, HashSet<string>> ShouldNot { get; }
private ShardingRouteContext()
{
Must = new Dictionary<Type, HashSet<string>>();
Should = new Dictionary<Type, HashSet<string>>();
ShouldNot = new Dictionary<Type, HashSet<string>>();
}
public static ShardingRouteContext Create()
{
return new ShardingRouteContext();
}
}
}

View File

@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
using System.Text;
using ShardingCore.Core.QueryRouteManagers.Abstractions;
namespace ShardingCore.Core.QueryRouteManagers
{
/*
* @Author: xjm
* @Description:
* @Date: 2021/8/23 21:55:57
* @Ver: 1.0
* @Email: 326308290@qq.com
*/
public class ShardingRouteManager: IShardingRouteManager
{
private readonly IShardingRouteAccessor _shardingRouteAccessor;
public ShardingRouteManager(IShardingRouteAccessor shardingRouteAccessor)
{
_shardingRouteAccessor = shardingRouteAccessor;
}
public ShardingRouteContext Current => _shardingRouteAccessor.ShardingRouteContext;
public ShardingRouteScope CreateScope()
{
var shardingRouteScope = new ShardingRouteScope(_shardingRouteAccessor);
_shardingRouteAccessor.ShardingRouteContext = ShardingRouteContext.Create();
return shardingRouteScope;
}
}
}

View File

@ -0,0 +1,40 @@
using System;
using System.Collections.Generic;
using System.Text;
using ShardingCore.Core.QueryRouteManagers.Abstractions;
namespace ShardingCore.Core.QueryRouteManagers
{
/*
* @Author: xjm
* @Description:
* @Date: 2021/8/23 16:53:43
* @Ver: 1.0
* @Email: 326308290@qq.com
*/
public class ShardingRouteScope : IDisposable
{
/// <summary>
/// 分表配置访问器
/// </summary>
public IShardingRouteAccessor ShardingRouteAccessor { get; }
/// <summary>
/// 构造函数
/// </summary>
/// <param name="shardingRouteAccessor"></param>
public ShardingRouteScope(IShardingRouteAccessor shardingRouteAccessor)
{
ShardingRouteAccessor = shardingRouteAccessor;
}
/// <summary>
/// 回收
/// </summary>
public void Dispose()
{
ShardingRouteAccessor.ShardingRouteContext = null;
}
}
}

View File

@ -23,6 +23,7 @@ namespace ShardingCore.Core.ShardingAccessors
/// <param name="shardingAccessor"></param>
public ShardingScope(IShardingAccessor shardingAccessor)
{
shardingAccessor.ShardingContext = null;
ShardingAccessor = shardingAccessor;
}

View File

@ -17,7 +17,7 @@ namespace ShardingCore.Core.VirtualRoutes.TableRoutes
*/
public abstract class AbstractShardingOperatorVirtualTableRoute<T, TKey> : AbstractVirtualTableRoute<T, TKey> where T : class, IShardingTable
{
protected override List<IPhysicTable> DoRouteWithWhere(List<IPhysicTable> allPhysicTables, IQueryable queryable)
protected override List<IPhysicTable> DoRouteWithPredicate(List<IPhysicTable> allPhysicTables, IQueryable queryable)
{
//获取所有需要路由的表后缀
var filter = ShardingKeyUtil.GetRouteShardingTableFilter(queryable, ShardingKeyUtil.Parse(typeof(T)), ConvertToShardingKey, GetRouteToFilter);

View File

@ -2,19 +2,31 @@ using System;
using System.Collections.Generic;
using System.Linq;
using ShardingCore.Core.PhysicTables;
using ShardingCore.Core.QueryRouteManagers;
using ShardingCore.Core.QueryRouteManagers.Abstractions;
using ShardingCore.Exceptions;
using ShardingCore.Extensions;
namespace ShardingCore.Core.VirtualRoutes.TableRoutes
{
/*
* @Author: xjm
* @Description:
* @Date: Friday, 18 December 2020 14:33:01
* @Email: 326308290@qq.com
*/
/*
* @Author: xjm
* @Description:
* @Date: Friday, 18 December 2020 14:33:01
* @Email: 326308290@qq.com
*/
public abstract class AbstractVirtualTableRoute<T, TKey> : IVirtualTableRoute<T> where T : class, IShardingTable
{
public Type ShardingEntityType => typeof(T);
public virtual ShardingRouteContext CurrentShardingRouteContext =>
ShardingContainer.GetService<IShardingRouteManager>().Current;
/// <summary>
/// 跳过表达式路由
/// </summary>
protected virtual bool SkipRouteWithPredicate =>
CurrentShardingRouteContext != null && CurrentShardingRouteContext.TryGetMustTail<T>(out HashSet<string> mustTails) && mustTails.IsNotEmpty();
protected abstract TKey ConvertToShardingKey(object shardingKey);
public abstract string ShardingKeyToTail(object shardingKey);
/// <summary>
@ -23,9 +35,24 @@ namespace ShardingCore.Core.VirtualRoutes.TableRoutes
/// <param name="allPhysicTables"></param>
/// <param name="queryable"></param>
/// <returns></returns>
public List<IPhysicTable> RouteWithWhere(List<IPhysicTable> allPhysicTables, IQueryable queryable)
public virtual List<IPhysicTable> RouteWithPredicate(List<IPhysicTable> allPhysicTables, IQueryable queryable)
{
return AfterPhysicTableFilter(allPhysicTables,DoRouteWithWhere(allPhysicTables,queryable));
if (SkipRouteWithPredicate)
{
var tails = CurrentShardingRouteContext.Must[ShardingEntityType];
var physicTables = allPhysicTables.Where(o => tails.Contains(o.Tail)).ToList();
if (physicTables.IsEmpty())
throw new ShardingCoreException(
$" sharding route must error:[{ShardingEntityType.FullName}]-->[{string.Join(",",tails)}]");
return physicTables;
}
var filterPhysicTables = BeforePhysicTableFilter(allPhysicTables);
filterPhysicTables = DoRouteWithPredicate(filterPhysicTables, queryable);
return AfterPhysicTableFilter(allPhysicTables, filterPhysicTables);
}
protected virtual List<IPhysicTable> BeforePhysicTableFilter(List<IPhysicTable> allPhysicTables)
{
return allPhysicTables;
}
/// <summary>
/// 实际路由
@ -33,14 +60,14 @@ namespace ShardingCore.Core.VirtualRoutes.TableRoutes
/// <param name="allPhysicTables"></param>
/// <param name="queryable"></param>
/// <returns></returns>
protected abstract List<IPhysicTable> DoRouteWithWhere(List<IPhysicTable> allPhysicTables, IQueryable queryable);
protected abstract List<IPhysicTable> DoRouteWithPredicate(List<IPhysicTable> allPhysicTables, IQueryable queryable);
/// <summary>
/// 物理表过滤后
/// </summary>
/// <param name="allPhysicTables">所有的物理表</param>
/// <param name="filterPhysicTables">过滤后的物理表</param>
/// <returns></returns>
public virtual List<IPhysicTable> AfterPhysicTableFilter(List<IPhysicTable> allPhysicTables,List<IPhysicTable> filterPhysicTables)
protected virtual List<IPhysicTable> AfterPhysicTableFilter(List<IPhysicTable> allPhysicTables, List<IPhysicTable> filterPhysicTables)
{
return filterPhysicTables;
}

View File

@ -25,7 +25,7 @@ namespace ShardingCore.Core.VirtualRoutes.TableRoutes
/// <param name="allPhysicTables"></param>
/// <param name="queryable"></param>
/// <returns></returns>
List<IPhysicTable> RouteWithWhere(List<IPhysicTable> allPhysicTables,IQueryable queryable);
List<IPhysicTable> RouteWithPredicate(List<IPhysicTable> allPhysicTables,IQueryable queryable);
/// <summary>
/// 根据值进行路由

View File

@ -45,9 +45,9 @@ namespace ShardingCore.Core.VirtualTables
{
var route = _virtualTableRoute;
if (tableRouteConfig.UseQueryable())
return route.RouteWithWhere(_physicTables, tableRouteConfig.GetQueryable());
return route.RouteWithPredicate(_physicTables, tableRouteConfig.GetQueryable());
if (tableRouteConfig.UsePredicate())
return route.RouteWithWhere(_physicTables, new EnumerableQuery<T>((Expression<Func<T, bool>>) tableRouteConfig.GetPredicate()));
return route.RouteWithPredicate(_physicTables, new EnumerableQuery<T>((Expression<Func<T, bool>>) tableRouteConfig.GetPredicate()));
object shardingKeyValue = null;
if (tableRouteConfig.UseValue())
shardingKeyValue = tableRouteConfig.GetShardingKeyValue();

View File

@ -12,6 +12,8 @@ using ShardingCore.Sharding;
using ShardingCore.Sharding.Abstractions;
using ShardingCore.TableCreator;
using System;
using ShardingCore.Core.QueryRouteManagers;
using ShardingCore.Core.QueryRouteManagers.Abstractions;
using ShardingCore.Core.ShardingAccessors;
using ShardingCore.Core.ShardingAccessors.Abstractions;
using ShardingCore.Core.VirtualRoutes;
@ -84,6 +86,8 @@ namespace ShardingCore
services.AddSingleton<IShardingAccessor, ShardingAccessor>();
services.AddSingleton<IShardingScopeFactory, ShardingScopeFactory>();
services.AddSingleton<IRouteTailFactory, RouteTailFactory>();
services.AddSingleton<IShardingRouteManager, ShardingRouteManager>();
services.AddSingleton<IShardingRouteAccessor, ShardingRouteAccessor>();
return services;
}

View File

@ -0,0 +1,42 @@
using System;
using System.Collections.Generic;
using System.Text;
using ShardingCore.Core;
using ShardingCore.Core.QueryRouteManagers;
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 ShardingRouteExtension
{
public static bool TryGetMustTail<TEntity>(this ShardingRouteContext shardingRouteContext, out HashSet<string> tail) where TEntity : class,IShardingTable
{
return TryGetMustTail(shardingRouteContext,typeof(TEntity),out tail);
}
public static bool TryGetMustTail(this ShardingRouteContext shardingRouteContext,Type entityType, out HashSet<string> tail)
{
if (shardingRouteContext == null)
{
tail = null;
return false;
}
if (!entityType.IsShardingTable())
throw new ShardingCoreException($"sharding route entity type :{entityType.FullName} must impl {nameof(IShardingTable)}");
if (!shardingRouteContext.Must.ContainsKey(entityType))
{
tail = null;
return false;
}
tail = shardingRouteContext.Must[entityType];
return true;
}
}
}

View File

@ -66,7 +66,7 @@ namespace ShardingCore.TableCreator
var shardingConfigOptions = _shardingConfigOptions.FirstOrDefault(o => o.ShardingDbContextType == shardingDbContextType);
if (shardingConfigOptions == null)
throw new ShardingCoreException(
"not found sharding config options db context is {shardingDbContextType.FullName}");
$"not found sharding config options db context is {shardingDbContextType.FullName}");
using (var serviceScope = _serviceProvider.CreateScope())
{
var virtualTable = _virtualTableManager.GetVirtualTable(shardingDbContextType, shardingEntityType);

View File

@ -1,7 +1,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using ShardingCore.Core.QueryRouteManagers.Abstractions;
using ShardingCore.Core.VirtualRoutes.TableRoutes.RoutingRuleEngine;
using ShardingCore.DbContexts.VirtualDbContexts;
using ShardingCore.Extensions;
@ -20,10 +22,12 @@ namespace ShardingCore.Test50
public class ShardingTest
{
private readonly ShardingDefaultDbContext _virtualDbContext;
private readonly IShardingRouteManager _shardingRouteManager;
public ShardingTest(ShardingDefaultDbContext virtualDbContext)
public ShardingTest(ShardingDefaultDbContext virtualDbContext,IShardingRouteManager shardingRouteManager)
{
_virtualDbContext = virtualDbContext;
_shardingRouteManager = shardingRouteManager;
}
//[Fact]
@ -44,6 +48,36 @@ namespace ShardingCore.Test50
// Assert.Equal(true,routeResult2s.SelectMany(o=>o.ReplaceTables).All(o=>new[]{"0","1"}.Contains(o.Tail)));
//}
[Fact]
public async Task ToList_All_Route_Test()
{
using (_shardingRouteManager.CreateScope())
{
_shardingRouteManager.Current.Must.TryAdd(typeof(SysUserMod), new HashSet<string>() { "00" });
var mod00s = await _virtualDbContext.Set<SysUserMod>().ToListAsync();
Assert.Equal(333, mod00s.Count);
}
var mods = await _virtualDbContext.Set<SysUserMod>().ToListAsync();
Assert.Equal(1000, mods.Count);
var modOrders1 = await _virtualDbContext.Set<SysUserMod>().OrderBy(o => o.Age).ToListAsync();
int ascAge = 1;
foreach (var sysUserMod in modOrders1)
{
Assert.Equal(ascAge, sysUserMod.Age);
ascAge++;
}
var modOrders2 = await _virtualDbContext.Set<SysUserMod>().OrderByDescending(o => o.Age).ToListAsync();
int descAge = 1000;
foreach (var sysUserMod in modOrders2)
{
Assert.Equal(descAge, sysUserMod.Age);
descAge--;
}
}
[Fact]
public async Task ToList_All_Test()
{
@ -81,6 +115,7 @@ namespace ShardingCore.Test50
DateOfMonth = salary.DateOfMonth,
Name = u.Name
}).ToListAsync();
var list2 = list.OrderBy(o=>o.Age).Select(o=>o.Age).Distinct().ToList();
Assert.Equal(24000, list.Count());
Assert.Equal(24, list.Count(o => o.Name == "name_200"));

View File

@ -1,6 +1,8 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using ShardingCore.Core.QueryRouteManagers.Abstractions;
using ShardingCore.Test50_2x.Domain.Entities;
using Xunit;
@ -15,10 +17,12 @@ namespace ShardingCore.Test50_2x
public class ShardingTest
{
private readonly ShardingDefaultDbContext _virtualDbContext;
private readonly IShardingRouteManager _shardingRouteManager;
public ShardingTest(ShardingDefaultDbContext virtualDbContext)
public ShardingTest(ShardingDefaultDbContext virtualDbContext,IShardingRouteManager shardingRouteManager)
{
_virtualDbContext = virtualDbContext;
_shardingRouteManager = shardingRouteManager;
}
//[Fact]
@ -38,6 +42,38 @@ namespace ShardingCore.Test50_2x
// Assert.Equal(2,routeResult2s.SelectMany(o=>o.ReplaceTables).Count());
// Assert.Equal(true,routeResult2s.SelectMany(o=>o.ReplaceTables).All(o=>new[]{"0","1"}.Contains(o.Tail)));
//}
[Fact]
public async Task ToList_All_Route_Test()
{
using (_shardingRouteManager.CreateScope())
{
_shardingRouteManager.Current.Must.TryAdd(typeof(SysUserMod), new HashSet<string>() { "00" });
var mod00s = await _virtualDbContext.Set<SysUserMod>().ToListAsync();
Assert.Equal(333, mod00s.Count);
}
var mods = await _virtualDbContext.Set<SysUserMod>().ToListAsync();
Assert.Equal(1000, mods.Count);
var modOrders1 = await _virtualDbContext.Set<SysUserMod>().OrderBy(o => o.Age).ToListAsync();
int ascAge = 1;
foreach (var sysUserMod in modOrders1)
{
Assert.Equal(ascAge, sysUserMod.Age);
ascAge++;
}
var modOrders2 = await _virtualDbContext.Set<SysUserMod>().OrderByDescending(o => o.Age).ToListAsync();
int descAge = 1000;
foreach (var sysUserMod in modOrders2)
{
Assert.Equal(descAge, sysUserMod.Age);
descAge--;
}
}
[Fact]
public async Task ToList_All_Test()
{

View File

@ -1,6 +1,8 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using ShardingCore.Core.QueryRouteManagers.Abstractions;
using ShardingCore.Test50_3x.Domain.Entities;
using Xunit;
@ -15,10 +17,12 @@ namespace ShardingCore.Test50_3x
public class ShardingTest
{
private readonly ShardingDefaultDbContext _virtualDbContext;
private readonly IShardingRouteManager _shardingRouteManager;
public ShardingTest(ShardingDefaultDbContext virtualDbContext)
public ShardingTest(ShardingDefaultDbContext virtualDbContext, IShardingRouteManager shardingRouteManager)
{
_virtualDbContext = virtualDbContext;
_shardingRouteManager = shardingRouteManager;
}
//[Fact]
@ -38,6 +42,38 @@ namespace ShardingCore.Test50_3x
// Assert.Equal(2,routeResult2s.SelectMany(o=>o.ReplaceTables).Count());
// Assert.Equal(true,routeResult2s.SelectMany(o=>o.ReplaceTables).All(o=>new[]{"0","1"}.Contains(o.Tail)));
//}
[Fact]
public async Task ToList_All_Route_Test()
{
using (_shardingRouteManager.CreateScope())
{
_shardingRouteManager.Current.Must.TryAdd(typeof(SysUserMod), new HashSet<string>() { "00" });
var mod00s = await _virtualDbContext.Set<SysUserMod>().ToListAsync();
Assert.Equal(333, mod00s.Count);
}
var mods = await _virtualDbContext.Set<SysUserMod>().ToListAsync();
Assert.Equal(1000, mods.Count);
var modOrders1 = await _virtualDbContext.Set<SysUserMod>().OrderBy(o => o.Age).ToListAsync();
int ascAge = 1;
foreach (var sysUserMod in modOrders1)
{
Assert.Equal(ascAge, sysUserMod.Age);
ascAge++;
}
var modOrders2 = await _virtualDbContext.Set<SysUserMod>().OrderByDescending(o => o.Age).ToListAsync();
int descAge = 1000;
foreach (var sysUserMod in modOrders2)
{
Assert.Equal(descAge, sysUserMod.Age);
descAge--;
}
}
[Fact]
public async Task ToList_All_Test()
{