优化读写分离支持权重添加,优化sum和average的装箱拆箱

This commit is contained in:
xuejiaming 2021-11-30 16:11:06 +08:00
parent d91dd52c5e
commit be9476e591
11 changed files with 79 additions and 23 deletions

View File

@ -51,7 +51,7 @@ namespace Sample.SqlServer
o.AddShardingTableRoute<TestYearShardingVirtualTableRoute>(); o.AddShardingTableRoute<TestYearShardingVirtualTableRoute>();
}).AddReadWriteSeparation(sp => }).AddReadWriteSeparation(sp =>
{ {
return new Dictionary<string, ISet<string>>() return new Dictionary<string, IEnumerable<string>>()
{ {
{"ds0",new HashSet<string>(){"Data Source=localhost;Initial Catalog=ShardingCoreDB1;Integrated Security=True;"}} {"ds0",new HashSet<string>(){"Data Source=localhost;Initial Catalog=ShardingCoreDB1;Integrated Security=True;"}}
}; };

View File

@ -26,7 +26,7 @@ namespace ShardingCore.DIExtensions
} }
public ShardingCoreConfigEndBuilder<TShardingDbContext> AddReadWriteSeparation( public ShardingCoreConfigEndBuilder<TShardingDbContext> AddReadWriteSeparation(
Func<IServiceProvider, IDictionary<string, ISet<string>>> readWriteSeparationConfigure, Func<IServiceProvider, IDictionary<string, IEnumerable<string>>> readWriteSeparationConfigure,
ReadStrategyEnum readStrategyEnum, ReadStrategyEnum readStrategyEnum,
bool defaultEnable = false, bool defaultEnable = false,
int defaultPriority = 10, int defaultPriority = 10,

View File

@ -99,14 +99,8 @@ namespace ShardingCore.Sharding.Enumerators.AggregateExtensions
return source.Count(property); return source.Count(property);
} }
/// <summary>
/// 根据属性求和 private static MethodCallExpression CreateSumByProperty(this IQueryable source, PropertyInfo property)
/// </summary>
/// <param name="source"></param>
/// <param name="property"></param>
/// <returns></returns>
/// <exception cref="ArgumentNullException"></exception>
public static object SumByProperty(this IQueryable source, PropertyInfo property)
{ {
if (source == null) throw new ArgumentNullException(nameof(source)); if (source == null) throw new ArgumentNullException(nameof(source));
if (property == null) throw new ArgumentNullException(nameof(property)); if (property == null) throw new ArgumentNullException(nameof(property));
@ -121,15 +115,31 @@ namespace ShardingCore.Sharding.Enumerators.AggregateExtensions
&& m.ReturnType == property.PropertyType && m.ReturnType == property.PropertyType
&& m.IsGenericMethod); && m.IsGenericMethod);
var genericSumMethod = sumMethod.MakeGenericMethod(new[] {source.ElementType}); var genericSumMethod = sumMethod.MakeGenericMethod(new[] { source.ElementType });
var callExpression = Expression.Call( var callExpression = Expression.Call(
null, null,
genericSumMethod, genericSumMethod,
new[] {source.Expression, Expression.Quote(selector)}); new[] { source.Expression, Expression.Quote(selector) });
return callExpression;
}
/// <summary>
/// 根据属性求和
/// </summary>
/// <param name="source"></param>
/// <param name="property"></param>
/// <returns></returns>
/// <exception cref="ArgumentNullException"></exception>
public static object SumByProperty(this IQueryable source, PropertyInfo property)
{
var callExpression = CreateSumByProperty(source, property);
return source.Provider.Execute(callExpression); return source.Provider.Execute(callExpression);
} }
public static TSelect SumByProperty<TSelect>(this IQueryable source, PropertyInfo property)
{
var callExpression = CreateSumByProperty(source, property);
return source.Provider.Execute<TSelect>(callExpression);
}
/// <summary> /// <summary>
/// 根据属性求和 /// 根据属性求和
/// </summary> /// </summary>
@ -145,6 +155,22 @@ namespace ShardingCore.Sharding.Enumerators.AggregateExtensions
PropertyInfo property = source.ElementType.GetProperty(propertyName); PropertyInfo property = source.ElementType.GetProperty(propertyName);
return source.SumByProperty(property); return source.SumByProperty(property);
} }
/// <summary>
/// 对
/// </summary>
/// <typeparam name="TSelect"></typeparam>
/// <param name="source"></param>
/// <param name="propertyName"></param>
/// <returns></returns>
/// <exception cref="ArgumentNullException"></exception>
public static TSelect SumByPropertyName<TSelect>(this IQueryable source, string propertyName)
{
if (source == null) throw new ArgumentNullException(nameof(source));
if (propertyName == null) throw new ArgumentNullException(nameof(propertyName));
PropertyInfo property = source.ElementType.GetProperty(propertyName);
return source.SumByProperty<TSelect>(property);
}
//public static object Average(this IQueryable source, string member) //public static object Average(this IQueryable source, string member)
//{ //{
// if (source == null) throw new ArgumentNullException(nameof(source)); // if (source == null) throw new ArgumentNullException(nameof(source));
@ -312,6 +338,35 @@ namespace ShardingCore.Sharding.Enumerators.AggregateExtensions
var invoke = Expression.Lambda(binaryExpression).Compile().DynamicInvoke(); var invoke = Expression.Lambda(binaryExpression).Compile().DynamicInvoke();
return invoke; return invoke;
} }
public static TResult AverageConstant<TSum,TCount,TResult>(TSum sum, TCount count)
{
var resultType = typeof(TResult);
Expression constantSum = Expression.Constant(sum);
//如果计算类型和返回类型不一致先转成一致
if (sum.GetType() != resultType)
constantSum = Expression.Convert(constantSum, resultType);
Expression constantCount = Expression.Constant(count);
//如果计算类型和返回类型不一致先转成一致
if (count.GetType() != resultType)
constantCount = Expression.Convert(constantCount, resultType);
var binaryExpression = Expression.Divide(constantSum, constantCount);
var invoke = Expression.Lambda<Func<TResult>>(binaryExpression).Compile()();
return invoke;
}
//private static readonly Type _divideFirstDecimalType=typeof(decimal);
//private static readonly Type _divideSecondDoubleType=typeof(double);
//private static readonly Type _divideThirdFloatType=typeof(float);
//private static Type GetConvertPriorityType(Type sum, Type count, Type result)
//{
// if (_divideFirstDecimalType == sum || _divideFirstDecimalType == count || _divideFirstDecimalType == result)
// return _divideFirstDecimalType;
// if (_divideSecondDoubleType == sum || _divideSecondDoubleType == count || _divideSecondDoubleType == result)
// return _divideSecondDoubleType;
// if (_divideThirdFloatType == sum || _divideThirdFloatType == count || _divideThirdFloatType == result)
// return _divideThirdFloatType;
// return result;
//}
/// <summary> /// <summary>
/// 获取平均数和 [{avg1,sum1},{avg2,sum2}....]=>sum(sum1...n)/sum(sum1...n/avg1...n) /// 获取平均数和 [{avg1,sum1},{avg2,sum2}....]=>sum(sum1...n)/sum(sum1...n/avg1...n)
/// </summary> /// </summary>

View File

@ -85,9 +85,9 @@ namespace ShardingCore.Sharding.StreamMergeEngines.AggregateMergeEngines
Sum = o.QueryResult.Sum, Sum = o.QueryResult.Sum,
Count = o.QueryResult.Count Count = o.QueryResult.Count
}).AsQueryable(); }).AsQueryable();
var sum = queryable.SumByPropertyName(nameof(AverageResult<object>.Sum)); var sum = queryable.SumByPropertyName<TSelect>(nameof(AverageResult<object>.Sum));
var count = queryable.SumByPropertyName(nameof(AverageResult<object>.Count)); var count = queryable.Sum(o => o.Count);
return (TEnsureResult)AggregateExtension.AverageConstant(sum, count,typeof(TEnsureResult)); return AggregateExtension.AverageConstant<TSelect, long, TEnsureResult>(sum, count);
} }
} }

View File

@ -57,7 +57,7 @@ namespace ShardingCore.Sharding.StreamMergeEngines.AggregateMergeEngines
{ {
if (source.IsEmpty()) if (source.IsEmpty())
return default; return default;
var sum = source.AsQueryable().SumByPropertyName(nameof(RouteQueryResult<TInnerSelect>.QueryResult)); var sum = source.AsQueryable().SumByPropertyName<TInnerSelect>(nameof(RouteQueryResult<TInnerSelect>.QueryResult));
return ConvertSum(sum); return ConvertSum(sum);
} }
private TEnsureResult ConvertSum<TNumber>(TNumber number) private TEnsureResult ConvertSum<TNumber>(TNumber number)

View File

@ -71,7 +71,7 @@ namespace ShardingCore
//} //}
public bool UseReadWrite => ReadConnStringConfigure != null; public bool UseReadWrite => ReadConnStringConfigure != null;
public Func<IServiceProvider, IDictionary<string, ISet<string>>> ReadConnStringConfigure { get; private set; } public Func<IServiceProvider, IDictionary<string, IEnumerable<string>>> ReadConnStringConfigure { get; private set; }
public ReadStrategyEnum ReadStrategyEnum { get; private set; } public ReadStrategyEnum ReadStrategyEnum { get; private set; }
public bool ReadWriteDefaultEnable { get; private set; } public bool ReadWriteDefaultEnable { get; private set; }
public int ReadWriteDefaultPriority { get; private set; } public int ReadWriteDefaultPriority { get; private set; }
@ -85,7 +85,7 @@ namespace ShardingCore
/// <param name="defaultEnable">考虑到很多时候读写分离的延迟需要马上用到写入的数据所以默认关闭需要的话自己开启或者通过IShardingReadWriteManager,false表示默认不走读写分离除非你自己开启,true表示默认走读写分离除非你禁用,</param> /// <param name="defaultEnable">考虑到很多时候读写分离的延迟需要马上用到写入的数据所以默认关闭需要的话自己开启或者通过IShardingReadWriteManager,false表示默认不走读写分离除非你自己开启,true表示默认走读写分离除非你禁用,</param>
/// <param name="defaultPriority">IShardingReadWriteManager.CreateScope()会判断dbcontext的priority然后判断是否启用readwrite</param> /// <param name="defaultPriority">IShardingReadWriteManager.CreateScope()会判断dbcontext的priority然后判断是否启用readwrite</param>
/// <param name="readConnStringGetStrategy">读写分离可能会造成每次查询不一样甚至分表后的分页会有错位问题,因为他不是一个原子操作,所以如果整个请求为一次读写切换大多数更加合适</param> /// <param name="readConnStringGetStrategy">读写分离可能会造成每次查询不一样甚至分表后的分页会有错位问题,因为他不是一个原子操作,所以如果整个请求为一次读写切换大多数更加合适</param>
public void UseReadWriteConfiguration(Func<IServiceProvider, IDictionary<string, ISet<string>>> readConnStringConfigure, ReadStrategyEnum readStrategyEnum, bool defaultEnable = false, int defaultPriority = 10, ReadConnStringGetStrategyEnum readConnStringGetStrategy = ReadConnStringGetStrategyEnum.LatestFirstTime) public void UseReadWriteConfiguration(Func<IServiceProvider, IDictionary<string, IEnumerable<string>>> readConnStringConfigure, ReadStrategyEnum readStrategyEnum, bool defaultEnable = false, int defaultPriority = 10, ReadConnStringGetStrategyEnum readConnStringGetStrategy = ReadConnStringGetStrategyEnum.LatestFirstTime)
{ {
ReadConnStringConfigure = readConnStringConfigure ?? throw new ArgumentNullException(nameof(readConnStringConfigure)); ReadConnStringConfigure = readConnStringConfigure ?? throw new ArgumentNullException(nameof(readConnStringConfigure));
ReadStrategyEnum = readStrategyEnum; ReadStrategyEnum = readStrategyEnum;

View File

@ -899,6 +899,7 @@ namespace ShardingCore.Test
[Fact] [Fact]
public async Task OrderReadWrite() public async Task OrderReadWrite()
{ {
//切换到只读数据库只读数据库又只配置了A数据源读取B数据源 //切换到只读数据库只读数据库又只配置了A数据源读取B数据源
_virtualDbContext.ReadWriteSeparationReadOnly(); _virtualDbContext.ReadWriteSeparationReadOnly();
var list = await _virtualDbContext.Set<Order>().Where(o => o.Money == 1).ToListAsync(); var list = await _virtualDbContext.Set<Order>().Where(o => o.Money == 1).ToListAsync();

View File

@ -73,7 +73,7 @@ namespace ShardingCore.Test
op.AddShardingTableRoute<LogDayLongVirtualRoute>(); op.AddShardingTableRoute<LogDayLongVirtualRoute>();
}).AddReadWriteSeparation(sp => }).AddReadWriteSeparation(sp =>
{ {
return new Dictionary<string, ISet<string>>() return new Dictionary<string, IEnumerable<string>>()
{ {
{ {
"A", new HashSet<string>() "A", new HashSet<string>()

View File

@ -69,7 +69,7 @@ namespace ShardingCore.Test2x
op.AddShardingTableRoute<LogDayLongVirtualRoute>(); op.AddShardingTableRoute<LogDayLongVirtualRoute>();
}).AddReadWriteSeparation(sp => }).AddReadWriteSeparation(sp =>
{ {
return new Dictionary<string, ISet<string>>() return new Dictionary<string, IEnumerable<string>>()
{ {
{ {
"A", new HashSet<string>() "A", new HashSet<string>()

View File

@ -69,7 +69,7 @@ namespace ShardingCore.Test3x
op.AddShardingTableRoute<LogDayLongVirtualRoute>(); op.AddShardingTableRoute<LogDayLongVirtualRoute>();
}).AddReadWriteSeparation(sp => }).AddReadWriteSeparation(sp =>
{ {
return new Dictionary<string, ISet<string>>() return new Dictionary<string, IEnumerable<string>>()
{ {
{ {
"A", new HashSet<string>() "A", new HashSet<string>()

View File

@ -69,7 +69,7 @@ namespace ShardingCore.Test5x
op.AddShardingTableRoute<LogDayLongVirtualRoute>(); op.AddShardingTableRoute<LogDayLongVirtualRoute>();
}).AddReadWriteSeparation(sp => }).AddReadWriteSeparation(sp =>
{ {
return new Dictionary<string, ISet<string>>() return new Dictionary<string, IEnumerable<string>>()
{ {
{ {
"A", new HashSet<string>() "A", new HashSet<string>()