- 修复 分组查询后,无法使用子查询的问题;

This commit is contained in:
2881099 2020-12-11 22:03:02 +08:00
parent 2401f7a9e3
commit bfb59d9d39
7 changed files with 200 additions and 26 deletions

View File

@ -161,6 +161,7 @@ namespace FreeSql.Internal.CommonProvider
public ISelectedQuery<TOut> OrderByIf<TMember>(bool condition, Expression<Func<TOut, TMember>> column, bool descending = false) public ISelectedQuery<TOut> OrderByIf<TMember>(bool condition, Expression<Func<TOut, TMember>> column, bool descending = false)
{ {
if (condition == false) return this; if (condition == false) return this;
_lambdaParameter = column?.Parameters[0];
var sql = _comonExp.ExpressionWhereLambda(null, column, this, null, null); var sql = _comonExp.ExpressionWhereLambda(null, column, this, null, null);
var method = _select.GetType().GetMethod("OrderBy", new[] { typeof(string), typeof(object) }); var method = _select.GetType().GetMethod("OrderBy", new[] { typeof(string), typeof(object) });
method.Invoke(_select, new object[] { descending ? $"{sql} DESC" : sql, null }); method.Invoke(_select, new object[] { descending ? $"{sql} DESC" : sql, null });
@ -172,6 +173,7 @@ namespace FreeSql.Internal.CommonProvider
public ISelectedQuery<TOut> WhereIf(bool condition, Expression<Func<TOut, bool>> exp) public ISelectedQuery<TOut> WhereIf(bool condition, Expression<Func<TOut, bool>> exp)
{ {
if (condition == false) return this; if (condition == false) return this;
_lambdaParameter = exp?.Parameters[0];
var sql = _comonExp.ExpressionWhereLambda(null, exp, this, null, null); var sql = _comonExp.ExpressionWhereLambda(null, exp, this, null, null);
var method = _select.GetType().GetMethod("Where", new[] { typeof(string), typeof(object) }); var method = _select.GetType().GetMethod("Where", new[] { typeof(string), typeof(object) });
method.Invoke(_select, new object[] { sql, null }); method.Invoke(_select, new object[] { sql, null });

View File

@ -512,5 +512,14 @@
<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

@ -13,6 +13,120 @@ namespace FreeSql.Tests
{ {
public class UnitTest4 public class UnitTest4
{ {
[Fact]
public void GroupSubSelect()
{
var fsql = g.sqlite;
fsql.Delete<ts_group_sub_select01>().Where("1=1").ExecuteAffrows();
var affrows = fsql.Insert(new[]{
new ts_group_sub_select01
{
code = "code_01",
seqid = 1,
name = "name_01"
},
new ts_group_sub_select01
{
code = "code_02",
seqid = 2,
name = "name_02"
}
}).ExecuteAffrows();
Assert.Equal(2, affrows);
var sql = fsql.Select<ts_group_sub_select01>()
.GroupBy(a => new
{
a.code,
a.seqid,
a.name
})
.ToSql(g => new
{
g.Key.code,
g.Key.seqid,
g.Key.name,
number = fsql.Select<ts_group_sub_select01>()
.Where(o => o.seqid == 6)
.Count(),
number2 = 3,
number3 = 5
});
Assert.Equal(@"SELECT a.""code"" as1, a.""seqid"" as2, a.""name"" as3, (SELECT count(1)
FROM ""ts_group_sub_select01"" o
WHERE (o.""seqid"" = 6)) as4, 3 as5, 5 as6
FROM ""ts_group_sub_select01"" a
GROUP BY a.""code"", a.""seqid"", a.""name""", sql);
Assert.Equal(2, fsql.Select<ts_group_sub_select01>()
.GroupBy(a => new
{
a.code,
a.seqid,
a.name
})
.ToList(g => new
{
g.Key.code,
g.Key.seqid,
g.Key.name,
number = fsql.Select<ts_group_sub_select01>()
.Where(o => o.seqid == 6)
.Count(),
number2 = 3,
number3 = 5
}).Count);
sql = fsql.Select<ts_group_sub_select01>()
.GroupBy(a => new
{
a.code,
a.seqid,
a.name
})
.ToSql(g => new
{
g.Key.code,
g.Key.seqid,
g.Key.name,
number = fsql.Select<ts_group_sub_select01>()
.Where(o => o.seqid == g.Key.seqid)
.Count(),
number2 = 3,
number3 = 5
});
Assert.Equal(@"SELECT a.""code"" as1, a.""seqid"" as2, a.""name"" as3, (SELECT count(1)
FROM ""ts_group_sub_select01"" o
WHERE (o.""seqid"" = a.""seqid"")) as4, 3 as5, 5 as6
FROM ""ts_group_sub_select01"" a
GROUP BY a.""code"", a.""seqid"", a.""name""", sql);
Assert.Equal(2, fsql.Select<ts_group_sub_select01>()
.GroupBy(a => new
{
a.code,
a.seqid,
a.name
})
.ToList(g => new
{
g.Key.code,
g.Key.seqid,
g.Key.name,
number = fsql.Select<ts_group_sub_select01>()
.Where(o => o.seqid == g.Key.seqid)
.Count(),
number2 = 3,
number3 = 5
}).Count);
}
class ts_group_sub_select01
{
public Guid id { get; set; }
public string code { get; set; }
public int seqid { get; set; }
public string name { get; set; }
}
[Fact] [Fact]
public void OneToManyLazyloading() public void OneToManyLazyloading()
{ {

View File

@ -91,8 +91,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FreeSql.Provider.KingbaseES
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FreeSql.Provider.Firebird", "Providers\FreeSql.Provider.Firebird\FreeSql.Provider.Firebird.csproj", "{101B11D2-7780-4E14-9B72-77F5D69B3DF9}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FreeSql.Provider.Firebird", "Providers\FreeSql.Provider.Firebird\FreeSql.Provider.Firebird.csproj", "{101B11D2-7780-4E14-9B72-77F5D69B3DF9}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FreeSql.Provider.ElasticsearchSQL", "Providers\FreeSql.Provider.ElasticsearchSQL\FreeSql.Provider.ElasticsearchSQL.csproj", "{EC6980FD-090D-4BAA-8421-0D4C3D306F0D}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@ -559,18 +557,6 @@ Global
{101B11D2-7780-4E14-9B72-77F5D69B3DF9}.Release|x64.Build.0 = Release|Any CPU {101B11D2-7780-4E14-9B72-77F5D69B3DF9}.Release|x64.Build.0 = Release|Any CPU
{101B11D2-7780-4E14-9B72-77F5D69B3DF9}.Release|x86.ActiveCfg = Release|Any CPU {101B11D2-7780-4E14-9B72-77F5D69B3DF9}.Release|x86.ActiveCfg = Release|Any CPU
{101B11D2-7780-4E14-9B72-77F5D69B3DF9}.Release|x86.Build.0 = Release|Any CPU {101B11D2-7780-4E14-9B72-77F5D69B3DF9}.Release|x86.Build.0 = Release|Any CPU
{EC6980FD-090D-4BAA-8421-0D4C3D306F0D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EC6980FD-090D-4BAA-8421-0D4C3D306F0D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EC6980FD-090D-4BAA-8421-0D4C3D306F0D}.Debug|x64.ActiveCfg = Debug|Any CPU
{EC6980FD-090D-4BAA-8421-0D4C3D306F0D}.Debug|x64.Build.0 = Debug|Any CPU
{EC6980FD-090D-4BAA-8421-0D4C3D306F0D}.Debug|x86.ActiveCfg = Debug|Any CPU
{EC6980FD-090D-4BAA-8421-0D4C3D306F0D}.Debug|x86.Build.0 = Debug|Any CPU
{EC6980FD-090D-4BAA-8421-0D4C3D306F0D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EC6980FD-090D-4BAA-8421-0D4C3D306F0D}.Release|Any CPU.Build.0 = Release|Any CPU
{EC6980FD-090D-4BAA-8421-0D4C3D306F0D}.Release|x64.ActiveCfg = Release|Any CPU
{EC6980FD-090D-4BAA-8421-0D4C3D306F0D}.Release|x64.Build.0 = Release|Any CPU
{EC6980FD-090D-4BAA-8421-0D4C3D306F0D}.Release|x86.ActiveCfg = Release|Any CPU
{EC6980FD-090D-4BAA-8421-0D4C3D306F0D}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@ -603,7 +589,6 @@ Global
{3D2BD8EC-253A-437F-B4C8-74BC0D91429B} = {2A381C57-2697-427B-9F10-55DA11FD02E4} {3D2BD8EC-253A-437F-B4C8-74BC0D91429B} = {2A381C57-2697-427B-9F10-55DA11FD02E4}
{CDD6A896-F6DF-44CB-B430-06B383916EB0} = {2A381C57-2697-427B-9F10-55DA11FD02E4} {CDD6A896-F6DF-44CB-B430-06B383916EB0} = {2A381C57-2697-427B-9F10-55DA11FD02E4}
{101B11D2-7780-4E14-9B72-77F5D69B3DF9} = {2A381C57-2697-427B-9F10-55DA11FD02E4} {101B11D2-7780-4E14-9B72-77F5D69B3DF9} = {2A381C57-2697-427B-9F10-55DA11FD02E4}
{EC6980FD-090D-4BAA-8421-0D4C3D306F0D} = {2A381C57-2697-427B-9F10-55DA11FD02E4}
EndGlobalSection EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {089687FD-5D25-40AB-BA8A-A10D1E137F98} SolutionGuid = {089687FD-5D25-40AB-BA8A-A10D1E137F98}

View File

@ -3760,6 +3760,11 @@
<param name="database"></param> <param name="database"></param>
<returns></returns> <returns></returns>
</member> </member>
<member name="F:FreeSql.Internal.BaseDiyMemberExpression._lambdaParameter">
<summary>
临时 LambdaExpression.Parameter
</summary>
</member>
<member name="M:FreeSql.Internal.CommonProvider.InsertOrUpdateProvider`1.SplitSourceByIdentityValueIsNull(System.Collections.Generic.List{`0})"> <member name="M:FreeSql.Internal.CommonProvider.InsertOrUpdateProvider`1.SplitSourceByIdentityValueIsNull(System.Collections.Generic.List{`0})">
<summary> <summary>
如果实体类有自增属性,分成两个 List有值的Item1 merge无值的Item2 insert 如果实体类有自增属性,分成两个 List有值的Item1 merge无值的Item2 insert

View File

@ -18,6 +18,10 @@ namespace FreeSql.Internal
{ {
public abstract class BaseDiyMemberExpression public abstract class BaseDiyMemberExpression
{ {
/// <summary>
/// 临时 LambdaExpression.Parameter
/// </summary>
public ParameterExpression _lambdaParameter;
public ReadAnonymousTypeInfo _map; public ReadAnonymousTypeInfo _map;
public string _field; public string _field;
public abstract string ParseExp(Expression[] members); public abstract string ParseExp(Expression[] members);
@ -676,6 +680,7 @@ namespace FreeSql.Internal
static ConcurrentDictionary<Type, bool> _dicTypeExistsExpressionCallAttribute = new ConcurrentDictionary<Type, bool>(); static ConcurrentDictionary<Type, bool> _dicTypeExistsExpressionCallAttribute = new ConcurrentDictionary<Type, bool>();
static ConcurrentDictionary<Type, ConcurrentDictionary<string, bool>> _dicMethodExistsExpressionCallAttribute = new ConcurrentDictionary<Type, ConcurrentDictionary<string, bool>>(); static ConcurrentDictionary<Type, ConcurrentDictionary<string, bool>> _dicMethodExistsExpressionCallAttribute = new ConcurrentDictionary<Type, ConcurrentDictionary<string, bool>>();
static ConcurrentDictionary<Type, FieldInfo[]> _dicTypeExpressionCallClassContextFields = new ConcurrentDictionary<Type, FieldInfo[]>(); static ConcurrentDictionary<Type, FieldInfo[]> _dicTypeExpressionCallClassContextFields = new ConcurrentDictionary<Type, FieldInfo[]>();
static ThreadLocal<List<BaseDiyMemberExpression>> _subSelectParentDiyMemExps = new ThreadLocal<List<BaseDiyMemberExpression>>(); //子查询的所有父自定义查询,比如分组之后的子查询
public string ExpressionLambdaToSql(Expression exp, ExpTSC tsc) public string ExpressionLambdaToSql(Expression exp, ExpTSC tsc)
{ {
if (exp == null) return ""; if (exp == null) return "";
@ -982,14 +987,20 @@ namespace FreeSql.Internal
fsqltables = fsqlSelect0._tables; fsqltables = fsqlSelect0._tables;
//fsqltables[0].Alias = $"{tsc._tables[0].Alias}_{fsqltables[0].Alias}"; //fsqltables[0].Alias = $"{tsc._tables[0].Alias}_{fsqltables[0].Alias}";
if (fsqltables != tsc._tables) if (fsqltables != tsc._tables)
fsqltables.AddRange(tsc._tables.Select(a => new SelectTableInfo {
if (tsc._tables == null && tsc.diymemexp == null) throw new NotSupportedException($"这个特别的子查询不能解析"); //2020-12-11 IUpdate 条件不支持子查询
if (tsc._tables != null) //groupby is null
{ {
Alias = a.Alias, fsqltables.AddRange(tsc._tables.Select(a => new SelectTableInfo
On = "1=1", {
Table = a.Table, Alias = a.Alias,
Type = SelectTableInfoType.Parent, On = "1=1",
Parameter = a.Parameter Table = a.Table,
})); Type = SelectTableInfoType.Parent,
Parameter = a.Parameter
}));
}
}
if (tsc.whereGlobalFilter?.Any() == true) if (tsc.whereGlobalFilter?.Any() == true)
{ {
var fsqlGlobalFilter = fsqlSelect0._whereGlobalFilter; var fsqlGlobalFilter = fsqlSelect0._whereGlobalFilter;
@ -1030,7 +1041,28 @@ namespace FreeSql.Internal
//if (args[a] == null) ExpressionLambdaToSql(call3Exp.Arguments[a], fsqltables, null, null, SelectTableInfoType.From, true); //if (args[a] == null) ExpressionLambdaToSql(call3Exp.Arguments[a], fsqltables, null, null, SelectTableInfoType.From, true);
} }
} }
method.Invoke(fsql, args); var isSubSelectPdme = tsc._tables == null && tsc.diymemexp != null;
try
{
if (isSubSelectPdme)
{
if (_subSelectParentDiyMemExps.Value == null) _subSelectParentDiyMemExps.Value = new List<BaseDiyMemberExpression>();
_subSelectParentDiyMemExps.Value.Add(tsc.diymemexp);
}
method.Invoke(fsql, args);
}
finally
{
if (isSubSelectPdme)
{
var psgpdmes = _subSelectParentDiyMemExps.Value;
if (psgpdmes != null)
{
psgpdmes.RemoveAt(psgpdmes.Count - 1);
if (psgpdmes.Count == 0) _subSelectParentDiyMemExps.Value = null;
}
}
}
} }
if (fsql == null) asSelectBefores.Push(exp3tmp); if (fsql == null) asSelectBefores.Push(exp3tmp);
} }
@ -1302,6 +1334,16 @@ namespace FreeSql.Internal
var expText = tsc.diymemexp.ParseExp(expStack.Where((a, b) => b >= bidx).ToArray()); var expText = tsc.diymemexp.ParseExp(expStack.Where((a, b) => b >= bidx).ToArray());
if (string.IsNullOrEmpty(expText) == false) return expText; if (string.IsNullOrEmpty(expText) == false) return expText;
} }
var psgpdymes = _subSelectParentDiyMemExps.Value; //解决:分组之后的子查询解析
if (psgpdymes?.Any() == true)
{
var expStackFirst = expStack.First();
if (expStackFirst.NodeType == ExpressionType.Parameter)
{
var expText = psgpdymes.Where(a => a._lambdaParameter == expStackFirst).FirstOrDefault()?.ParseExp(expStack.Where((a, b) => b >= 2).ToArray());
if (string.IsNullOrEmpty(expText) == false) return expText;
}
}
if (tsc._tables == null) if (tsc._tables == null)
{ {

View File

@ -142,7 +142,11 @@ namespace FreeSql.Internal.CommonProvider
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)
:base(orm, select, map, field, comonExp, tables) { } :base(orm, select, map, field, comonExp, tables) { }
public string ToSql<TReturn>(Expression<Func<ISelectGroupingAggregate<TKey, TValue>, TReturn>> select, FieldAliasOptions fieldAlias = FieldAliasOptions.AsIndex) => InternalToSql(select, fieldAlias); public string ToSql<TReturn>(Expression<Func<ISelectGroupingAggregate<TKey, TValue>, TReturn>> select, FieldAliasOptions fieldAlias = FieldAliasOptions.AsIndex)
{
_lambdaParameter = select?.Parameters[0];
return InternalToSql(select, fieldAlias);
}
public string ToSql(string field) public string ToSql(string field)
{ {
if (string.IsNullOrEmpty(field)) if (string.IsNullOrEmpty(field))
@ -180,23 +184,34 @@ namespace FreeSql.Internal.CommonProvider
public ISelectGrouping<TKey, TValue> Having(Expression<Func<ISelectGroupingAggregate<TKey, TValue>, bool>> exp) public ISelectGrouping<TKey, TValue> Having(Expression<Func<ISelectGroupingAggregate<TKey, TValue>, bool>> exp)
{ {
_lambdaParameter = exp?.Parameters[0];
InternalHaving(exp); InternalHaving(exp);
return this; return this;
} }
public ISelectGrouping<TKey, TValue> OrderBy<TMember>(Expression<Func<ISelectGroupingAggregate<TKey, TValue>, TMember>> column) public ISelectGrouping<TKey, TValue> OrderBy<TMember>(Expression<Func<ISelectGroupingAggregate<TKey, TValue>, TMember>> column)
{ {
_lambdaParameter = column?.Parameters[0];
InternalOrderBy(column, false); InternalOrderBy(column, false);
return this; return this;
} }
public ISelectGrouping<TKey, TValue> OrderByDescending<TMember>(Expression<Func<ISelectGroupingAggregate<TKey, TValue>, TMember>> column) public ISelectGrouping<TKey, TValue> OrderByDescending<TMember>(Expression<Func<ISelectGroupingAggregate<TKey, TValue>, TMember>> column)
{ {
_lambdaParameter = column?.Parameters[0];
InternalOrderBy(column, true); InternalOrderBy(column, true);
return this; return this;
} }
public List<TReturn> Select<TReturn>(Expression<Func<ISelectGroupingAggregate<TKey, TValue>, TReturn>> select) => ToList(select); public List<TReturn> Select<TReturn>(Expression<Func<ISelectGroupingAggregate<TKey, TValue>, TReturn>> select) => ToList(select);
public List<TReturn> ToList<TReturn>(Expression<Func<ISelectGroupingAggregate<TKey, TValue>, TReturn>> select) => InternalToList(select, typeof(TReturn)) as List<TReturn>; public List<TReturn> ToList<TReturn>(Expression<Func<ISelectGroupingAggregate<TKey, TValue>, TReturn>> select)
public Dictionary<TKey, TElement> ToDictionary<TElement>(Expression<Func<ISelectGroupingAggregate<TKey, TValue>, TElement>> elementSelector) => InternalToKeyValuePairs(elementSelector, typeof(TElement)).ToDictionary(a => (TKey)a.Key, a => (TElement)a.Value); {
_lambdaParameter = select?.Parameters[0];
return InternalToList(select, typeof(TReturn)) as List<TReturn>;
}
public Dictionary<TKey, TElement> ToDictionary<TElement>(Expression<Func<ISelectGroupingAggregate<TKey, TValue>, TElement>> elementSelector)
{
_lambdaParameter = elementSelector?.Parameters[0];
return InternalToKeyValuePairs(elementSelector, typeof(TElement)).ToDictionary(a => (TKey)a.Key, a => (TElement)a.Value);
}
#if net40 #if net40
#else #else
@ -208,6 +223,7 @@ namespace FreeSql.Internal.CommonProvider
var field = new StringBuilder(); var field = new StringBuilder();
var index = 0; var index = 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("ToListMapReaderAsync", BindingFlags.Instance | BindingFlags.NonPublic);
@ -220,6 +236,7 @@ namespace FreeSql.Internal.CommonProvider
var field = new StringBuilder(); var field = new StringBuilder();
var index = 0; var index = 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("ToListMapReaderPrivateAsync", BindingFlags.Instance | BindingFlags.NonPublic);