- 修复 Oracle/Dameng 分组查询后分页的 bug;#710

This commit is contained in:
2881099 2021-03-04 21:28:10 +08:00
parent a1a120495b
commit 19e12c6cd2
3 changed files with 51 additions and 31 deletions

View File

@ -512,14 +512,5 @@
<param name="that"></param> <param name="that"></param>
<returns></returns> <returns></returns>
</member> </member>
<member name="M:Microsoft.Extensions.DependencyInjection.FreeSqlRepositoryDependencyInjection.AddFreeRepository(Microsoft.Extensions.DependencyInjection.IServiceCollection,System.Action{FreeSql.FluentDataFilter},System.Reflection.Assembly[])">
<summary>
批量注入 Repository可以参考代码自行调整
</summary>
<param name="services"></param>
<param name="globalDataFilter"></param>
<param name="assemblies"></param>
<returns></returns>
</member>
</members> </members>
</doc> </doc>

View File

@ -240,7 +240,8 @@ namespace FreeSql.Internal.CommonProvider
} }
public TSelect RightJoin(Expression<Func<T1, bool>> exp) public TSelect RightJoin(Expression<Func<T1, bool>> exp)
{ {
if (exp == null) return this as TSelect; _tables[0].Parameter = exp.Parameters[0]; if (exp == null) return this as TSelect;
_tables[0].Parameter = exp.Parameters[0];
return this.InternalJoin(exp?.Body, SelectTableInfoType.RightJoin); return this.InternalJoin(exp?.Body, SelectTableInfoType.RightJoin);
} }
public TSelect LeftJoin<T2>(Expression<Func<T1, T2, bool>> exp) public TSelect LeftJoin<T2>(Expression<Func<T1, T2, bool>> exp)

View File

@ -18,6 +18,7 @@ namespace FreeSql.Internal.CommonProvider
public Select0Provider _select; public Select0Provider _select;
public CommonExpression _comonExp; public CommonExpression _comonExp;
public List<SelectTableInfo> _tables; public List<SelectTableInfo> _tables;
public int _groupByLimit, _groupBySkip;
public SelectGroupingProvider(IFreeSql orm, Select0Provider select, ReadAnonymousTypeInfo map, string field, CommonExpression comonExp, List<SelectTableInfo> tables) public SelectGroupingProvider(IFreeSql orm, Select0Provider select, ReadAnonymousTypeInfo map, string field, CommonExpression comonExp, List<SelectTableInfo> tables)
{ {
@ -107,9 +108,10 @@ namespace FreeSql.Internal.CommonProvider
_comonExp.ReadAnonymousField(null, field, map, ref index, select, null, this, null, null, false); _comonExp.ReadAnonymousField(null, field, map, ref index, select, null, this, null, null, false);
if (map.Childs.Any() == false && map.MapType == null) map.MapType = elementType; if (map.Childs.Any() == false && map.MapType == null) map.MapType = elementType;
var method = _select.GetType().GetMethod("ToListMapReader", BindingFlags.Instance | BindingFlags.NonPublic); var method = _select.GetType().GetMethod("ToListMrPrivate", BindingFlags.Instance | BindingFlags.NonPublic);
method = method.MakeGenericMethod(elementType); method = method.MakeGenericMethod(elementType);
return method.Invoke(_select, new object[] { new ReadAnonymousTypeAfInfo(map, field.Length > 0 ? field.Remove(0, 2).ToString() : null) }); var fieldSql = field.Length > 0 ? field.Remove(0, 2).ToString() : null;
return method.Invoke(_select, new object[] { InternalToSql(fieldSql), new ReadAnonymousTypeAfInfo(map, fieldSql), null });
} }
public IEnumerable<KeyValuePair<object, object>> InternalToKeyValuePairs(Expression elementSelector, Type elementType) public IEnumerable<KeyValuePair<object, object>> InternalToKeyValuePairs(Expression elementSelector, Type elementType)
{ {
@ -119,10 +121,11 @@ namespace FreeSql.Internal.CommonProvider
_comonExp.ReadAnonymousField(null, field, map, ref index, elementSelector, null, this, null, null, false); _comonExp.ReadAnonymousField(null, field, map, ref index, elementSelector, null, this, null, null, false);
if (map.Childs.Any() == false && map.MapType == null) map.MapType = elementType; if (map.Childs.Any() == false && map.MapType == null) map.MapType = elementType;
var method = _select.GetType().GetMethod("ToListMapReaderPrivate", BindingFlags.Instance | BindingFlags.NonPublic); var method = _select.GetType().GetMethod("ToListMrPrivate", BindingFlags.Instance | BindingFlags.NonPublic);
method = method.MakeGenericMethod(elementType); method = method.MakeGenericMethod(elementType);
var fieldSql = field.Length > 0 ? field.Remove(0, 2).ToString() : null;
var otherAf = new ReadAnonymousTypeOtherInfo(_field, _map, new List<object>()); var otherAf = new ReadAnonymousTypeOtherInfo(_field, _map, new List<object>());
var values = method.Invoke(_select, new object[] { new ReadAnonymousTypeAfInfo(map, field.Length > 0 ? field.Remove(0, 2).ToString() : null), new[] { otherAf } }) as IList; var values = method.Invoke(_select, new object[] { InternalToSql($"{fieldSql}{_field}"), new ReadAnonymousTypeAfInfo(map, fieldSql), new[] { otherAf } }) as IList;
return otherAf.retlist.Select((a, b) => new KeyValuePair<object, object>(a, values[b])); return otherAf.retlist.Select((a, b) => new KeyValuePair<object, object>(a, values[b]));
} }
public string InternalToSql(Expression select, FieldAliasOptions fieldAlias = FieldAliasOptions.AsIndex) public string InternalToSql(Expression select, FieldAliasOptions fieldAlias = FieldAliasOptions.AsIndex)
@ -132,8 +135,38 @@ namespace FreeSql.Internal.CommonProvider
var index = fieldAlias == FieldAliasOptions.AsProperty ? CommonExpression.ReadAnonymousFieldAsCsName : 0; var index = fieldAlias == FieldAliasOptions.AsProperty ? CommonExpression.ReadAnonymousFieldAsCsName : 0;
_comonExp.ReadAnonymousField(null, field, map, ref index, select, null, this, null, null, false); _comonExp.ReadAnonymousField(null, field, map, ref index, select, null, this, null, null, false);
var fieldSql = field.Length > 0 ? field.Remove(0, 2).ToString() : null;
return InternalToSql(fieldSql);
}
public string InternalToSql(string field)
{
if (string.IsNullOrEmpty(field))
throw new ArgumentException("参数 field 未指定");
var isNestedPageSql = false;
switch (_orm.Ado.DataType)
{
case DataType.Oracle:
case DataType.OdbcOracle:
case DataType.Dameng:
case DataType.OdbcDameng: //Oracle、Dameng 分组时,嵌套分页
isNestedPageSql = true;
break;
default:
_select._limit = _groupByLimit;
_select._skip = _groupBySkip;
break;
}
var method = _select.GetType().GetMethod("ToSql", new[] { typeof(string) }); var method = _select.GetType().GetMethod("ToSql", new[] { typeof(string) });
return method.Invoke(_select, new object[] { field.Length > 0 ? field.Remove(0, 2).ToString() : null }) as string; var sql = method.Invoke(_select, new object[] { field }) as string;
if (isNestedPageSql == false)
{
_select._limit = 0;
_select._skip = 0;
return sql;
}
if (_groupByLimit == 0 && _groupBySkip == 0) return sql;
return _orm.Select<object>().As("t").WithSql(sql).Limit(_groupByLimit).Skip(_groupBySkip).ToSql("t.*");
} }
} }
@ -147,31 +180,24 @@ namespace FreeSql.Internal.CommonProvider
_lambdaParameter = select?.Parameters[0]; _lambdaParameter = select?.Parameters[0];
return InternalToSql(select, fieldAlias); return InternalToSql(select, fieldAlias);
} }
public string ToSql(string field) public string ToSql(string field) => InternalToSql(field);
{
if (string.IsNullOrEmpty(field))
throw new ArgumentException("参数 field 未指定");
var method = _select.GetType().GetMethod("ToSql", new[] { typeof(string) });
return method.Invoke(_select, new object[] { field }) as string;
}
public ISelectGrouping<TKey, TValue> Skip(int offset) public ISelectGrouping<TKey, TValue> Skip(int offset)
{ {
_select._skip = offset; _groupBySkip = offset;
return this; return this;
} }
public ISelectGrouping<TKey, TValue> Offset(int offset) => this.Skip(offset); public ISelectGrouping<TKey, TValue> Offset(int offset) => this.Skip(offset);
public ISelectGrouping<TKey, TValue> Limit(int limit) public ISelectGrouping<TKey, TValue> Limit(int limit)
{ {
_select._limit = limit; _groupByLimit = limit;
return this; return this;
} }
public ISelectGrouping<TKey, TValue> Take(int limit) => this.Limit(limit); public ISelectGrouping<TKey, TValue> Take(int limit) => this.Limit(limit);
public ISelectGrouping<TKey, TValue> Page(int pageNumber, int pageSize) public ISelectGrouping<TKey, TValue> Page(int pageNumber, int pageSize)
{ {
_select._skip = Math.Max(0, pageNumber - 1) * pageSize; _groupBySkip = Math.Max(0, pageNumber - 1) * pageSize;
_select._limit = pageSize; _groupByLimit = pageSize;
return this; return this;
} }
@ -226,9 +252,10 @@ namespace FreeSql.Internal.CommonProvider
_lambdaParameter = select?.Parameters[0]; _lambdaParameter = select?.Parameters[0];
_comonExp.ReadAnonymousField(null, field, map, ref index, select, null, this, null, null, false); _comonExp.ReadAnonymousField(null, field, map, ref index, select, null, this, null, null, false);
if (map.Childs.Any() == false && map.MapType == null) map.MapType = typeof(TReturn); if (map.Childs.Any() == false && map.MapType == null) map.MapType = typeof(TReturn);
var method = _select.GetType().GetMethod("ToListMapReaderAsync", BindingFlags.Instance | BindingFlags.NonPublic); var method = _select.GetType().GetMethod("ToListMrPrivateAsync", BindingFlags.Instance | BindingFlags.NonPublic);
method = method.MakeGenericMethod(typeof(TReturn)); method = method.MakeGenericMethod(typeof(TReturn));
return method.Invoke(_select, new object[] { new ReadAnonymousTypeAfInfo(map, field.Length > 0 ? field.Remove(0, 2).ToString() : null), cancellationToken }) as Task<List<TReturn>>; var fieldSql = field.Length > 0 ? field.Remove(0, 2).ToString() : null;
return method.Invoke(_select, new object[] { InternalToSql(fieldSql), new ReadAnonymousTypeAfInfo(map, fieldSql), null, cancellationToken }) as Task<List<TReturn>>;
} }
async public Task<Dictionary<TKey, TElement>> ToDictionaryAsync<TElement>(Expression<Func<ISelectGroupingAggregate<TKey, TValue>, TElement>> elementSelector, CancellationToken cancellationToken = default) async public Task<Dictionary<TKey, TElement>> ToDictionaryAsync<TElement>(Expression<Func<ISelectGroupingAggregate<TKey, TValue>, TElement>> elementSelector, CancellationToken cancellationToken = default)
{ {
@ -239,10 +266,11 @@ namespace FreeSql.Internal.CommonProvider
_lambdaParameter = elementSelector?.Parameters[0]; _lambdaParameter = elementSelector?.Parameters[0];
_comonExp.ReadAnonymousField(null, field, map, ref index, elementSelector, null, this, null, null, false); _comonExp.ReadAnonymousField(null, field, map, ref index, elementSelector, null, this, null, null, false);
if (map.Childs.Any() == false && map.MapType == null) map.MapType = typeof(TElement); if (map.Childs.Any() == false && map.MapType == null) map.MapType = typeof(TElement);
var method = _select.GetType().GetMethod("ToListMapReaderPrivateAsync", BindingFlags.Instance | BindingFlags.NonPublic); var method = _select.GetType().GetMethod("ToListMrPrivateAsync", BindingFlags.Instance | BindingFlags.NonPublic);
method = method.MakeGenericMethod(typeof(TElement)); method = method.MakeGenericMethod(typeof(TElement));
var fieldSql = field.Length > 0 ? field.Remove(0, 2).ToString() : null;
var otherAf = new ReadAnonymousTypeOtherInfo(_field, _map, new List<object>()); var otherAf = new ReadAnonymousTypeOtherInfo(_field, _map, new List<object>());
var values = await (method.Invoke(_select, new object[] { new ReadAnonymousTypeAfInfo(map, field.Length > 0 ? field.Remove(0, 2).ToString() : null), new[] { otherAf }, cancellationToken }) as Task<List<TElement>>); var values = await (method.Invoke(_select, new object[] { InternalToSql($"{fieldSql}{_field}"), new ReadAnonymousTypeAfInfo(map, fieldSql), new[] { otherAf }, cancellationToken }) as Task<List<TElement>>);
return otherAf.retlist.Select((a, b) => new KeyValuePair<TKey, TElement>((TKey)a, values[b])).ToDictionary(a => a.Key, a => a.Value); return otherAf.retlist.Select((a, b) => new KeyValuePair<TKey, TElement>((TKey)a, values[b])).ToDictionary(a => a.Key, a => a.Value);
} }
#endif #endif