[#166] 提交首次将first or default修改

This commit is contained in:
xuejiaming 2022-07-03 22:26:31 +08:00
parent 89a8e66a6f
commit 7e3b0c4025
21 changed files with 262 additions and 327 deletions

View File

@ -26,6 +26,8 @@ namespace Sample.MySql.Controllers
[HttpGet]
public async Task<IActionResult> Get()
{
var resultX = await _defaultTableDbContext.Set<SysUserMod>().Where(o => o.Id == "2" || o.Id == "3").FirstOrDefaultAsync();
var resultY = await _defaultTableDbContext.Set<SysUserMod>().FirstOrDefaultAsync(o => o.Id == "2" || o.Id == "3");
var result = await _defaultTableDbContext.Set<SysTest>().AnyAsync();
var result1 = await _defaultTableDbContext.Set<SysUserMod>().Where(o => o.Id == "2" || o.Id == "3").ToListAsync();
var result2 = await _defaultTableDbContext.Set<SysUserLogByMonth>().Skip(1).Take(10).ToListAsync();

View File

@ -7,6 +7,8 @@ using ShardingCore.Bootstrappers;
using ShardingCore.Core;
using ShardingCore.Core.RuntimeContexts;
using ShardingCore.Extensions;
using ShardingCore.TableExists;
using ShardingCore.TableExists.Abstractions;
namespace Sample.MySql
{
@ -59,7 +61,7 @@ namespace Sample.MySql
builder.UseMySql(connection, new MySqlServerVersion(new Version())).UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking).UseLoggerFactory(efLogger);
});
o.AddDefaultDataSource("ds0", "server=127.0.0.1;port=3306;database=dbdbd0;userid=root;password=root;");
})
}).ReplaceService<ITableEnsureManager,MySqlTableEnsureManager>(ServiceLifetime.Singleton)
.Build(sp);
stopwatch.Stop();
Console.WriteLine("ShardingRuntimeContext build:"+stopwatch.ElapsedMilliseconds);

View File

@ -27,14 +27,6 @@ namespace ShardingCore.Extensions
private static readonly MethodInfo QueryableTakeMethod = typeof(Queryable).GetMethods().First(
m => m.Name == nameof(Queryable.Take)
&& m.GetParameters().Length == 2 && m.GetParameters()[1].ParameterType == typeof(int));
internal static ExtraEntry GetExtraEntry<T>(this IQueryable<T> source)
{
var extraVisitor = new QueryableExtraDiscoverVisitor();
extraVisitor.Visit(source.Expression);
var extraEntry = new ExtraEntry(extraVisitor.GetPaginationContext().Skip, extraVisitor.GetPaginationContext().Take, extraVisitor.GetOrderByContext().PropertyOrders,extraVisitor.GetSelectContext(),extraVisitor.GetGroupByContext());
extraEntry.ProcessGroupBySelectProperties();
return extraEntry;
}
/// <summary>
/// 删除Skip表达式
/// </summary>

View File

@ -0,0 +1,13 @@
using System.Linq;
namespace ShardingCore.Sharding.Abstractions
{
public interface IMergeContext
{
IQueryable GetCombineQueryable();
IQueryable GetRewriteQueryable();
int? GetSkip();
int? GetTake();
}
}

View File

@ -4,7 +4,6 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using ShardingCore.Core.Internal.StreamMerge;
using ShardingCore.Extensions;
namespace ShardingCore.Sharding.Enumerators

View File

@ -16,9 +16,9 @@ namespace ShardingCore.Sharding.MergeContexts
public IParseResult Parse(IMergeQueryCompilerContext mergeQueryCompilerContext)
{
var isEnumerableQuery = mergeQueryCompilerContext.IsEnumerableQuery();
string queryMethodName = isEnumerableQuery ? null : mergeQueryCompilerContext.QueryMethodName();
string queryMethodName = mergeQueryCompilerContext.GetQueryMethodName();
var combineQueryable = mergeQueryCompilerContext.GetQueryCombineResult().GetCombineQueryable();
var queryableExtraDiscoverVisitor = new QueryableExtraDiscoverVisitor();
var queryableExtraDiscoverVisitor = new QueryableExtraDiscoverVisitor(mergeQueryCompilerContext);
queryableExtraDiscoverVisitor.Visit(combineQueryable.Expression);
return new ParseResult(queryableExtraDiscoverVisitor.GetPaginationContext(),
queryableExtraDiscoverVisitor.GetOrderByContext(), queryableExtraDiscoverVisitor.GetSelectContext(),

View File

@ -21,11 +21,12 @@ namespace ShardingCore.Sharding.MergeContexts
public sealed class QueryableRewriteEngine : IQueryableRewriteEngine
{
private static readonly ISet<string> singleEntityMethodNames = new HashSet<string>();
private static readonly ISet<string> supportSingleEntityMethodNames = new HashSet<string>();
static QueryableRewriteEngine()
{
singleEntityMethodNames.Add(nameof(Enumerable.First));
singleEntityMethodNames.Add(nameof(Enumerable.FirstOrDefault));
supportSingleEntityMethodNames.Add(nameof(Enumerable.First));
supportSingleEntityMethodNames.Add(nameof(Enumerable.FirstOrDefault));
singleEntityMethodNames.Add(nameof(Enumerable.Last));
singleEntityMethodNames.Add(nameof(Enumerable.LastOrDefault));
singleEntityMethodNames.Add(nameof(Enumerable.Single));
@ -46,7 +47,7 @@ namespace ShardingCore.Sharding.MergeContexts
{
if (!mergeQueryCompilerContext.IsEnumerableQuery())
{
var queryMethodName = mergeQueryCompilerContext.QueryMethodName();
var queryMethodName = mergeQueryCompilerContext.GetQueryMethodName();
if (singleEntityMethodNames.Contains(queryMethodName))
{
//todo 修复做兼容
@ -69,17 +70,33 @@ namespace ShardingCore.Sharding.MergeContexts
reWriteQueryable = reWriteQueryable.RemoveSkip();
}
if (take.HasValue)
//如果是first or default
var fixedTake = mergeQueryCompilerContext.GetFixedTake();
if (fixedTake.HasValue)
{
if (skip.HasValue)
{
reWriteQueryable = reWriteQueryable.ReSkip(0).ReTake(take.Value + skip.GetValueOrDefault());
reWriteQueryable = reWriteQueryable.ReSkip(0).ReTake(fixedTake.Value + skip.GetValueOrDefault());
}
else
{
reWriteQueryable = reWriteQueryable.ReTake(take.Value + skip.GetValueOrDefault());
reWriteQueryable = reWriteQueryable.ReTake(fixedTake.Value);
}
}
else
{
if (take.HasValue)
{
if (skip.HasValue)
{
reWriteQueryable = reWriteQueryable.ReSkip(0).ReTake(take.Value + skip.GetValueOrDefault());
}
else
{
reWriteQueryable = reWriteQueryable.ReTake(take.Value + skip.GetValueOrDefault());
}
}
}
//包含group by
if (groupByContext.GroupExpression != null)
{

View File

@ -107,7 +107,7 @@ namespace ShardingCore.Sharding.MergeEngines.EnumeratorStreamMergeEngines.Enumer
var sequenceResults = new SequencePaginationList(sortRouteResults.Select(o => o.RouteQueryResult)).Skip(skip).Take(take).ToList();
GetStreamMergeContext().ReSetOrders(reSetOrders);
GetStreamMergeContext().ReSetOrders(reSetOrders.ToArray());
return sequenceResults.Select(sequenceResult => new SqlSequenceRouteUnit(sequenceResult));
}

View File

@ -1,68 +1,75 @@
// using System.Collections.Generic;
// using System.Linq;
// using System.Threading;
// using System.Threading.Tasks;
// using ShardingCore.Extensions;
// using ShardingCore.Sharding.MergeEngines.Abstractions.InMemoryMerge;
// using ShardingCore.Sharding.MergeEngines.EnumeratorStreamMergeEngines;
//
// namespace ShardingCore.Sharding.MergeEngines
// {
// /*
// * @Author: xjm
// * @Description:
// * @Date: 2021/8/17 15:16:36
// * @Ver: 1.0
// * @Email: 326308290@qq.com
// */
// internal class FirstOrDefaultSkipAsyncInMemoryMergeEngine<TEntity> : IEnsureMergeResult<TEntity>
// {
// private readonly StreamMergeContext _streamMergeContext;
//
// public FirstOrDefaultSkipAsyncInMemoryMergeEngine(StreamMergeContext streamMergeContext)
// {
// _streamMergeContext = streamMergeContext;
// }
// // protected override IExecutor<RouteQueryResult<TEntity>> CreateExecutor0(bool async)
// // {
// // return new FirstOrDefaultMethodExecutor<TEntity>(GetStreamMergeContext());
// // }
// //
// // protected override TEntity DoMergeResult0(List<RouteQueryResult<TEntity>> resultList)
// // {
// // var notNullResult = resultList.Where(o => o != null && o.HasQueryResult()).Select(o => o.QueryResult).ToList();
// //
// // if (notNullResult.IsEmpty())
// // return default;
// //
// // var streamMergeContext = GetStreamMergeContext();
// // if (streamMergeContext.Orders.Any())
// // return notNullResult.AsQueryable().OrderWithExpression(streamMergeContext.Orders, streamMergeContext.GetShardingComparer()).FirstOrDefault();
// //
// // return notNullResult.FirstOrDefault();
// // }
// public TEntity MergeResult()
// {
// return MergeResultAsync().WaitAndUnwrapException(false);
// }
//
// public async Task<TEntity> MergeResultAsync(CancellationToken cancellationToken = new CancellationToken())
// {
//
// //将toke改成1
// var asyncEnumeratorStreamMergeEngine = new AsyncEnumeratorStreamMergeEngine<TEntity>(_streamMergeContext);
//
// var list = new List<TEntity>();
// await foreach (var element in asyncEnumeratorStreamMergeEngine.WithCancellation(cancellationToken))
// {
// list.Add(element);
// }
//
// if (list.IsEmpty())
// {
// return default;
// }
// return list.FirstOrDefault();
// }
// }
// }
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using ShardingCore.Extensions;
using ShardingCore.Sharding.MergeEngines.Abstractions.InMemoryMerge;
using ShardingCore.Sharding.MergeEngines.EnumeratorStreamMergeEngines;
namespace ShardingCore.Sharding.MergeEngines
{
/*
* @Author: xjm
* @Description:
* @Date: 2021/8/17 15:16:36
* @Ver: 1.0
* @Email: 326308290@qq.com
*/
internal class FirstOrDefaultSkipAsyncInMemoryMergeEngine<TEntity> : IEnsureMergeResult<TEntity>
{
private readonly StreamMergeContext _streamMergeContext;
public FirstOrDefaultSkipAsyncInMemoryMergeEngine(StreamMergeContext streamMergeContext)
{
_streamMergeContext = streamMergeContext;
}
// protected override IExecutor<RouteQueryResult<TEntity>> CreateExecutor0(bool async)
// {
// return new FirstOrDefaultMethodExecutor<TEntity>(GetStreamMergeContext());
// }
//
// protected override TEntity DoMergeResult0(List<RouteQueryResult<TEntity>> resultList)
// {
// var notNullResult = resultList.Where(o => o != null && o.HasQueryResult()).Select(o => o.QueryResult).ToList();
//
// if (notNullResult.IsEmpty())
// return default;
//
// var streamMergeContext = GetStreamMergeContext();
// if (streamMergeContext.Orders.Any())
// return notNullResult.AsQueryable().OrderWithExpression(streamMergeContext.Orders, streamMergeContext.GetShardingComparer()).FirstOrDefault();
//
// return notNullResult.FirstOrDefault();
// }
public TEntity MergeResult()
{
return MergeResultAsync().WaitAndUnwrapException(false);
}
public async Task<TEntity> MergeResultAsync(CancellationToken cancellationToken = new CancellationToken())
{
//将toke改成1
var asyncEnumeratorStreamMergeEngine = new AsyncEnumeratorStreamMergeEngine<TEntity>(_streamMergeContext);
#if EFCORE2
var list = await asyncEnumeratorStreamMergeEngine.ToList<TEntity>(cancellationToken);
#endif
#if !EFCORE2
var take = _streamMergeContext.GetTake();
var list = new List<TEntity>(take??31);
await foreach (var element in asyncEnumeratorStreamMergeEngine.WithCancellation(cancellationToken))
{
list.Add(element);
}
#endif
if (list.IsEmpty())
{
return default;
}
return list.FirstOrDefault();
}
}
}

View File

@ -1,73 +1,78 @@
// using System;
// using System.Collections.Generic;
// using System.Linq;
// using System.Threading;
// using System.Threading.Tasks;
// using ShardingCore.Extensions;
// using ShardingCore.Sharding.MergeEngines.Abstractions.InMemoryMerge;
// using ShardingCore.Sharding.MergeEngines.EnumeratorStreamMergeEngines;
//
// namespace ShardingCore.Sharding.MergeEngines
// {
//
// public class FirstSkipAsyncInMemoryMergeEngine<TEntity> : IEnsureMergeResult<TEntity>
// {
// private readonly StreamMergeContext _streamMergeContext;
//
// public FirstSkipAsyncInMemoryMergeEngine(StreamMergeContext streamMergeContext)
// {
// _streamMergeContext = streamMergeContext;
// }
// // protected override IExecutor<RouteQueryResult<TEntity>> CreateExecutor0(bool async)
// // {
// // return new FirstOrDefaultMethodExecutor<TEntity>(GetStreamMergeContext());
// // }
// //
// // protected override TEntity DoMergeResult0(List<RouteQueryResult<TEntity>> resultList)
// // {
// // var notNullResult = resultList.Where(o => o != null && o.HasQueryResult()).Select(o => o.QueryResult).ToList();
// //
// // if (notNullResult.IsEmpty())
// // return default;
// //
// // var streamMergeContext = GetStreamMergeContext();
// // if (streamMergeContext.Orders.Any())
// // return notNullResult.AsQueryable().OrderWithExpression(streamMergeContext.Orders, streamMergeContext.GetShardingComparer()).FirstOrDefault();
// //
// // return notNullResult.FirstOrDefault();
// // }
// public TEntity MergeResult()
// {
// return MergeResultAsync().WaitAndUnwrapException(false);
// }
//
// public async Task<TEntity> MergeResultAsync(CancellationToken cancellationToken = new CancellationToken())
// {
//
// //将toke改成1
// var asyncEnumeratorStreamMergeEngine = new AsyncEnumeratorStreamMergeEngine<TEntity>(_streamMergeContext);
//
// var list = new List<TEntity>();
// await foreach (var element in asyncEnumeratorStreamMergeEngine.WithCancellation(cancellationToken))
// {
// list.Add(element);
// }
//
// if (list.IsEmpty())
// throw new InvalidOperationException("Sequence contains no elements.");
//
// return list.First();
// }
//
//
// // if (notNullResult.IsEmpty())
// // throw new InvalidOperationException("Sequence contains no elements.");
// //
// // var streamMergeContext = GetStreamMergeContext();
// // if (streamMergeContext.Orders.Any())
// // return notNullResult.AsQueryable().OrderWithExpression(streamMergeContext.Orders, streamMergeContext.GetShardingComparer()).First();
// //
// // return notNullResult.First();
// }
// }
//
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using ShardingCore.Extensions;
using ShardingCore.Sharding.MergeEngines.Abstractions.InMemoryMerge;
using ShardingCore.Sharding.MergeEngines.EnumeratorStreamMergeEngines;
namespace ShardingCore.Sharding.MergeEngines
{
public class FirstSkipAsyncInMemoryMergeEngine<TEntity> : IEnsureMergeResult<TEntity>
{
private readonly StreamMergeContext _streamMergeContext;
public FirstSkipAsyncInMemoryMergeEngine(StreamMergeContext streamMergeContext)
{
_streamMergeContext = streamMergeContext;
}
// protected override IExecutor<RouteQueryResult<TEntity>> CreateExecutor0(bool async)
// {
// return new FirstOrDefaultMethodExecutor<TEntity>(GetStreamMergeContext());
// }
//
// protected override TEntity DoMergeResult0(List<RouteQueryResult<TEntity>> resultList)
// {
// var notNullResult = resultList.Where(o => o != null && o.HasQueryResult()).Select(o => o.QueryResult).ToList();
//
// if (notNullResult.IsEmpty())
// return default;
//
// var streamMergeContext = GetStreamMergeContext();
// if (streamMergeContext.Orders.Any())
// return notNullResult.AsQueryable().OrderWithExpression(streamMergeContext.Orders, streamMergeContext.GetShardingComparer()).FirstOrDefault();
//
// return notNullResult.FirstOrDefault();
// }
public TEntity MergeResult()
{
return MergeResultAsync().WaitAndUnwrapException(false);
}
public async Task<TEntity> MergeResultAsync(CancellationToken cancellationToken = new CancellationToken())
{
//将toke改成1
var asyncEnumeratorStreamMergeEngine = new AsyncEnumeratorStreamMergeEngine<TEntity>(_streamMergeContext);
#if EFCORE2
var list = await asyncEnumeratorStreamMergeEngine.ToList<TEntity>(cancellationToken);
#endif
#if !EFCORE2
var take = _streamMergeContext.GetTake();
var list = new List<TEntity>(take??31);
await foreach (var element in asyncEnumeratorStreamMergeEngine.WithCancellation(cancellationToken))
{
list.Add(element);
}
#endif
if (list.IsEmpty())
throw new InvalidOperationException("Sequence contains no elements.");
return list.First();
}
// if (notNullResult.IsEmpty())
// throw new InvalidOperationException("Sequence contains no elements.");
//
// var streamMergeContext = GetStreamMergeContext();
// if (streamMergeContext.Orders.Any())
// return notNullResult.AsQueryable().OrderWithExpression(streamMergeContext.Orders, streamMergeContext.GetShardingComparer()).First();
//
// return notNullResult.First();
}
}

View File

@ -1,99 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Extensions.DependencyInjection;
using ShardingCore.Core.EntityMetadatas;
using ShardingCore.Core.Internal.Visitors;
using ShardingCore.Exceptions;
using ShardingCore.Extensions;
using ShardingCore.Extensions.InternalExtensions;
using ShardingCore.Sharding.MergeContexts;
using ShardingCore.Sharding.Visitors.Selects;
namespace ShardingCore.Core.Internal.StreamMerge.ReWrite
{
/*
* @Author: xjm
* @Description:
* @Date: Thursday, 28 January 2021 23:44:24
* @Email: 326308290@qq.com
*/
internal class ReWriteEngine<T>
{
private readonly IQueryable<T> _queryable;
public ReWriteEngine(IQueryable<T> queryable)
{
_queryable = queryable;
}
public ReWriteResult<T> ReWrite()
{
var extraEntry = _queryable.GetExtraEntry();
var skip = extraEntry.Skip;
var take = extraEntry.Take;
var orders = extraEntry.Orders ?? Enumerable.Empty<PropertyOrder>();
//去除分页,获取前Take+Skip数量
var reWriteQueryable = _queryable;
if (take.HasValue)
{
reWriteQueryable = reWriteQueryable.RemoveTake().As<IQueryable<T>>();
}
if (skip.HasValue)
{
reWriteQueryable = reWriteQueryable.RemoveSkip().As<IQueryable<T>>();
}
if (take.HasValue)
{
if (skip.HasValue)
{
reWriteQueryable = reWriteQueryable.Skip(0).Take(take.Value + skip.GetValueOrDefault());
}
else
{
reWriteQueryable = reWriteQueryable.Take(take.Value + skip.GetValueOrDefault());
}
}
//包含group by
if (extraEntry.GroupByContext.GroupExpression != null)
{
if (orders.IsEmpty())
{
//将查询的属性转换成order by
var selectProperties = extraEntry.SelectContext.SelectProperties.Where(o => !(o is SelectAggregateProperty));
if (selectProperties.IsNotEmpty())
{
var sort = string.Join(",",selectProperties.Select(o=>$"{o.PropertyName} asc"));
reWriteQueryable = reWriteQueryable.OrderWithExpression(sort,null);
var reWriteOrders = new List<PropertyOrder>(selectProperties.Count());
foreach (var orderProperty in selectProperties)
{
reWriteOrders.Add(new PropertyOrder(orderProperty.PropertyName,true, orderProperty.OwnerType));
}
orders = reWriteOrders;
}
}
else
{
//将查询的属性转换成order by 并且order和select的未聚合查询必须一致
var selectProperties = extraEntry.SelectContext.SelectProperties.Where(o => !(o is SelectAggregateProperty));
if (orders.Count() != selectProperties.Count())
throw new ShardingCoreInvalidOperationException("group by query order items not equal select un-aggregate items");
var os=orders.Select(o => o.PropertyExpression).ToList();
var ss = selectProperties.Select(o => o.PropertyName).ToList();
for (int i = 0; i < os.Count(); i++)
{
if(!os[i].Equals(ss[i]))
throw new ShardingCoreInvalidOperationException($"group by query order items not equal select un-aggregate items: order:[{os[i]}],select:[{ss[i]}");
}
}
}
return new ReWriteResult<T>(_queryable,reWriteQueryable,skip,take,orders,extraEntry.SelectContext,extraEntry.GroupByContext);
}
}
}

View File

@ -1,37 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using ShardingCore.Core.Internal.Visitors;
using ShardingCore.Core.Internal.Visitors.Selects;
using ShardingCore.Sharding.MergeContexts;
namespace ShardingCore.Core.Internal.StreamMerge.ReWrite
{
/*
* @Author: xjm
* @Description:
* @Date: Thursday, 28 January 2021 23:45:29
* @Email: 326308290@qq.com
*/
internal class ReWriteResult<T>
{
public ReWriteResult(IQueryable<T> originalQueryable, IQueryable<T> reWriteQueryable, int? skip, int? take, IEnumerable<PropertyOrder> orders, SelectContext selectContext, GroupByContext groupByContext)
{
OriginalQueryable = originalQueryable;
ReWriteQueryable = reWriteQueryable;
Skip = skip;
Take = take;
Orders = orders;
SelectContext = selectContext;
GroupByContext = groupByContext;
}
public IQueryable<T> OriginalQueryable { get; }
public IQueryable<T> ReWriteQueryable { get; }
public int? Skip { get; }
public int? Take { get; }
public IEnumerable<PropertyOrder> Orders { get; }
public SelectContext SelectContext { get; }
public GroupByContext GroupByContext { get; }
}
}

View File

@ -18,8 +18,6 @@ namespace ShardingCore.Sharding.ShardingExecutors.Abstractions
bool IsCrossTable();
bool IsCrossDataSource();
string QueryMethodName();
//bool IsEnumerableQuery();
int? GetFixedTake();
}
}

View File

@ -30,6 +30,7 @@ namespace ShardingCore.Sharding.ShardingExecutors.Abstractions
/// <returns></returns>
QueryCompilerExecutor GetQueryCompilerExecutor();
bool IsEnumerableQuery();
string GetQueryMethodName();
/// <summary>
/// 当前是否读写分离走读库(包括是否启用读写分离和是否当前的dbcontext启用了读库查询)

View File

@ -15,6 +15,7 @@ using Microsoft.Extensions.Logging;
using ShardingCore.Core;
using ShardingCore.Extensions.InternalExtensions;
using ShardingCore.Logger;
using ShardingCore.Sharding.MergeEngines;
#if EFCORE2
using Microsoft.EntityFrameworkCore.Internal;
#endif
@ -70,13 +71,13 @@ namespace ShardingCore.Sharding.ShardingQueryExecutors
}
private TResult DoExecute<TResult>(IMergeQueryCompilerContext mergeQueryCompilerContext, bool async, CancellationToken cancellationToken = new CancellationToken())
{
var queryMethodName = mergeQueryCompilerContext.QueryMethodName();
var queryMethodName = mergeQueryCompilerContext.GetQueryMethodName();
switch (queryMethodName)
{
case nameof(Enumerable.First):
return EnsureResultTypeMergeExecute<TResult>(typeof(FirstAsyncInMemoryMergeEngine<>), mergeQueryCompilerContext, async, cancellationToken);
return EnsureResultTypeMergeExecute<TResult>(typeof(FirstSkipAsyncInMemoryMergeEngine<>), mergeQueryCompilerContext, async, cancellationToken);
case nameof(Enumerable.FirstOrDefault):
return EnsureResultTypeMergeExecute<TResult>(typeof(FirstOrDefaultAsyncInMemoryMergeEngine<>), mergeQueryCompilerContext, async, cancellationToken);
return EnsureResultTypeMergeExecute<TResult>(typeof(FirstOrDefaultSkipAsyncInMemoryMergeEngine<>), mergeQueryCompilerContext, async, cancellationToken);
case nameof(Enumerable.Last):
return EnsureResultTypeMergeExecute<TResult>(typeof(LastAsyncInMemoryMergeEngine<>), mergeQueryCompilerContext, async, cancellationToken);
case nameof(Enumerable.LastOrDefault):

View File

@ -49,6 +49,7 @@ namespace ShardingCore.Sharding.ShardingExecutors
private QueryCompilerExecutor _queryCompilerExecutor;
private bool? hasQueryCompilerExecutor;
private readonly int? _fixedTake;
private MergeQueryCompilerContext(IShardingRuntimeContext shardingRuntimeContext,IQueryCompilerContext queryCompilerContext, QueryCombineResult queryCombineResult, ShardingRouteResult shardingRouteResult)
{
_shardingRuntimeContext = shardingRuntimeContext;
@ -60,6 +61,11 @@ namespace ShardingCore.Sharding.ShardingExecutors
_isCrossDataSource = shardingRouteResult.IsCrossDataSource;
_isCrossTable = shardingRouteResult.IsCrossTable;
_existCrossTableTails = shardingRouteResult.ExistCrossTableTails;
var queryMethodName = queryCompilerContext.GetQueryMethodName();
if (nameof(Enumerable.First) == queryMethodName || nameof(Enumerable.FirstOrDefault) == queryMethodName)
{
_fixedTake = 1;
}
}
//
// private IEnumerable<TableRouteResult> GetTableRouteResults(IEnumerable<TableRouteResult> tableRouteResults)
@ -208,6 +214,11 @@ namespace ShardingCore.Sharding.ShardingExecutors
return _queryCompilerContext.IsEnumerableQuery();
}
public string GetQueryMethodName()
{
return _queryCompilerContext.GetQueryMethodName();
}
/// <summary>
/// 如果需要聚合并且存在跨tail的查询或者本次是读链接
/// </summary>
@ -217,23 +228,9 @@ namespace ShardingCore.Sharding.ShardingExecutors
return _isCrossTable || _existCrossTableTails|| _queryCompilerContext.IsParallelQuery();
}
public string QueryMethodName()
public int? GetFixedTake()
{
if (IsEnumerableQuery())
{
throw new ShardingCoreInvalidOperationException(
$"queryable:[{GetQueryExpression().ShardingPrint()}] is enumerable query cant found query method name");
}
if (GetQueryExpression() is MethodCallExpression methodCallExpression)
{
return methodCallExpression.Method.Name;
}
else
{
throw new ShardingCoreInvalidOperationException(
$"queryable:[{GetQueryExpression().ShardingPrint()}] not {nameof(MethodCallExpression)} cant found query method name");
}
return _fixedTake;
}
}
}

View File

@ -11,6 +11,7 @@ using System.Linq;
using System.Linq.Expressions;
using ShardingCore.Core;
using ShardingCore.Core.RuntimeContexts;
using ShardingCore.Exceptions;
using ShardingCore.Sharding.Parsers;
using ShardingCore.Sharding.Parsers.Abstractions;
@ -18,6 +19,7 @@ namespace ShardingCore.Sharding.ShardingExecutors
{
public class QueryCompilerContext: IQueryCompilerContext
{
public const string ENUMERABLE = "Enumerable";
private readonly Dictionary<Type/* 查询对象类型 */, IQueryable/* 查询对象对应的表达式 */> _queryEntities;
private readonly IShardingDbContext _shardingDbContext;
private readonly IShardingRuntimeContext _shardingRuntimeContext;
@ -33,6 +35,7 @@ namespace ShardingCore.Sharding.ShardingExecutors
private readonly ConnectionModeEnum? _connectionMode;
private readonly bool? _isSequence;
private readonly bool? _sameWithShardingComparer;
private readonly string _queryMethodName;
private QueryCompilerContext(IPrepareParseResult prepareParseResult)
{
@ -47,13 +50,32 @@ namespace ShardingCore.Sharding.ShardingExecutors
_maxQueryConnectionsLimit = prepareParseResult.GetMaxQueryConnectionsLimit();
_connectionMode = prepareParseResult.GetConnectionMode();
_entityMetadataManager = _shardingRuntimeContext.GetEntityMetadataManager();
_queryMethodName = QueryMethodName(_queryExpression);
//原生对象的原生查询如果是读写分离就需要启用并行查询
_isParallelQuery = prepareParseResult.ReadOnly().GetValueOrDefault();
_isSequence = prepareParseResult.IsSequence();
_sameWithShardingComparer = prepareParseResult.SameWithShardingComparer();
}
private string QueryMethodName(Expression queryExpression)
{
var isEnumerableQuery = queryExpression.Type
.HasImplementedRawGeneric(typeof(IQueryable<>));
if (isEnumerableQuery)
{
return ENUMERABLE;
}
if (queryExpression is MethodCallExpression methodCallExpression)
{
return methodCallExpression.Method.Name;
}
else
{
throw new ShardingCoreInvalidOperationException(
$"queryable:[{queryExpression.ShardingPrint()}] not {nameof(MethodCallExpression)} cant found query method name");
}
}
public static QueryCompilerContext Create(IPrepareParseResult prepareParseResult)
{
return new QueryCompilerContext(prepareParseResult);
@ -159,8 +181,12 @@ namespace ShardingCore.Sharding.ShardingExecutors
public bool IsEnumerableQuery()
{
return _queryExpression.Type
.HasImplementedRawGeneric(typeof(IQueryable<>));
return ENUMERABLE == _queryMethodName;
}
public string GetQueryMethodName()
{
return _queryMethodName;
}
}
}

View File

@ -49,7 +49,7 @@ namespace ShardingCore.Sharding
public int? Skip { get; private set; }
public int? Take { get; private set;}
public IEnumerable<PropertyOrder> Orders { get; private set; }
public PropertyOrder[] Orders { get; private set; }
public SelectContext SelectContext => ParseResult.GetSelectContext();
public GroupByContext GroupByContext => ParseResult.GetGroupByContext();
@ -105,7 +105,7 @@ namespace ShardingCore.Sharding
Take = parseResult.GetPaginationContext().Take;
}
public void ReSetOrders(IEnumerable<PropertyOrder> orders)
public void ReSetOrders(PropertyOrder[] orders)
{
Orders = orders;
}

View File

@ -6,6 +6,7 @@ using ShardingCore.Core.Internal.Visitors.Selects;
using ShardingCore.Exceptions;
using ShardingCore.Extensions;
using ShardingCore.Sharding.MergeContexts;
using ShardingCore.Sharding.ShardingExecutors.Abstractions;
using ShardingCore.Sharding.Visitors.Selects;
namespace ShardingCore.Core.Internal.Visitors
@ -18,12 +19,16 @@ namespace ShardingCore.Core.Internal.Visitors
*/
internal class QueryableExtraDiscoverVisitor : ShardingExpressionVisitor
{
private readonly IMergeQueryCompilerContext _mergeQueryCompilerContext;
private GroupByContext _groupByContext = new GroupByContext();
private SelectContext _selectContext = new SelectContext();
private PaginationContext _paginationContext = new PaginationContext();
private OrderByContext _orderByContext = new OrderByContext();
public QueryableExtraDiscoverVisitor(IMergeQueryCompilerContext mergeQueryCompilerContext)
{
_mergeQueryCompilerContext = mergeQueryCompilerContext;
}
public SelectContext GetSelectContext()
{
return _selectContext;
@ -36,6 +41,11 @@ namespace ShardingCore.Core.Internal.Visitors
public PaginationContext GetPaginationContext()
{
var fixedTake = _mergeQueryCompilerContext.GetFixedTake();
if (fixedTake.HasValue)
{
_paginationContext.Take = fixedTake.Value;
}
return _paginationContext;
}
public OrderByContext GetOrderByContext()

View File

@ -24,7 +24,7 @@ namespace ShardingCore.TableExists
public override ISet<string> DoGetExistTables(DbConnection connection, string dataSourceName)
{
var database = connection.Database;
ISet<string> result = new HashSet<string>();
ISet<string> result = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
using (var dataTable = connection.GetSchema(Tables))
{
for (int i = 0; i < dataTable.Rows.Count; i++)

View File

@ -1,4 +1,5 @@
using Microsoft.EntityFrameworkCore;
using System;
using Microsoft.EntityFrameworkCore;
using ShardingCore.Sharding.Abstractions;
using ShardingCore.TableExists.Abstractions;
using System.Collections.Generic;
@ -17,7 +18,7 @@ namespace ShardingCore.TableExists
public override ISet<string> DoGetExistTables(DbConnection connection, string dataSourceName)
{
ISet<string> result = new HashSet<string>();
ISet<string> result = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
using (var dataTable = connection.GetSchema(Tables))
{
for (int i = 0; i < dataTable.Rows.Count; i++)