diff --git a/README.md b/README.md index 3631bcaa..73af9007 100644 --- a/README.md +++ b/README.md @@ -223,6 +223,29 @@ AbstractSimpleShardingYearKeyLongVirtualRoute |按时间戳 |yyyy | `>,>=,<,<=,= 注:`contains`表示为`o=>ids.contains(o.shardingkey)` +#高级 + +##批量操作 + +批量操作将对应的dbcontext和数据进行分离由用户自己选择第三方框架比如zzz进行批量操作或者batchextension +```c# + virtualDbContext.BulkInsert(new List()) +.BatchGroups.ForEach(pair => +{ + ///zzz or other + pair.Key.BlukInsert(pair.Value); +}); +var shardingBatchUpdateEntry = virtualDbContext.BulkUpdate(o => o.Id == "1", o => new SysUserMod() +{ +Name = "name_01" +}); +shardingBatchUpdateEntry.DbContexts.ForEach(context => +{ +//zzz or other +context.Where(shardingBatchUpdateEntry.Where).Update(shardingBatchUpdateEntry.UpdateExp); +}); +``` + # 最后 凭借各大开源生态圈提供的优秀代码和思路才有的这个框架,希望可以为.Net生态提供一份微薄之力,该框架本人会一直长期维护,有大神技术支持可以联系下方方式欢迎star :) diff --git a/src/ShardingCore/Core/Internal/StreamMerge/GenericMerges/GenericInMemoryMergeEngine.cs b/src/ShardingCore/Core/Internal/StreamMerge/GenericMerges/GenericInMemoryMergeEngine.cs index 01be8e40..36064fb6 100644 --- a/src/ShardingCore/Core/Internal/StreamMerge/GenericMerges/GenericInMemoryMergeEngine.cs +++ b/src/ShardingCore/Core/Internal/StreamMerge/GenericMerges/GenericInMemoryMergeEngine.cs @@ -38,6 +38,8 @@ namespace ShardingCore.Core.Internal.StreamMerge.GenericMerges } public async Task> ExecuteAsync(Func> efQuery) { + if (_mergeContext.Skip.HasValue || _mergeContext.Take.HasValue) + throw new InvalidOperationException("aggregate not support skip take"); //从各个分表获取数据 List parallelDbContexts = new List(_mergeContext.RouteResults.Count()); try diff --git a/src/ShardingCore/Core/Internal/Visitors/GroupBys/GroupByAggregateMethod.cs b/src/ShardingCore/Core/Internal/Visitors/GroupBys/GroupByAggregateMethod.cs new file mode 100644 index 00000000..2234e952 --- /dev/null +++ b/src/ShardingCore/Core/Internal/Visitors/GroupBys/GroupByAggregateMethod.cs @@ -0,0 +1,23 @@ +using System; + +namespace ShardingCore.Core.Internal.Visitors.GroupBys +{ +/* +* @Author: xjm +* @Description: +* @Date: Monday, 01 February 2021 21:20:19 +* @Email: 326308290@qq.com +*/ + public class GroupByAggregateMethod + { + public GroupByAggregateMethod(string aggregateMethodName) + { + AggregateMethodName = aggregateMethodName; + } + + /// + /// + /// + public string AggregateMethodName { get; } + } +} \ No newline at end of file diff --git a/src/ShardingCore/Core/Internal/Visitors/GroupBys/GroupByContext.cs b/src/ShardingCore/Core/Internal/Visitors/GroupBys/GroupByContext.cs new file mode 100644 index 00000000..a65b9b9a --- /dev/null +++ b/src/ShardingCore/Core/Internal/Visitors/GroupBys/GroupByContext.cs @@ -0,0 +1,19 @@ +using System.Collections.Generic; +using System.Linq.Expressions; + +namespace ShardingCore.Core.Internal.Visitors.GroupBys +{ +/* +* @Author: xjm +* @Description: +* @Date: Monday, 01 February 2021 21:17:55 +* @Email: 326308290@qq.com +*/ + public class GroupByContext + { + + public LambdaExpression GroupExpression { get; set; } + public List GroupByAggregateMethods { get; set; } = new List(); + + } +} \ No newline at end of file diff --git a/src/ShardingCore/Core/Internal/Visitors/QueryAggregateDiscoverVisitor.cs b/src/ShardingCore/Core/Internal/Visitors/QueryAggregateDiscoverVisitor.cs new file mode 100644 index 00000000..f346bc9b --- /dev/null +++ b/src/ShardingCore/Core/Internal/Visitors/QueryAggregateDiscoverVisitor.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using ShardingCore.Core.Internal.Visitors.GroupBys; + +namespace ShardingCore.Core.Internal.Visitors +{ +/* +* @Author: xjm +* @Description: +* @Date: Monday, 01 February 2021 17:30:48 +* @Email: 326308290@qq.com +*/ + public class QueryAggregateDiscoverVisitor:ExpressionVisitor + { + public List AggregateMethods { get; private set; } = new List(); + protected override Expression VisitMethodCall(MethodCallExpression node) + { + var method = node.Method; + if (method.Name == nameof(Queryable.Count)||method.Name == nameof(Queryable.Sum)||method.Name == nameof(Queryable.Max)||method.Name == nameof(Queryable.Min)||method.Name == nameof(Queryable.Average)) + { + AggregateMethods.Add(new GroupByAggregateMethod(method.Name)); + } + return base.VisitMethodCall(node); + } + } +} \ No newline at end of file diff --git a/src/ShardingCore/Core/Internal/Visitors/QueryableExtraDiscoverVisitor.cs b/src/ShardingCore/Core/Internal/Visitors/QueryableExtraDiscoverVisitor.cs index 8600ba71..3ff4c0be 100644 --- a/src/ShardingCore/Core/Internal/Visitors/QueryableExtraDiscoverVisitor.cs +++ b/src/ShardingCore/Core/Internal/Visitors/QueryableExtraDiscoverVisitor.cs @@ -2,6 +2,8 @@ using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; +using ShardingCore.Core.Internal.Visitors.GroupBys; +using ShardingCore.Extensions; namespace ShardingCore.Core.Internal.Visitors { @@ -16,6 +18,8 @@ namespace ShardingCore.Core.Internal.Visitors private int? _skip; private int? _take; private LinkedList _orders = new LinkedList(); + private LinkedList _groups = new LinkedList(); + private GroupByContext _groupByContext=new GroupByContext(); public int? GetSkip() { @@ -76,6 +80,29 @@ namespace ShardingCore.Core.Internal.Visitors var propertyExpression=string.Join(".", properties); _orders.AddFirst(new PropertyOrder(propertyExpression,method.Name == nameof(Queryable.OrderBy)||method.Name == nameof(Queryable.ThenBy))); } + // else if (node.Method.Name == nameof(Queryable.GroupBy)) + // { + // if (_groupByContext.GroupExpression == null) + // { + // var expression=(node.Arguments[1] as UnaryExpression).Operand as LambdaExpression; + // if (expression == null) + // throw new NotSupportedException("sharding group not support "); + // _groupByContext.GroupExpression = expression; + // } + // } + // else if (node.Method.Name == nameof(Queryable.Select)) + // { + // if (_groupByContext.GroupByAggregateMethods.IsEmpty()) + // { + // var expression=((node.Arguments[1] as UnaryExpression).Operand as LambdaExpression).Body as NewExpression; + // if (expression != null) + // { + // var aggregateDiscoverVisitor = new QueryAggregateDiscoverVisitor(); + // aggregateDiscoverVisitor.Visit(expression); + // _groupByContext.GroupByAggregateMethods = aggregateDiscoverVisitor.AggregateMethods; + // } + // } + // } return base.VisitMethodCall(node); } diff --git a/test/ShardingCore.Test50.MySql/Domain/Entities/SysUserMod.cs b/test/ShardingCore.Test50.MySql/Domain/Entities/SysUserMod.cs index 4883a53b..20026616 100644 --- a/test/ShardingCore.Test50.MySql/Domain/Entities/SysUserMod.cs +++ b/test/ShardingCore.Test50.MySql/Domain/Entities/SysUserMod.cs @@ -23,6 +23,7 @@ namespace ShardingCore.Test50.MySql.Domain.Entities /// 用户姓名 /// public int Age { get; set; } + public int AgeGroup { get; set; } } } \ No newline at end of file diff --git a/test/ShardingCore.Test50.MySql/Domain/Entities/SysUserRange.cs b/test/ShardingCore.Test50.MySql/Domain/Entities/SysUserRange.cs index 6eeec2db..48e6b9cf 100644 --- a/test/ShardingCore.Test50.MySql/Domain/Entities/SysUserRange.cs +++ b/test/ShardingCore.Test50.MySql/Domain/Entities/SysUserRange.cs @@ -1,27 +1,27 @@ -using ShardingCore.Core; - -namespace ShardingCore.Test50.MySql.Domain.Entities -{ -/* -* @Author: xjm -* @Description: -* @Date: Wednesday, 20 January 2021 10:43:19 -* @Email: 326308290@qq.com -*/ - public class SysUserRange:IShardingEntity - { - /// - /// 分表分库range切分 - /// - [ShardingKey(TailPrefix = "_",AutoCreateTableOnStart = true)] - public string Id { get; set; } - /// - /// 姓名 - /// - public string Name { get; set; } - /// - /// 年龄 - /// - public int Age { get; set; } - } -} \ No newline at end of file +// using ShardingCore.Core; +// +// namespace ShardingCore.Test50.MySql.Domain.Entities +// { +// /* +// * @Author: xjm +// * @Description: +// * @Date: Wednesday, 20 January 2021 10:43:19 +// * @Email: 326308290@qq.com +// */ +// public class SysUserRange:IShardingEntity +// { +// /// +// /// 分表分库range切分 +// /// +// [ShardingKey(TailPrefix = "_",AutoCreateTableOnStart = true)] +// public string Id { get; set; } +// /// +// /// 姓名 +// /// +// public string Name { get; set; } +// /// +// /// 年龄 +// /// +// public int Age { get; set; } +// } +// } \ No newline at end of file diff --git a/test/ShardingCore.Test50.MySql/Domain/Entities/SysUserSalary.cs b/test/ShardingCore.Test50.MySql/Domain/Entities/SysUserSalary.cs new file mode 100644 index 00000000..9382c912 --- /dev/null +++ b/test/ShardingCore.Test50.MySql/Domain/Entities/SysUserSalary.cs @@ -0,0 +1,26 @@ +using System; +using ShardingCore.Core; + +namespace ShardingCore.Test50.MySql.Domain.Entities +{ +/* +* @Author: xjm +* @Description: +* @Date: Monday, 01 February 2021 15:40:46 +* @Email: 326308290@qq.com +*/ + public class SysUserSalary:IShardingEntity + { + public string Id { get; set; } + public string UserId { get; set; } + /// + /// 每月的金额 + /// + [ShardingKey(AutoCreateTableOnStart = false)] + public int DateOfMonth { get; set; } + /// + /// 工资 + /// + public int Salary { get; set; } + } +} \ No newline at end of file diff --git a/test/ShardingCore.Test50.MySql/Domain/Maps/SysUserRangeMap.cs b/test/ShardingCore.Test50.MySql/Domain/Maps/SysUserRangeMap.cs index 614472ae..8c094bbc 100644 --- a/test/ShardingCore.Test50.MySql/Domain/Maps/SysUserRangeMap.cs +++ b/test/ShardingCore.Test50.MySql/Domain/Maps/SysUserRangeMap.cs @@ -1,23 +1,23 @@ -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Metadata.Builders; -using ShardingCore.Test50.MySql.Domain.Entities; - -namespace ShardingCore.Test50.MySql.Domain.Maps -{ -/* -* @Author: xjm -* @Description: -* @Date: Wednesday, 20 January 2021 10:45:47 -* @Email: 326308290@qq.com -*/ - public class SysUserRangeMap:IEntityTypeConfiguration - { - public void Configure(EntityTypeBuilder builder) - { - builder.HasKey(o => o.Id); - builder.Property(o => o.Id).IsRequired().HasMaxLength(128); - builder.Property(o => o.Name).HasMaxLength(128); - builder.ToTable(nameof(SysUserRange)); - } - } -} \ No newline at end of file +// using Microsoft.EntityFrameworkCore; +// using Microsoft.EntityFrameworkCore.Metadata.Builders; +// using ShardingCore.Test50.MySql.Domain.Entities; +// +// namespace ShardingCore.Test50.MySql.Domain.Maps +// { +// /* +// * @Author: xjm +// * @Description: +// * @Date: Wednesday, 20 January 2021 10:45:47 +// * @Email: 326308290@qq.com +// */ +// public class SysUserRangeMap:IEntityTypeConfiguration +// { +// public void Configure(EntityTypeBuilder builder) +// { +// builder.HasKey(o => o.Id); +// builder.Property(o => o.Id).IsRequired().HasMaxLength(128); +// builder.Property(o => o.Name).HasMaxLength(128); +// builder.ToTable(nameof(SysUserRange)); +// } +// } +// } \ No newline at end of file diff --git a/test/ShardingCore.Test50.MySql/Domain/Maps/SysUserSalaryMap.cs b/test/ShardingCore.Test50.MySql/Domain/Maps/SysUserSalaryMap.cs new file mode 100644 index 00000000..36914906 --- /dev/null +++ b/test/ShardingCore.Test50.MySql/Domain/Maps/SysUserSalaryMap.cs @@ -0,0 +1,24 @@ +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using ShardingCore.Test50.MySql.Domain.Entities; + +namespace ShardingCore.Test50.MySql.Domain.Maps +{ +/* +* @Author: xjm +* @Description: +* @Date: Monday, 01 February 2021 15:42:35 +* @Email: 326308290@qq.com +*/ + public class SysUserSalaryMap:IEntityTypeConfiguration + { + public void Configure(EntityTypeBuilder builder) + { + builder.HasKey(o => o.Id); + builder.Property(o => o.Id).IsRequired().HasMaxLength(128); + builder.Property(o => o.UserId).IsRequired().HasMaxLength(128); + builder.ToTable(nameof(SysUserSalary)); + } + } +} \ No newline at end of file diff --git a/test/ShardingCore.Test50.MySql/ShardingTest.cs b/test/ShardingCore.Test50.MySql/ShardingTest.cs index 744008ec..6dae59a0 100644 --- a/test/ShardingCore.Test50.MySql/ShardingTest.cs +++ b/test/ShardingCore.Test50.MySql/ShardingTest.cs @@ -26,15 +26,42 @@ namespace ShardingCore.Test50.MySql public async Task ToList_All_Test() { var mods=await _virtualDbContext.Set().ToShardingListAsync(); - Assert.Equal(100,mods.Count); - var ranges=await _virtualDbContext.Set().ToShardingListAsync(); - Assert.Equal(1000,ranges.Count); + Assert.Equal(1000,mods.Count); + } + [Fact] + public async Task ToList_Join_Test() + { + var list =await (from u in _virtualDbContext.Set() + join salary in _virtualDbContext.Set() + on u.Id equals salary.UserId + select new + { + Salary = salary.Salary, + DateOfMonth=salary.DateOfMonth, + Name = u.Name + }).ToShardingListAsync(); + Assert.Equal(24000,list.Count()); + Assert.Equal(24,list.Count(o => o.Name=="name_200")); + + + var queryable = (from u in _virtualDbContext.Set().Where(o=>o.Id=="300") + join salary in _virtualDbContext.Set() + on u.Id equals salary.UserId + select new + { + Salary = salary.Salary, + DateOfMonth=salary.DateOfMonth, + Name = u.Name + }); + var list1 = await queryable.ToShardingListAsync(); + Assert.Equal(24,list1.Count()); + Assert.DoesNotContain(list1,o=>o.Name!="name_300"); } [Fact] public async Task ToList_OrderBy_Asc_Desc_Test() { var modascs=await _virtualDbContext.Set().OrderBy(o=>o.Age).ToShardingListAsync(); - Assert.Equal(100,modascs.Count); + Assert.Equal(1000,modascs.Count); var i = 1; foreach (var age in modascs) { @@ -43,13 +70,12 @@ namespace ShardingCore.Test50.MySql } var moddescs=await _virtualDbContext.Set().OrderByDescending(o=>o.Age).ToShardingListAsync(); - Assert.Equal(100,moddescs.Count); - var j = 100; + Assert.Equal(1000,moddescs.Count); + var j = 1000; foreach (var age in moddescs) { Assert.Equal(j,age.Age); j--; - } } [Fact] @@ -57,14 +83,11 @@ namespace ShardingCore.Test50.MySql { var ids = new[] {"1", "2", "3", "4"}; var sysUserMods=await _virtualDbContext.Set().Where(o=>ids.Contains(o.Id)).ToShardingListAsync(); - var sysUserRanges=await _virtualDbContext.Set().Where(o=>ids.Contains(o.Id)).ToShardingListAsync(); foreach (var id in ids) { Assert.Contains(sysUserMods, o =>o.Id==id); - Assert.Contains(sysUserRanges, o =>o.Id==id); } Assert.DoesNotContain(sysUserMods,o=>o.Age>4); - Assert.DoesNotContain(sysUserRanges,o=>o.Age>4); } [Fact] public async Task ToList_Id_Eq_Test() @@ -72,34 +95,28 @@ namespace ShardingCore.Test50.MySql var mods=await _virtualDbContext.Set().Where(o=>o.Id=="3").ToShardingListAsync(); Assert.Single(mods); Assert.Equal("3",mods[0].Id); - var ranges=await _virtualDbContext.Set().Where(o=>o.Id=="3").ToShardingListAsync(); - Assert.Single(ranges); - Assert.Equal("3",ranges[0].Id); } [Fact] public async Task ToList_Id_Not_Eq_Test() { var mods=await _virtualDbContext.Set().Where(o=>o.Id!="3").ToShardingListAsync(); - Assert.Equal(99,mods.Count); + Assert.Equal(999,mods.Count); Assert.DoesNotContain(mods,o=>o.Id=="3"); - var ranges=await _virtualDbContext.Set().Where(o=>o.Id!="3").ToShardingListAsync(); - Assert.Equal(999,ranges.Count); - Assert.DoesNotContain(ranges,o=>o.Id=="3"); } [Fact] public async Task ToList_Id_Not_Eq_Skip_Test() { var mods=await _virtualDbContext.Set().Where(o=>o.Id!="3").OrderBy(o=>o.Age).Skip(2).ToShardingListAsync(); - Assert.Equal(97,mods.Count); + Assert.Equal(997,mods.Count); Assert.DoesNotContain(mods,o=>o.Id=="3"); Assert.Equal(4,mods[0].Age); Assert.Equal(5,mods[1].Age); var modsDesc=await _virtualDbContext.Set().Where(o=>o.Id!="3").OrderByDescending(o=>o.Age).Skip(13).ToShardingListAsync(); - Assert.Equal(86,modsDesc.Count); + Assert.Equal(986,modsDesc.Count); Assert.DoesNotContain(mods,o=>o.Id=="3"); - Assert.Equal(87,modsDesc[0].Age); - Assert.Equal(86,modsDesc[1].Age); + Assert.Equal(987,modsDesc[0].Age); + Assert.Equal(986,modsDesc[1].Age); } [Fact] public async Task ToList_Name_Eq_Test() @@ -107,25 +124,18 @@ namespace ShardingCore.Test50.MySql var mods=await _virtualDbContext.Set().Where(o=>o.Name=="name_3").ToShardingListAsync(); Assert.Single(mods); Assert.Equal("3",mods[0].Id); - var ranges=await _virtualDbContext.Set().Where(o=>o.Name=="name_range_3").ToShardingListAsync(); - Assert.Single(ranges); - Assert.Equal("3",ranges[0].Id); } [Fact] public async Task ToList_Id_Eq_Not_In_Db_Test() { var mods=await _virtualDbContext.Set().Where(o=>o.Id=="1001").ToShardingListAsync(); Assert.Empty(mods); - var ranges=await _virtualDbContext.Set().Where(o=>o.Id=="1001").ToShardingListAsync(); - Assert.Empty(ranges); } [Fact] public async Task ToList_Name_Eq_Not_In_Db_Test() { var mods=await _virtualDbContext.Set().Where(o=>o.Name=="name_1001").ToShardingListAsync(); Assert.Empty(mods); - var ranges=await _virtualDbContext.Set().Where(o=>o.Name=="name_range_1001").ToShardingListAsync(); - Assert.Empty(ranges); } [Fact] public async Task FirstOrDefault_Order_By_Id_Test() @@ -133,22 +143,19 @@ namespace ShardingCore.Test50.MySql var sysUserModAge=await _virtualDbContext.Set().OrderBy(o=>o.Age).ShardingFirstOrDefaultAsync(); Assert.True(sysUserModAge!=null&&sysUserModAge.Id=="1"); var sysUserModAgeDesc=await _virtualDbContext.Set().OrderByDescending(o=>o.Age).ShardingFirstOrDefaultAsync(); - Assert.True(sysUserModAgeDesc!=null&&sysUserModAgeDesc.Id=="100"); + Assert.True(sysUserModAgeDesc!=null&&sysUserModAgeDesc.Id=="1000"); var sysUserMod=await _virtualDbContext.Set().OrderBy(o=>o.Id).ShardingFirstOrDefaultAsync(); Assert.True(sysUserMod!=null&&sysUserMod.Id=="1"); var sysUserModDesc=await _virtualDbContext.Set().OrderByDescending(o=>o.Id).ShardingFirstOrDefaultAsync(); - Assert.True(sysUserModDesc!=null&&sysUserModDesc.Id=="99"); - var sysUserRange=await _virtualDbContext.Set().OrderBy(o=>o.Id).ShardingFirstOrDefaultAsync(); - Assert.True(sysUserRange!=null&&sysUserRange.Id=="1"); + Assert.True(sysUserModDesc!=null&&sysUserModDesc.Id=="999"); } [Fact] public async Task FirstOrDefault2() { var sysUserMod=await _virtualDbContext.Set().Where(o=>o.Id=="1").ShardingFirstOrDefaultAsync(); - Assert.True(sysUserMod!=null&&sysUserMod.Id=="1"); - var sysUserRange=await _virtualDbContext.Set().Where(o=>o.Id=="1").ShardingFirstOrDefaultAsync(); - Assert.True(sysUserRange!=null&&sysUserRange.Id=="1"); + Assert.NotNull(sysUserMod); + Assert.True(sysUserMod.Id=="1"); } [Fact] public async Task FirstOrDefault3() @@ -156,9 +163,6 @@ namespace ShardingCore.Test50.MySql var sysUserMod=await _virtualDbContext.Set().Where(o=>o.Name=="name_2").ShardingFirstOrDefaultAsync(); Assert.NotNull(sysUserMod); Assert.Equal("2",sysUserMod.Id); - var sysUserRange=await _virtualDbContext.Set().Where(o=>o.Name=="name_range_2").ShardingFirstOrDefaultAsync(); - Assert.NotNull(sysUserRange); - Assert.Equal("2",sysUserRange.Id); } [Fact] public async Task FirstOrDefault4() @@ -166,25 +170,98 @@ namespace ShardingCore.Test50.MySql var sysUserMod=await _virtualDbContext.Set().Where(o=>o.Id!="1").ShardingFirstOrDefaultAsync(); Assert.NotNull(sysUserMod); Assert.True(sysUserMod.Id!="1"); - var sysUserRange=await _virtualDbContext.Set().Where(o=>o.Id!="1").ShardingFirstOrDefaultAsync(); - Assert.NotNull(sysUserRange); - Assert.True(sysUserRange.Id!="1"); } [Fact] public async Task FirstOrDefault5() { - var sysUserMod=await _virtualDbContext.Set().Where(o=>o.Name=="name_101").ShardingFirstOrDefaultAsync(); + var sysUserMod=await _virtualDbContext.Set().Where(o=>o.Name=="name_1001").ShardingFirstOrDefaultAsync(); Assert.Null(sysUserMod); - var sysUserRange=await _virtualDbContext.Set().Where(o=>o.Name=="name_range_1001").ShardingFirstOrDefaultAsync(); - Assert.Null(sysUserRange); } [Fact] public async Task Count_Test() { - var a=await _virtualDbContext.Set().Where(o=>o.Name=="name_100").ShardingCountAsync(); + var a=await _virtualDbContext.Set().Where(o=>o.Name=="name_1000").ShardingCountAsync(); Assert.Equal(1,a); - var b=await _virtualDbContext.Set().Where(o=>o.Name!="name_100").ShardingCountAsync(); - Assert.Equal(99,b); + var b=await _virtualDbContext.Set().Where(o=>o.Name!="name_1000").ShardingCountAsync(); + Assert.Equal(999,b); } + [Fact] + public async Task Sum_Test() + { + var a = await _virtualDbContext.Set().ShardingSumAsync(o => o.Age); + var expected = 0; + for (int i = 1; i <= 1000; i++) + { + expected += i; + } + Assert.Equal(expected,a); + var b=await _virtualDbContext.Set().Where(o=>o.Name!="name_1000").ShardingSumAsync(o => o.Age); + Assert.Equal(expected-1000,b); + } + [Fact] + public async Task Max_Test() + { + var a = await _virtualDbContext.Set().ShardingMaxAsync(o => o.Age); + Assert.Equal(1000,a); + var b=await _virtualDbContext.Set().Where(o=>o.Name!="name_1000").ShardingMaxAsync(o => o.Age); + Assert.Equal(999,b); + var c=await _virtualDbContext.Set().Where(o=>o.Age<500).ShardingMaxAsync(o => o.Age); + Assert.Equal(499,c); + var e=await _virtualDbContext.Set().Where(o=>o.Age<=500).ShardingMaxAsync(o => o.Age); + Assert.Equal(500,e); + } + [Fact] + public async Task Max_Join_Test() + { + var queryable = (from u in _virtualDbContext.Set().Where(o=>o.Id=="300") + join salary in _virtualDbContext.Set() + on u.Id equals salary.UserId + select new + { + Salary = salary.Salary, + DateOfMonth=salary.DateOfMonth, + Name = u.Name + }); + var maxSalary = await queryable.ShardingMaxAsync(o => o.Salary); + Assert.Equal(1390000,maxSalary); + } + [Fact] + public async Task Min_Test() + { + var a = await _virtualDbContext.Set().ShardingMinAsync(o => o.Age); + Assert.Equal(1,a); + var b=await _virtualDbContext.Set().Where(o=>o.Name!="name_1").ShardingMinAsync(o => o.Age); + Assert.Equal(2,b); + var c=await _virtualDbContext.Set().Where(o=>o.Age>500).ShardingMinAsync(o => o.Age); + Assert.Equal(501,c); + var e=await _virtualDbContext.Set().Where(o=>o.Age>=500).ShardingMinAsync(o => o.Age); + Assert.Equal(500,e); + } + [Fact] + public async Task Any_Test() + { + var a = await _virtualDbContext.Set().ShardingAnyAsync(o => o.Age==100); + Assert.True(a); + var b=await _virtualDbContext.Set().Where(o=>o.Name!="name_1").ShardingAnyAsync(o => o.Age==1); + Assert.False(b); + var c=await _virtualDbContext.Set().Where(o=>o.Age>500).ShardingAnyAsync(o => o.Age<=500); + Assert.False(c); + var e=await _virtualDbContext.Set().Where(o=>o.Age>=500).ShardingAnyAsync(o => o.Age<=500); + Assert.True(e); + } + // [Fact] + // public async Task Group_Test() + // { + // var ids = new[] {"200", "300"}; + // var x=await (from u in _virtualDbContext.Set().Where(o=>ids.Contains(o.Id)) + // group u by u.UserId into g + // select new + // { + // AgeGroup=g.Key, + // Count=g.Count(), + // TotalSalary=g.Sum(o=>o.Salary) + // }).ToShardingListAsync(); + // var b = x; + // } } } \ No newline at end of file diff --git a/test/ShardingCore.Test50.MySql/Shardings/SysUserRangeVirtualRoute.cs b/test/ShardingCore.Test50.MySql/Shardings/SysUserRangeVirtualRoute.cs index b101efaa..daa35f69 100644 --- a/test/ShardingCore.Test50.MySql/Shardings/SysUserRangeVirtualRoute.cs +++ b/test/ShardingCore.Test50.MySql/Shardings/SysUserRangeVirtualRoute.cs @@ -1,70 +1,70 @@ -using System; -using System.Collections.Generic; -using System.Linq.Expressions; -using ShardingCore.Core.VirtualRoutes; -using ShardingCore.Core.VirtualRoutes.Abstractions; -using ShardingCore.Helpers; -using ShardingCore.Test50.MySql.Domain.Entities; - -namespace ShardingCore.Test50.MySql.Shardings -{ -/* -* @Author: xjm -* @Description: -* @Date: Wednesday, 20 January 2021 10:46:37 -* @Email: 326308290@qq.com -*/ - public class SysUserRangeVirtualRoute: AbstractShardingOperatorVirtualRoute - { - private int _mod = 1000; - protected override string ConvertToShardingKey(object shardingKey) - { - return shardingKey.ToString(); - } - - public override string ShardingKeyToTail(object shardingKey) - { - var shardingKeyStr = ConvertToShardingKey(shardingKey); - var m = Math.Abs(ShardingCoreHelper.GetStringHashCode(shardingKeyStr) % _mod); - if (m > 800)//801-999 - { - return "3"; - } else if (m > 600)//601-800 - { - return "2"; - } else if (m > 300)//301-600 - { - return "1"; - } else //0-300 - { - return "0"; - } - } - - public override List GetAllTails() - { - return new(){"0", "1","2","3"}; - } - - protected override Expression> GetRouteToFilter(string shardingKey, ShardingOperatorEnum shardingOperator) - { - var t = ShardingKeyToTail(shardingKey); - switch (shardingOperator) - { - case ShardingOperatorEnum.Equal: return tail => tail == t; - default: - { - Console.WriteLine($"shardingOperator is not equal scan all table tail"); - return tail => true; - } - } - } - - // public override List AfterPhysicTableFilter(List allPhysicTables, List filterPhysicTables) - // { - // if (filterPhysicTables.Count > 1) - // throw new Exception($"query {nameof(SysUserRange)} not support cross table"); - // return base.AfterPhysicTableFilter(allPhysicTables, filterPhysicTables); - // } - } -} \ No newline at end of file +// using System; +// using System.Collections.Generic; +// using System.Linq.Expressions; +// using ShardingCore.Core.VirtualRoutes; +// using ShardingCore.Core.VirtualRoutes.Abstractions; +// using ShardingCore.Helpers; +// using ShardingCore.Test50.MySql.Domain.Entities; +// +// namespace ShardingCore.Test50.MySql.Shardings +// { +// /* +// * @Author: xjm +// * @Description: +// * @Date: Wednesday, 20 January 2021 10:46:37 +// * @Email: 326308290@qq.com +// */ +// public class SysUserRangeVirtualRoute: AbstractShardingOperatorVirtualRoute +// { +// private int _mod = 1000; +// protected override string ConvertToShardingKey(object shardingKey) +// { +// return shardingKey.ToString(); +// } +// +// public override string ShardingKeyToTail(object shardingKey) +// { +// var shardingKeyStr = ConvertToShardingKey(shardingKey); +// var m = Math.Abs(ShardingCoreHelper.GetStringHashCode(shardingKeyStr) % _mod); +// if (m > 800)//801-999 +// { +// return "3"; +// } else if (m > 600)//601-800 +// { +// return "2"; +// } else if (m > 300)//301-600 +// { +// return "1"; +// } else //0-300 +// { +// return "0"; +// } +// } +// +// public override List GetAllTails() +// { +// return new(){"0", "1","2","3"}; +// } +// +// protected override Expression> GetRouteToFilter(string shardingKey, ShardingOperatorEnum shardingOperator) +// { +// var t = ShardingKeyToTail(shardingKey); +// switch (shardingOperator) +// { +// case ShardingOperatorEnum.Equal: return tail => tail == t; +// default: +// { +// Console.WriteLine($"shardingOperator is not equal scan all table tail"); +// return tail => true; +// } +// } +// } +// +// // public override List AfterPhysicTableFilter(List allPhysicTables, List filterPhysicTables) +// // { +// // if (filterPhysicTables.Count > 1) +// // throw new Exception($"query {nameof(SysUserRange)} not support cross table"); +// // return base.AfterPhysicTableFilter(allPhysicTables, filterPhysicTables); +// // } +// } +// } \ No newline at end of file diff --git a/test/ShardingCore.Test50.MySql/Shardings/SysUserSalaryVirtualRoute.cs b/test/ShardingCore.Test50.MySql/Shardings/SysUserSalaryVirtualRoute.cs new file mode 100644 index 00000000..de1600d4 --- /dev/null +++ b/test/ShardingCore.Test50.MySql/Shardings/SysUserSalaryVirtualRoute.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections.Generic; +using System.Linq.Expressions; +using ShardingCore.Core.VirtualRoutes; +using ShardingCore.Core.VirtualRoutes.Abstractions; +using ShardingCore.Test50.MySql.Domain.Entities; + +namespace ShardingCore.Test50.MySql.Shardings +{ +/* +* @Author: xjm +* @Description: +* @Date: Monday, 01 February 2021 15:54:55 +* @Email: 326308290@qq.com +*/ + public class SysUserSalaryVirtualRoute:AbstractShardingOperatorVirtualRoute + { + protected override int ConvertToShardingKey(object shardingKey) + { + return Convert.ToInt32(shardingKey); + } + + public override string ShardingKeyToTail(object shardingKey) + { + var time = ConvertToShardingKey(shardingKey); + return TimeFormatToTail(time); + } + + + public override List GetAllTails() + { + var beginTime = new DateTime(2020, 1, 1); + var endTime = new DateTime(2021, 12, 1); + var list = new List(24); + var tempTime = beginTime; + while (tempTime <= endTime) + { + list.Add($"{tempTime:yyyyMM}"); + tempTime = tempTime.AddMonths(1); + } + + return list; + } + + protected string TimeFormatToTail(int time) + { + var dateOfMonth=DateTime.ParseExact($"{time}","yyyyMM",System.Globalization.CultureInfo.InvariantCulture,System.Globalization.DateTimeStyles.AdjustToUniversal); + return $"{dateOfMonth:yyyyMM}"; + } + + protected override Expression> GetRouteToFilter(int shardingKey, ShardingOperatorEnum shardingOperator) + { + var t = TimeFormatToTail(shardingKey); + switch (shardingOperator) + { + case ShardingOperatorEnum.GreaterThan: + case ShardingOperatorEnum.GreaterThanOrEqual: + return tail => String.Compare(tail, t, StringComparison.Ordinal) >= 0; + case ShardingOperatorEnum.LessThan: + return tail => String.Compare(tail, t, StringComparison.Ordinal) < 0; + case ShardingOperatorEnum.LessThanOrEqual: + return tail => String.Compare(tail, t, StringComparison.Ordinal) <= 0; + case ShardingOperatorEnum.Equal: return tail => tail == t; + default: + { +#if DEBUG + Console.WriteLine($"shardingOperator is not equal scan all table tail"); +#endif + return tail => true; + } + } + } + } +} \ No newline at end of file diff --git a/test/ShardingCore.Test50.MySql/Startup.cs b/test/ShardingCore.Test50.MySql/Startup.cs index 3f9e23dd..b3d1ab4b 100644 --- a/test/ShardingCore.Test50.MySql/Startup.cs +++ b/test/ShardingCore.Test50.MySql/Startup.cs @@ -44,7 +44,7 @@ namespace ShardingCore.Test50.MySql o.ConnectionString = hostBuilderContext.Configuration.GetSection("MySql")["ConnectionString"]; o.ServerVersion = new MySqlServerVersion(new Version()); o.AddSharding(); - o.AddSharding(); + o.AddSharding(); o.CreateIfNotExists((provider, config) => { config.EnsureCreated = true; @@ -73,34 +73,41 @@ namespace ShardingCore.Test50.MySql var virtualDbContext = scope.ServiceProvider.GetService(); if (!await virtualDbContext.Set().ShardingAnyAsync(o => true)) { - var ids = Enumerable.Range(1, 100); + var ids = Enumerable.Range(1, 1000); var userMods = new List(); + var userSalaries = new List(); + var beginTime = new DateTime(2020, 1, 1); + var endTime = new DateTime(2021, 12, 1); foreach (var id in ids) { userMods.Add(new SysUserMod() { Id = id.ToString(), Age = id, - Name = $"name_{id}" + Name = $"name_{id}", + AgeGroup=Math.Abs(id%10) }); + var tempTime = beginTime; + var i = 0; + while (tempTime<=endTime) + { + var dateOfMonth = $@"{tempTime:yyyyMM}"; + userSalaries.Add(new SysUserSalary() + { + Id = $@"{id}{dateOfMonth}", + UserId = id.ToString(), + DateOfMonth = int.Parse(dateOfMonth), + Salary = 700000+id*100*i + }); + tempTime=tempTime.AddMonths(1); + i++; + } } await virtualDbContext.InsertRangeAsync(userMods); + await virtualDbContext.InsertRangeAsync(userSalaries); - - var idRanges = Enumerable.Range(1, 1000); - var userRanges = new List(); - foreach (var id in idRanges) - { - userRanges.Add(new SysUserRange() - { - Id = id.ToString(), - Age = id, - Name = $"name_range_{id}" - }); - } - await virtualDbContext.InsertRangeAsync(userRanges); await virtualDbContext.SaveChangesAsync(); } } diff --git a/test/ShardingCore.Test50/Domain/Entities/SysUserMod.cs b/test/ShardingCore.Test50/Domain/Entities/SysUserMod.cs index 3c777b7f..af923ff1 100644 --- a/test/ShardingCore.Test50/Domain/Entities/SysUserMod.cs +++ b/test/ShardingCore.Test50/Domain/Entities/SysUserMod.cs @@ -23,6 +23,7 @@ namespace ShardingCore.Test50.Domain.Entities /// 用户姓名 /// public int Age { get; set; } + public int AgeGroup { get; set; } } } \ No newline at end of file diff --git a/test/ShardingCore.Test50/Domain/Entities/SysUserRange.cs b/test/ShardingCore.Test50/Domain/Entities/SysUserRange.cs deleted file mode 100644 index 80e6b7b5..00000000 --- a/test/ShardingCore.Test50/Domain/Entities/SysUserRange.cs +++ /dev/null @@ -1,27 +0,0 @@ -using ShardingCore.Core; - -namespace ShardingCore.Test50.Domain.Entities -{ -/* -* @Author: xjm -* @Description: -* @Date: Wednesday, 20 January 2021 10:43:19 -* @Email: 326308290@qq.com -*/ - public class SysUserRange:IShardingEntity - { - /// - /// 分表分库range切分 - /// - [ShardingKey(TailPrefix = "_",AutoCreateTableOnStart = true)] - public string Id { get; set; } - /// - /// 姓名 - /// - public string Name { get; set; } - /// - /// 年龄 - /// - public int Age { get; set; } - } -} \ No newline at end of file diff --git a/test/ShardingCore.Test50/Domain/Entities/SysUserSalary.cs b/test/ShardingCore.Test50/Domain/Entities/SysUserSalary.cs new file mode 100644 index 00000000..8d75f334 --- /dev/null +++ b/test/ShardingCore.Test50/Domain/Entities/SysUserSalary.cs @@ -0,0 +1,26 @@ +using System; +using ShardingCore.Core; + +namespace ShardingCore.Test50.Domain.Entities +{ +/* +* @Author: xjm +* @Description: +* @Date: Monday, 01 February 2021 15:43:22 +* @Email: 326308290@qq.com +*/ + public class SysUserSalary:IShardingEntity + { + public string Id { get; set; } + public string UserId { get; set; } + /// + /// 每月的金额 + /// + [ShardingKey(AutoCreateTableOnStart = true)] + public int DateOfMonth { get; set; } + /// + /// 工资 + /// + public int Salary { get; set; } + } +} \ No newline at end of file diff --git a/test/ShardingCore.Test50/Domain/Entities/UserGroup.cs b/test/ShardingCore.Test50/Domain/Entities/UserGroup.cs deleted file mode 100644 index e104a6b7..00000000 --- a/test/ShardingCore.Test50/Domain/Entities/UserGroup.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace ShardingCore.Test50.Domain.Entities -{ -/* -* @Author: xjm -* @Description: -* @Date: Friday, 22 January 2021 14:17:29 -* @Email: 326308290@qq.com -*/ - public class UserGroup - { - - } -} \ No newline at end of file diff --git a/test/ShardingCore.Test50/Domain/Maps/SysUserRangeMap.cs b/test/ShardingCore.Test50/Domain/Maps/SysUserSalaryMap.cs similarity index 54% rename from test/ShardingCore.Test50/Domain/Maps/SysUserRangeMap.cs rename to test/ShardingCore.Test50/Domain/Maps/SysUserSalaryMap.cs index ce2422ba..1a58a3b3 100644 --- a/test/ShardingCore.Test50/Domain/Maps/SysUserRangeMap.cs +++ b/test/ShardingCore.Test50/Domain/Maps/SysUserSalaryMap.cs @@ -7,17 +7,17 @@ namespace ShardingCore.Test50.Domain.Maps /* * @Author: xjm * @Description: -* @Date: Wednesday, 20 January 2021 10:45:47 +* @Date: Monday, 01 February 2021 15:42:35 * @Email: 326308290@qq.com */ - public class SysUserRangeMap:IEntityTypeConfiguration + public class SysUserSalaryMap:IEntityTypeConfiguration { - public void Configure(EntityTypeBuilder builder) + public void Configure(EntityTypeBuilder builder) { builder.HasKey(o => o.Id); builder.Property(o => o.Id).IsRequired().HasMaxLength(128); - builder.Property(o => o.Name).HasMaxLength(128); - builder.ToTable(nameof(SysUserRange)); + builder.Property(o => o.UserId).IsRequired().HasMaxLength(128); + builder.ToTable(nameof(SysUserSalary)); } } } \ No newline at end of file diff --git a/test/ShardingCore.Test50/ShardingTest.cs b/test/ShardingCore.Test50/ShardingTest.cs index 89707b33..ecc4f4c0 100644 --- a/test/ShardingCore.Test50/ShardingTest.cs +++ b/test/ShardingCore.Test50/ShardingTest.cs @@ -25,166 +25,219 @@ namespace ShardingCore.Test50 [Fact] public async Task ToList_All_Test() { - var mods=await _virtualDbContext.Set().ToShardingListAsync(); - Assert.Equal(100,mods.Count); - var ranges=await _virtualDbContext.Set().ToShardingListAsync(); - Assert.Equal(1000,ranges.Count); + var mods = await _virtualDbContext.Set().ToShardingListAsync(); + Assert.Equal(1000, mods.Count); } + [Fact] public async Task ToList_OrderBy_Asc_Desc_Test() { - var modascs=await _virtualDbContext.Set().OrderBy(o=>o.Age).ToShardingListAsync(); - Assert.Equal(100,modascs.Count); + var modascs = await _virtualDbContext.Set().OrderBy(o => o.Age).ToShardingListAsync(); + Assert.Equal(1000, modascs.Count); var i = 1; foreach (var age in modascs) { - Assert.Equal(i,age.Age); + Assert.Equal(i, age.Age); i++; - } - var moddescs=await _virtualDbContext.Set().OrderByDescending(o=>o.Age).ToShardingListAsync(); - Assert.Equal(100,moddescs.Count); - var j = 100; + + var moddescs = await _virtualDbContext.Set().OrderByDescending(o => o.Age).ToShardingListAsync(); + Assert.Equal(1000, moddescs.Count); + var j = 1000; foreach (var age in moddescs) { - Assert.Equal(j,age.Age); + Assert.Equal(j, age.Age); j--; - } } + [Fact] public async Task ToList_Id_In_Test() { var ids = new[] {"1", "2", "3", "4"}; - var sysUserMods=await _virtualDbContext.Set().Where(o=>ids.Contains(o.Id)).ToShardingListAsync(); - var sysUserRanges=await _virtualDbContext.Set().Where(o=>ids.Contains(o.Id)).ToShardingListAsync(); + var sysUserMods = await _virtualDbContext.Set().Where(o => ids.Contains(o.Id)).ToShardingListAsync(); foreach (var id in ids) { - Assert.Contains(sysUserMods, o =>o.Id==id); - Assert.Contains(sysUserRanges, o =>o.Id==id); + Assert.Contains(sysUserMods, o => o.Id == id); } - Assert.DoesNotContain(sysUserMods,o=>o.Age>4); - Assert.DoesNotContain(sysUserRanges,o=>o.Age>4); + + Assert.DoesNotContain(sysUserMods, o => o.Age > 4); } + [Fact] public async Task ToList_Id_Eq_Test() { - var mods=await _virtualDbContext.Set().Where(o=>o.Id=="3").ToShardingListAsync(); + var mods = await _virtualDbContext.Set().Where(o => o.Id == "3").ToShardingListAsync(); Assert.Single(mods); - Assert.Equal("3",mods[0].Id); - var ranges=await _virtualDbContext.Set().Where(o=>o.Id=="3").ToShardingListAsync(); - Assert.Single(ranges); - Assert.Equal("3",ranges[0].Id); + Assert.Equal("3", mods[0].Id); } + [Fact] public async Task ToList_Id_Not_Eq_Test() { - var mods=await _virtualDbContext.Set().Where(o=>o.Id!="3").ToShardingListAsync(); - Assert.Equal(99,mods.Count); - Assert.DoesNotContain(mods,o=>o.Id=="3"); - var ranges=await _virtualDbContext.Set().Where(o=>o.Id!="3").ToShardingListAsync(); - Assert.Equal(999,ranges.Count); - Assert.DoesNotContain(ranges,o=>o.Id=="3"); + var mods = await _virtualDbContext.Set().Where(o => o.Id != "3").ToShardingListAsync(); + Assert.Equal(999, mods.Count); + Assert.DoesNotContain(mods, o => o.Id == "3"); } + [Fact] public async Task ToList_Id_Not_Eq_Skip_Test() { - var mods=await _virtualDbContext.Set().Where(o=>o.Id!="3").OrderBy(o=>o.Age).Skip(2).ToShardingListAsync(); - Assert.Equal(97,mods.Count); - Assert.DoesNotContain(mods,o=>o.Id=="3"); - Assert.Equal(4,mods[0].Age); - Assert.Equal(5,mods[1].Age); - - var modsDesc=await _virtualDbContext.Set().Where(o=>o.Id!="3").OrderByDescending(o=>o.Age).Skip(13).ToShardingListAsync(); - Assert.Equal(86,modsDesc.Count); - Assert.DoesNotContain(mods,o=>o.Id=="3"); - Assert.Equal(87,modsDesc[0].Age); - Assert.Equal(86,modsDesc[1].Age); + var mods = await _virtualDbContext.Set().Where(o => o.Id != "3").OrderBy(o => o.Age).Skip(2).ToShardingListAsync(); + Assert.Equal(997, mods.Count); + Assert.DoesNotContain(mods, o => o.Id == "3"); + Assert.Equal(4, mods[0].Age); + Assert.Equal(5, mods[1].Age); + + var modsDesc = await _virtualDbContext.Set().Where(o => o.Id != "3").OrderByDescending(o => o.Age).Skip(13).ToShardingListAsync(); + Assert.Equal(986, modsDesc.Count); + Assert.DoesNotContain(mods, o => o.Id == "3"); + Assert.Equal(987, modsDesc[0].Age); + Assert.Equal(986, modsDesc[1].Age); } + [Fact] public async Task ToList_Name_Eq_Test() { - var mods=await _virtualDbContext.Set().Where(o=>o.Name=="name_3").ToShardingListAsync(); + var mods = await _virtualDbContext.Set().Where(o => o.Name == "name_3").ToShardingListAsync(); Assert.Single(mods); - Assert.Equal("3",mods[0].Id); - var ranges=await _virtualDbContext.Set().Where(o=>o.Name=="name_range_3").ToShardingListAsync(); - Assert.Single(ranges); - Assert.Equal("3",ranges[0].Id); + Assert.Equal("3", mods[0].Id); } + [Fact] public async Task ToList_Id_Eq_Not_In_Db_Test() { - var mods=await _virtualDbContext.Set().Where(o=>o.Id=="1001").ToShardingListAsync(); + var mods = await _virtualDbContext.Set().Where(o => o.Id == "1001").ToShardingListAsync(); Assert.Empty(mods); - var ranges=await _virtualDbContext.Set().Where(o=>o.Id=="1001").ToShardingListAsync(); - Assert.Empty(ranges); } + [Fact] public async Task ToList_Name_Eq_Not_In_Db_Test() { - var mods=await _virtualDbContext.Set().Where(o=>o.Name=="name_1001").ToShardingListAsync(); + var mods = await _virtualDbContext.Set().Where(o => o.Name == "name_1001").ToShardingListAsync(); Assert.Empty(mods); - var ranges=await _virtualDbContext.Set().Where(o=>o.Name=="name_range_1001").ToShardingListAsync(); - Assert.Empty(ranges); } + [Fact] public async Task FirstOrDefault_Order_By_Id_Test() { - var sysUserModAge=await _virtualDbContext.Set().OrderBy(o=>o.Age).ShardingFirstOrDefaultAsync(); - Assert.True(sysUserModAge!=null&&sysUserModAge.Id=="1"); - var sysUserModAgeDesc=await _virtualDbContext.Set().OrderByDescending(o=>o.Age).ShardingFirstOrDefaultAsync(); - Assert.True(sysUserModAgeDesc!=null&&sysUserModAgeDesc.Id=="100"); - var sysUserMod=await _virtualDbContext.Set().OrderBy(o=>o.Id).ShardingFirstOrDefaultAsync(); - Assert.True(sysUserMod!=null&&sysUserMod.Id=="1"); - - var sysUserModDesc=await _virtualDbContext.Set().OrderByDescending(o=>o.Id).ShardingFirstOrDefaultAsync(); - Assert.True(sysUserModDesc!=null&&sysUserModDesc.Id=="99"); - var sysUserRange=await _virtualDbContext.Set().OrderBy(o=>o.Id).ShardingFirstOrDefaultAsync(); - Assert.True(sysUserRange!=null&&sysUserRange.Id=="1"); + var sysUserModAge = await _virtualDbContext.Set().OrderBy(o => o.Age).ShardingFirstOrDefaultAsync(); + Assert.True(sysUserModAge != null && sysUserModAge.Id == "1"); + var sysUserModAgeDesc = await _virtualDbContext.Set().OrderByDescending(o => o.Age).ShardingFirstOrDefaultAsync(); + Assert.True(sysUserModAgeDesc != null && sysUserModAgeDesc.Id == "1000"); + var sysUserMod = await _virtualDbContext.Set().OrderBy(o => o.Id).ShardingFirstOrDefaultAsync(); + Assert.True(sysUserMod != null && sysUserMod.Id == "1"); + + var sysUserModDesc = await _virtualDbContext.Set().OrderByDescending(o => o.Id).ShardingFirstOrDefaultAsync(); + Assert.True(sysUserModDesc != null && sysUserModDesc.Id == "999"); } + [Fact] public async Task FirstOrDefault2() { - var sysUserMod=await _virtualDbContext.Set().Where(o=>o.Id=="1").ShardingFirstOrDefaultAsync(); - Assert.True(sysUserMod!=null&&sysUserMod.Id=="1"); - var sysUserRange=await _virtualDbContext.Set().Where(o=>o.Id=="1").ShardingFirstOrDefaultAsync(); - Assert.True(sysUserRange!=null&&sysUserRange.Id=="1"); + var sysUserMod = await _virtualDbContext.Set().Where(o => o.Id == "1").ShardingFirstOrDefaultAsync(); + Assert.NotNull(sysUserMod); + Assert.True(sysUserMod.Id == "1"); } + [Fact] public async Task FirstOrDefault3() { - var sysUserMod=await _virtualDbContext.Set().Where(o=>o.Name=="name_2").ShardingFirstOrDefaultAsync(); + var sysUserMod = await _virtualDbContext.Set().Where(o => o.Name == "name_2").ShardingFirstOrDefaultAsync(); Assert.NotNull(sysUserMod); - Assert.Equal("2",sysUserMod.Id); - var sysUserRange=await _virtualDbContext.Set().Where(o=>o.Name=="name_range_2").ShardingFirstOrDefaultAsync(); - Assert.NotNull(sysUserRange); - Assert.Equal("2",sysUserRange.Id); + Assert.Equal("2", sysUserMod.Id); } + [Fact] public async Task FirstOrDefault4() { - var sysUserMod=await _virtualDbContext.Set().Where(o=>o.Id!="1").ShardingFirstOrDefaultAsync(); + var sysUserMod = await _virtualDbContext.Set().Where(o => o.Id != "1").ShardingFirstOrDefaultAsync(); Assert.NotNull(sysUserMod); - Assert.True(sysUserMod.Id!="1"); - var sysUserRange=await _virtualDbContext.Set().Where(o=>o.Id!="1").ShardingFirstOrDefaultAsync(); - Assert.NotNull(sysUserRange); - Assert.True(sysUserRange.Id!="1"); + Assert.True(sysUserMod.Id != "1"); } + [Fact] public async Task FirstOrDefault5() { - var sysUserMod=await _virtualDbContext.Set().Where(o=>o.Name=="name_101").ShardingFirstOrDefaultAsync(); + var sysUserMod = await _virtualDbContext.Set().Where(o => o.Name == "name_1001").ShardingFirstOrDefaultAsync(); Assert.Null(sysUserMod); - var sysUserRange=await _virtualDbContext.Set().Where(o=>o.Name=="name_range_1001").ShardingFirstOrDefaultAsync(); - Assert.Null(sysUserRange); } + [Fact] public async Task Count_Test() { - var a=await _virtualDbContext.Set().Where(o=>o.Name=="name_100").ShardingCountAsync(); - Assert.Equal(1,a); - var b=await _virtualDbContext.Set().Where(o=>o.Name!="name_100").ShardingCountAsync(); - Assert.Equal(99,b); + var a = await _virtualDbContext.Set().Where(o => o.Name == "name_1000").ShardingCountAsync(); + Assert.Equal(1, a); + var b = await _virtualDbContext.Set().Where(o => o.Name != "name_1000").ShardingCountAsync(); + Assert.Equal(999, b); } + + [Fact] + public async Task Sum_Test() + { + var a = await _virtualDbContext.Set().ShardingSumAsync(o => o.Age); + var expected = 0; + for (int i = 1; i <= 1000; i++) + { + expected += i; + } + + Assert.Equal(expected, a); + var b = await _virtualDbContext.Set().Where(o => o.Name != "name_1000").ShardingSumAsync(o => o.Age); + Assert.Equal(expected - 1000, b); + } + + [Fact] + public async Task Max_Test() + { + var a = await _virtualDbContext.Set().ShardingMaxAsync(o => o.Age); + Assert.Equal(1000, a); + var b = await _virtualDbContext.Set().Where(o => o.Name != "name_1000").ShardingMaxAsync(o => o.Age); + Assert.Equal(999, b); + var c = await _virtualDbContext.Set().Where(o => o.Age < 500).ShardingMaxAsync(o => o.Age); + Assert.Equal(499, c); + var e = await _virtualDbContext.Set().Where(o => o.Age <= 500).ShardingMaxAsync(o => o.Age); + Assert.Equal(500, e); + } + + [Fact] + public async Task Min_Test() + { + var a = await _virtualDbContext.Set().ShardingMinAsync(o => o.Age); + Assert.Equal(1, a); + var b = await _virtualDbContext.Set().Where(o => o.Name != "name_1").ShardingMinAsync(o => o.Age); + Assert.Equal(2, b); + var c = await _virtualDbContext.Set().Where(o => o.Age > 500).ShardingMinAsync(o => o.Age); + Assert.Equal(501, c); + var e = await _virtualDbContext.Set().Where(o => o.Age >= 500).ShardingMinAsync(o => o.Age); + Assert.Equal(500, e); + } + + [Fact] + public async Task Any_Test() + { + var a = await _virtualDbContext.Set().ShardingAnyAsync(o => o.Age == 100); + Assert.True(a); + var b = await _virtualDbContext.Set().Where(o => o.Name != "name_1").ShardingAnyAsync(o => o.Age == 1); + Assert.False(b); + var c = await _virtualDbContext.Set().Where(o => o.Age > 500).ShardingAnyAsync(o => o.Age <= 500); + Assert.False(c); + var e = await _virtualDbContext.Set().Where(o => o.Age >= 500).ShardingAnyAsync(o => o.Age <= 500); + Assert.True(e); + } + + // [Fact] + // public async Task Group_Test() + // { + // var x = await (from u in _virtualDbContext.Set() + // group u by u.AgeGroup + // into g + // select new + // { + // AgeGroup = g.Key, + // Count = g.Count() + // }).ToShardingListAsync(); + // var y = x; + // } } } \ No newline at end of file diff --git a/test/ShardingCore.Test50/Shardings/SysUserRangeVirtualRoute.cs b/test/ShardingCore.Test50/Shardings/SysUserRangeVirtualRoute.cs deleted file mode 100644 index 7afe0544..00000000 --- a/test/ShardingCore.Test50/Shardings/SysUserRangeVirtualRoute.cs +++ /dev/null @@ -1,70 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq.Expressions; -using ShardingCore.Core.VirtualRoutes; -using ShardingCore.Core.VirtualRoutes.Abstractions; -using ShardingCore.Helpers; -using ShardingCore.Test50.Domain.Entities; - -namespace ShardingCore.Test50.Shardings -{ -/* -* @Author: xjm -* @Description: -* @Date: Wednesday, 20 January 2021 10:46:37 -* @Email: 326308290@qq.com -*/ - public class SysUserRangeVirtualRoute: AbstractShardingOperatorVirtualRoute - { - private int _mod = 1000; - protected override string ConvertToShardingKey(object shardingKey) - { - return shardingKey.ToString(); - } - - public override string ShardingKeyToTail(object shardingKey) - { - var shardingKeyStr = ConvertToShardingKey(shardingKey); - var m = Math.Abs(ShardingCoreHelper.GetStringHashCode(shardingKeyStr) % _mod); - if (m > 800)//801-999 - { - return "3"; - } else if (m > 600)//601-800 - { - return "2"; - } else if (m > 300)//301-600 - { - return "1"; - } else //0-300 - { - return "0"; - } - } - - public override List GetAllTails() - { - return new(){"0", "1","2","3"}; - } - - protected override Expression> GetRouteToFilter(string shardingKey, ShardingOperatorEnum shardingOperator) - { - var t = ShardingKeyToTail(shardingKey); - switch (shardingOperator) - { - case ShardingOperatorEnum.Equal: return tail => tail == t; - default: - { - Console.WriteLine($"shardingOperator is not equal scan all table tail"); - return tail => true; - } - } - } - - // public override List AfterPhysicTableFilter(List allPhysicTables, List filterPhysicTables) - // { - // if (filterPhysicTables.Count > 1) - // throw new Exception($"query {nameof(SysUserRange)} not support cross table"); - // return base.AfterPhysicTableFilter(allPhysicTables, filterPhysicTables); - // } - } -} \ No newline at end of file diff --git a/test/ShardingCore.Test50/Shardings/SysUserSalaryVirtualRoute.cs b/test/ShardingCore.Test50/Shardings/SysUserSalaryVirtualRoute.cs new file mode 100644 index 00000000..d804189d --- /dev/null +++ b/test/ShardingCore.Test50/Shardings/SysUserSalaryVirtualRoute.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections.Generic; +using System.Linq.Expressions; +using ShardingCore.Core.VirtualRoutes; +using ShardingCore.Core.VirtualRoutes.Abstractions; +using ShardingCore.Test50.Domain.Entities; + +namespace ShardingCore.Test50.Shardings +{ +/* +* @Author: xjm +* @Description: +* @Date: Monday, 01 February 2021 15:54:55 +* @Email: 326308290@qq.com +*/ + public class SysUserSalaryVirtualRoute:AbstractShardingOperatorVirtualRoute + { + protected override int ConvertToShardingKey(object shardingKey) + { + return Convert.ToInt32(shardingKey); + } + + public override string ShardingKeyToTail(object shardingKey) + { + var time = ConvertToShardingKey(shardingKey); + return TimeFormatToTail(time); + } + + + public override List GetAllTails() + { + var beginTime = new DateTime(2020, 1, 1); + var endTime = new DateTime(2021, 12, 1); + var list = new List(24); + var tempTime = beginTime; + while (tempTime <= endTime) + { + list.Add($"{tempTime:yyyyMM}"); + tempTime = tempTime.AddMonths(1); + } + + return list; + } + + protected string TimeFormatToTail(int time) + { + var dateOfMonth=DateTime.ParseExact($"{time}","yyyyMM",System.Globalization.CultureInfo.InvariantCulture,System.Globalization.DateTimeStyles.AdjustToUniversal); + return $"{dateOfMonth:yyyyMM}"; + } + + protected override Expression> GetRouteToFilter(int shardingKey, ShardingOperatorEnum shardingOperator) + { + var t = TimeFormatToTail(shardingKey); + switch (shardingOperator) + { + case ShardingOperatorEnum.GreaterThan: + case ShardingOperatorEnum.GreaterThanOrEqual: + return tail => String.Compare(tail, t, StringComparison.Ordinal) >= 0; + case ShardingOperatorEnum.LessThan: + return tail => String.Compare(tail, t, StringComparison.Ordinal) < 0; + case ShardingOperatorEnum.LessThanOrEqual: + return tail => String.Compare(tail, t, StringComparison.Ordinal) <= 0; + case ShardingOperatorEnum.Equal: return tail => tail == t; + default: + { +#if DEBUG + Console.WriteLine($"shardingOperator is not equal scan all table tail"); +#endif + return tail => true; + } + } + } + } +} \ No newline at end of file diff --git a/test/ShardingCore.Test50/Startup.cs b/test/ShardingCore.Test50/Startup.cs index e8289d1a..bcffe094 100644 --- a/test/ShardingCore.Test50/Startup.cs +++ b/test/ShardingCore.Test50/Startup.cs @@ -49,7 +49,7 @@ namespace ShardingCore.Test50 { o.ConnectionString = hostBuilderContext.Configuration.GetSection("SqlServer")["ConnectionString"]; o.AddSharding(); - o.AddSharding(); + o.AddSharding(); o.CreateIfNotExists((provider, config) => { config.EnsureCreated = true; @@ -78,34 +78,40 @@ namespace ShardingCore.Test50 var virtualDbContext = scope.ServiceProvider.GetService(); if (!await virtualDbContext.Set().ShardingAnyAsync(o => true)) { - var ids = Enumerable.Range(1, 100); + var ids = Enumerable.Range(1, 1000); var userMods = new List(); + var userSalaries = new List(); + var beginTime = new DateTime(2020, 1, 1); + var endTime = new DateTime(2021, 12, 1); foreach (var id in ids) { userMods.Add(new SysUserMod() { Id = id.ToString(), Age = id, - Name = $"name_{id}" + Name = $"name_{id}", + AgeGroup=Math.Abs(id%10) }); + var tempTime = beginTime; + var i = 0; + while (tempTime<=endTime) + { + var dateOfMonth = $@"{tempTime:yyyyMM}"; + userSalaries.Add(new SysUserSalary() + { + Id = $@"{id}{dateOfMonth}", + UserId = id.ToString(), + DateOfMonth = int.Parse(dateOfMonth), + Salary = 700000+id*100*i + }); + tempTime=tempTime.AddMonths(1); + i++; + } } await virtualDbContext.InsertRangeAsync(userMods); + await virtualDbContext.InsertRangeAsync(userSalaries); - - var idRanges = Enumerable.Range(1, 1000); - var userRanges = new List(); - foreach (var id in idRanges) - { - userRanges.Add(new SysUserRange() - { - Id = id.ToString(), - Age = id, - Name = $"name_range_{id}" - }); - } - - await virtualDbContext.InsertRangeAsync(userRanges); await virtualDbContext.SaveChangesAsync(); } }