mirror of
				https://github.com/nsnail/FreeSql.git
				synced 2025-11-04 01:05:27 +08:00 
			
		
		
		
	- 处理 PgArrayToMany AsSelect 子查询 #1145
This commit is contained in:
		@@ -862,6 +862,12 @@ namespace FreeSql
 | 
				
			|||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                var atms = navs.Where(a => a.Item1.RefType == TableRefType.PgArrayToMany).ToList();
 | 
				
			||||||
 | 
					                if (atms.Any())
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if (dbset == rootDbSet)
 | 
					                if (dbset == rootDbSet)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    if (CanRemove(data, true) == false) return;
 | 
					                    if (CanRemove(data, true) == false) return;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1195,45 +1195,164 @@ namespace FreeSql.Internal
 | 
				
			|||||||
                                if (fsql != null)
 | 
					                                if (fsql != null)
 | 
				
			||||||
                                {
 | 
					                                {
 | 
				
			||||||
                                    if (asSelectParentExp != null)
 | 
					                                    if (asSelectParentExp != null)
 | 
				
			||||||
                                    { //执行 AsSelect() 的关联,OneToMany,ManyToMany
 | 
					                                    {
 | 
				
			||||||
 | 
					                                        //执行 AsSelect() 的关联,OneToMany,ManyToMany,PgArrayToMany
 | 
				
			||||||
                                        if (fsqltables[0].Parameter == null)
 | 
					                                        if (fsqltables[0].Parameter == null)
 | 
				
			||||||
                                        {
 | 
					                                        {
 | 
				
			||||||
                                            fsqltables[0].Alias = $"tb_{fsqltables.Count}";
 | 
					                                            fsqltables[0].Alias = $"tb_{fsqltables.Count}";
 | 
				
			||||||
                                            fsqltables[0].Parameter = Expression.Parameter(asSelectEntityType, fsqltables[0].Alias);
 | 
					                                            fsqltables[0].Parameter = Expression.Parameter(asSelectEntityType, fsqltables[0].Alias);
 | 
				
			||||||
                                        }
 | 
					                                        }
 | 
				
			||||||
                                        var fsqlWhere = _dicExpressionLambdaToSqlAsSelectWhereMethodInfo.GetOrAdd(asSelectEntityType, asSelectEntityType3 =>
 | 
					                                        
 | 
				
			||||||
                                            typeof(ISelect<>).MakeGenericType(asSelectEntityType3).GetMethod("Where", new[] {
 | 
					 | 
				
			||||||
                                                typeof(Expression<>).MakeGenericType(typeof(Func<,>).MakeGenericType(asSelectEntityType3, typeof(bool)))
 | 
					 | 
				
			||||||
                                            }));
 | 
					 | 
				
			||||||
                                        var parm123Tb = _common.GetTableByEntity(asSelectParentExp.Type);
 | 
					                                        var parm123Tb = _common.GetTableByEntity(asSelectParentExp.Type);
 | 
				
			||||||
                                        var parm123Ref = parm123Tb.GetTableRef(asSelectParentExp1.Member.Name, true);
 | 
					                                        var parm123Ref = parm123Tb.GetTableRef(asSelectParentExp1.Member.Name, true);
 | 
				
			||||||
                                        if (parm123Ref != null)
 | 
					                                        if (parm123Ref != null)
 | 
				
			||||||
                                        {
 | 
					                                        {
 | 
				
			||||||
                                            var fsqlWhereParam = fsqltables.First().Parameter; //Expression.Parameter(asSelectEntityType);
 | 
					                                            if (parm123Ref.RefType == TableRefType.PgArrayToMany)
 | 
				
			||||||
                                            Expression fsqlWhereExp = null;
 | 
					 | 
				
			||||||
                                            if (parm123Ref.RefType == TableRefType.ManyToMany)
 | 
					 | 
				
			||||||
                                            {
 | 
					                                            {
 | 
				
			||||||
                                                //g.mysql.Select<Tag>().Where(a => g.mysql.Select<Song_tag>().Where(b => b.Tag_id == a.Id && b.Song_id == 1).Any());
 | 
					                                                var amtReftbname = ExpressionLambdaToSql(Expression.MakeMemberAccess(asSelectParentExp, parm123Tb.Properties[parm123Tb.ColumnsByPosition[0].CsName]), tsc);
 | 
				
			||||||
                                                var manyTb = _common.GetTableByEntity(parm123Ref.RefMiddleEntityType);
 | 
					                                                amtReftbname = amtReftbname.Substring(0, amtReftbname.Length - _common.QuoteSqlName(parm123Tb.ColumnsByPosition[0].Attribute.Name).Length - 1);
 | 
				
			||||||
                                                var manySubSelectWhere = _dicExpressionLambdaToSqlAsSelectWhereMethodInfo.GetOrAdd(parm123Ref.RefMiddleEntityType, refMiddleEntityType3 =>
 | 
					                                                if (parm123Ref.RefColumns[0] == fsqltables[0].Table.Primarys[0])
 | 
				
			||||||
                                                    typeof(ISelect<>).MakeGenericType(refMiddleEntityType3).GetMethod("Where", new[] {
 | 
					                                                    (fsql as Select0Provider)._where.Append(" AND (").Append($"{amtReftbname}.{_common.QuoteSqlName(parm123Ref.Columns[0].Attribute.Name)} @> {fsqltables[0].Alias}.{_common.QuoteSqlName(parm123Ref.RefColumns[0].Attribute.Name)}").Append(")");
 | 
				
			||||||
 | 
					                                                else if (parm123Ref.Columns[0] == fsqltables[0].Table.Primarys[0])
 | 
				
			||||||
 | 
					                                                    (fsql as Select0Provider)._where.Append(" AND (").Append($"{amtReftbname}.{_common.QuoteSqlName(parm123Ref.RefColumns[0].Attribute.Name)} @> {fsqltables[0].Alias}.{_common.QuoteSqlName(parm123Ref.Columns[0].Attribute.Name)}").Append(")");
 | 
				
			||||||
 | 
					                                            }
 | 
				
			||||||
 | 
					                                            else
 | 
				
			||||||
 | 
					                                            {
 | 
				
			||||||
 | 
					                                                var fsqlWhere = _dicExpressionLambdaToSqlAsSelectWhereMethodInfo.GetOrAdd(asSelectEntityType, asSelectEntityType3 =>
 | 
				
			||||||
 | 
					                                                    typeof(ISelect<>).MakeGenericType(asSelectEntityType3).GetMethod("Where", new[] {
 | 
				
			||||||
 | 
					                                                        typeof(Expression<>).MakeGenericType(typeof(Func<,>).MakeGenericType(asSelectEntityType3, typeof(bool)))
 | 
				
			||||||
 | 
					                                                }));
 | 
				
			||||||
 | 
					                                                var fsqlWhereParam = fsqltables.First().Parameter; //Expression.Parameter(asSelectEntityType);
 | 
				
			||||||
 | 
					                                                Expression fsqlWhereExp = null;
 | 
				
			||||||
 | 
					                                                if (parm123Ref.RefType == TableRefType.ManyToMany)
 | 
				
			||||||
 | 
					                                                {
 | 
				
			||||||
 | 
					                                                    //g.mysql.Select<Tag>().Where(a => g.mysql.Select<Song_tag>().Where(b => b.Tag_id == a.Id && b.Song_id == 1).Any());
 | 
				
			||||||
 | 
					                                                    var manyTb = _common.GetTableByEntity(parm123Ref.RefMiddleEntityType);
 | 
				
			||||||
 | 
					                                                    var manySubSelectWhere = _dicExpressionLambdaToSqlAsSelectWhereMethodInfo.GetOrAdd(parm123Ref.RefMiddleEntityType, refMiddleEntityType3 =>
 | 
				
			||||||
 | 
					                                                        typeof(ISelect<>).MakeGenericType(refMiddleEntityType3).GetMethod("Where", new[] {
 | 
				
			||||||
                                                        typeof(Expression<>).MakeGenericType(typeof(Func<,>).MakeGenericType(refMiddleEntityType3, typeof(bool)))
 | 
					                                                        typeof(Expression<>).MakeGenericType(typeof(Func<,>).MakeGenericType(refMiddleEntityType3, typeof(bool)))
 | 
				
			||||||
                                                    }));
 | 
					                                                        }));
 | 
				
			||||||
                                                var manySubSelectWhereSql = _dicExpressionLambdaToSqlAsSelectWhereSqlMethodInfo.GetOrAdd(parm123Ref.RefMiddleEntityType, refMiddleEntityType3 =>
 | 
					                                                    var manySubSelectWhereSql = _dicExpressionLambdaToSqlAsSelectWhereSqlMethodInfo.GetOrAdd(parm123Ref.RefMiddleEntityType, refMiddleEntityType3 =>
 | 
				
			||||||
                                                    typeof(ISelect0<,>).MakeGenericType(typeof(ISelect<>).MakeGenericType(refMiddleEntityType3), refMiddleEntityType3).GetMethod("Where", new[] { typeof(string), typeof(object) }));
 | 
					                                                        typeof(ISelect0<,>).MakeGenericType(typeof(ISelect<>).MakeGenericType(refMiddleEntityType3), refMiddleEntityType3).GetMethod("Where", new[] { typeof(string), typeof(object) }));
 | 
				
			||||||
                                                var manySubSelectAsSelectExp = _dicFreeSqlGlobalExtensionsAsSelectExpression.GetOrAdd(parm123Ref.RefMiddleEntityType, refMiddleEntityType3 =>
 | 
					                                                    var manySubSelectAsSelectExp = _dicFreeSqlGlobalExtensionsAsSelectExpression.GetOrAdd(parm123Ref.RefMiddleEntityType, refMiddleEntityType3 =>
 | 
				
			||||||
                                                    Expression.Call(
 | 
					                                                        Expression.Call(
 | 
				
			||||||
                                                        typeof(FreeSqlGlobalExtensions).GetMethods(BindingFlags.Static | BindingFlags.Public).Where(mfil => mfil.Name == "AsSelect" && mfil.GetParameters().Length == 1).FirstOrDefault()?.MakeGenericMethod(refMiddleEntityType3),
 | 
					                                                            typeof(FreeSqlGlobalExtensions).GetMethods(BindingFlags.Static | BindingFlags.Public).Where(mfil => mfil.Name == "AsSelect" && mfil.GetParameters().Length == 1).FirstOrDefault()?.MakeGenericMethod(refMiddleEntityType3),
 | 
				
			||||||
                                                        Expression.Constant(Activator.CreateInstance(typeof(List<>).MakeGenericType(refMiddleEntityType3)))
 | 
					                                                            Expression.Constant(Activator.CreateInstance(typeof(List<>).MakeGenericType(refMiddleEntityType3)))
 | 
				
			||||||
                                                    ));
 | 
					                                                        ));
 | 
				
			||||||
                                                var manyMainParam = tsc._tables[0].Parameter;
 | 
					                                                    var manyMainParam = tsc._tables[0].Parameter;
 | 
				
			||||||
                                                var manySubSelectWhereParam = Expression.Parameter(parm123Ref.RefMiddleEntityType, $"M{fsqlWhereParam.Name}_M{asSelectParentExp.ToString().Replace(".", "__")}");//, $"{fsqlWhereParam.Name}__");
 | 
					                                                    var manySubSelectWhereParam = Expression.Parameter(parm123Ref.RefMiddleEntityType, $"M{fsqlWhereParam.Name}_M{asSelectParentExp.ToString().Replace(".", "__")}");//, $"{fsqlWhereParam.Name}__");
 | 
				
			||||||
                                                Expression manySubSelectWhereExp = null;
 | 
					                                                    Expression manySubSelectWhereExp = null;
 | 
				
			||||||
 | 
					                                                    for (var mn = 0; mn < parm123Ref.Columns.Count; mn++)
 | 
				
			||||||
 | 
					                                                    {
 | 
				
			||||||
 | 
					                                                        var col1 = parm123Ref.MiddleColumns[mn];
 | 
				
			||||||
 | 
					                                                        var col2 = parm123Ref.Columns[mn];
 | 
				
			||||||
 | 
					                                                        var pexp1 = Expression.Property(manySubSelectWhereParam, col1.CsName);
 | 
				
			||||||
 | 
					                                                        var pexp2 = Expression.Property(asSelectParentExp, col2.CsName);
 | 
				
			||||||
 | 
					                                                        if (col1.CsType != col2.CsType)
 | 
				
			||||||
 | 
					                                                        {
 | 
				
			||||||
 | 
					                                                            if (col1.CsType.IsNullableType()) pexp1 = Expression.Property(pexp1, _dicNullableValueProperty.GetOrAdd(col1.CsType, ct1 => ct1.GetProperty("Value")));
 | 
				
			||||||
 | 
					                                                            if (col2.CsType.IsNullableType()) pexp2 = Expression.Property(pexp2, _dicNullableValueProperty.GetOrAdd(col2.CsType, ct2 => ct2.GetProperty("Value")));
 | 
				
			||||||
 | 
					                                                        }
 | 
				
			||||||
 | 
					                                                        var tmpExp = Expression.Equal(pexp1, pexp2);
 | 
				
			||||||
 | 
					                                                        if (mn == 0) manySubSelectWhereExp = tmpExp;
 | 
				
			||||||
 | 
					                                                        else manySubSelectWhereExp = Expression.AndAlso(manySubSelectWhereExp, tmpExp);
 | 
				
			||||||
 | 
					                                                    }
 | 
				
			||||||
 | 
					                                                    var manySubSelectExpBoy = Expression.Call(
 | 
				
			||||||
 | 
					                                                        manySubSelectAsSelectExp,
 | 
				
			||||||
 | 
					                                                        manySubSelectWhere,
 | 
				
			||||||
 | 
					                                                        Expression.Lambda(
 | 
				
			||||||
 | 
					                                                            manySubSelectWhereExp,
 | 
				
			||||||
 | 
					                                                            manySubSelectWhereParam
 | 
				
			||||||
 | 
					                                                        )
 | 
				
			||||||
 | 
					                                                    );
 | 
				
			||||||
 | 
					                                                    Expression fsqlManyWhereExp = null;
 | 
				
			||||||
 | 
					                                                    for (var mn = 0; mn < parm123Ref.RefColumns.Count; mn++)
 | 
				
			||||||
 | 
					                                                    {
 | 
				
			||||||
 | 
					                                                        var col1 = parm123Ref.RefColumns[mn];
 | 
				
			||||||
 | 
					                                                        var col2 = parm123Ref.MiddleColumns[mn + parm123Ref.Columns.Count + mn];
 | 
				
			||||||
 | 
					                                                        var pexp1 = Expression.Property(fsqlWhereParam, col1.CsName);
 | 
				
			||||||
 | 
					                                                        var pexp2 = Expression.Property(manySubSelectWhereParam, col2.CsName);
 | 
				
			||||||
 | 
					                                                        if (col1.CsType != col2.CsType)
 | 
				
			||||||
 | 
					                                                        {
 | 
				
			||||||
 | 
					                                                            if (col1.CsType.IsNullableType()) pexp1 = Expression.Property(pexp1, _dicNullableValueProperty.GetOrAdd(col1.CsType, ct1 => ct1.GetProperty("Value")));
 | 
				
			||||||
 | 
					                                                            if (col2.CsType.IsNullableType()) pexp2 = Expression.Property(pexp2, _dicNullableValueProperty.GetOrAdd(col2.CsType, ct2 => ct2.GetProperty("Value")));
 | 
				
			||||||
 | 
					                                                        }
 | 
				
			||||||
 | 
					                                                        var tmpExp = Expression.Equal(pexp1, pexp2);
 | 
				
			||||||
 | 
					                                                        if (mn == 0) fsqlManyWhereExp = tmpExp;
 | 
				
			||||||
 | 
					                                                        else fsqlManyWhereExp = Expression.AndAlso(fsqlManyWhereExp, tmpExp);
 | 
				
			||||||
 | 
					                                                    }
 | 
				
			||||||
 | 
					                                                    MethodInfo manySubSelectAggMethod = null;
 | 
				
			||||||
 | 
					                                                    switch (exp3.Method.Name) //https://github.com/dotnetcore/FreeSql/issues/362
 | 
				
			||||||
 | 
					                                                    {
 | 
				
			||||||
 | 
					                                                        case "Any":
 | 
				
			||||||
 | 
					                                                        case "Count":
 | 
				
			||||||
 | 
					                                                            fsqltables.Add(new SelectTableInfo { Alias = manySubSelectWhereParam.Name, Parameter = manySubSelectWhereParam, Table = manyTb, Type = SelectTableInfoType.Parent });
 | 
				
			||||||
 | 
					                                                            fsqlWhere.Invoke(fsql, new object[] { Expression.Lambda(fsqlManyWhereExp, fsqlWhereParam) });
 | 
				
			||||||
 | 
					                                                            var sql2 = fsqlType.GetMethod("ToSql", new Type[] { typeof(string) })?.Invoke(fsql, new object[] { "1" })?.ToString();
 | 
				
			||||||
 | 
					                                                            if (string.IsNullOrEmpty(sql2) == false)
 | 
				
			||||||
 | 
					                                                                manySubSelectExpBoy = Expression.Call(manySubSelectExpBoy, manySubSelectWhereSql, Expression.Constant($"exists({sql2.Replace(" \r\n", " \r\n    ")})"), Expression.Constant(null));
 | 
				
			||||||
 | 
					                                                            manySubSelectAggMethod = _dicExpressionLambdaToSqlAsSelectAggMethodInfo.GetOrAdd(parm123Ref.RefMiddleEntityType, _ => new ConcurrentDictionary<string, MethodInfo>()).GetOrAdd(exp3.Method.Name, exp3MethodName =>
 | 
				
			||||||
 | 
					                                                                typeof(ISelect0<,>).MakeGenericType(typeof(ISelect<>).MakeGenericType(parm123Ref.RefMiddleEntityType), parm123Ref.RefMiddleEntityType).GetMethod(exp3MethodName, new Type[0]));
 | 
				
			||||||
 | 
					                                                            manySubSelectExpBoy = Expression.Call(manySubSelectExpBoy, manySubSelectAggMethod);
 | 
				
			||||||
 | 
					                                                            break;
 | 
				
			||||||
 | 
					                                                        case "Sum":
 | 
				
			||||||
 | 
					                                                        case "Min":
 | 
				
			||||||
 | 
					                                                        case "Max":
 | 
				
			||||||
 | 
					                                                        case "Avg":
 | 
				
			||||||
 | 
					                                                        case "ToList":
 | 
				
			||||||
 | 
					                                                        case "ToOne":
 | 
				
			||||||
 | 
					                                                        case "First":
 | 
				
			||||||
 | 
					                                                            //解析:string.Join(",", w.Roles.AsSelect().ToList(b => b.RoleName)
 | 
				
			||||||
 | 
					                                                            var exp3Args0 = (exp3.Arguments[0] as UnaryExpression)?.Operand as LambdaExpression;
 | 
				
			||||||
 | 
					                                                            manySubSelectAggMethod = _dicSelectMethodToSql.GetOrAdd(fsqlType, fsqlType2 =>
 | 
				
			||||||
 | 
					                                                                fsqlType2.GetMethods().Where(a => a.Name == "ToSql" && a.GetParameters().Length == 2 && a.GetParameters()[1].ParameterType == typeof(FieldAliasOptions) && a.GetGenericArguments().Length == 1).FirstOrDefault());
 | 
				
			||||||
 | 
					                                                            if (manySubSelectAggMethod == null || exp3Args0 == null) throw new ArgumentException(CoreStrings.ManyToMany_AsSelect_NotSupport_Sum_Avg_etc);
 | 
				
			||||||
 | 
					                                                            manySubSelectAggMethod = manySubSelectAggMethod.MakeGenericMethod(exp3Args0.ReturnType);
 | 
				
			||||||
 | 
					                                                            var fsqls0p = fsql as Select0Provider;
 | 
				
			||||||
 | 
					                                                            var fsqls0pWhere = fsqls0p._where.ToString();
 | 
				
			||||||
 | 
					                                                            fsqls0p._where.Clear();
 | 
				
			||||||
 | 
					                                                            var fsqltablesLast = new SelectTableInfo { Alias = manySubSelectWhereParam.Name, Parameter = manySubSelectWhereParam, Table = manyTb, Type = SelectTableInfoType.InnerJoin };
 | 
				
			||||||
 | 
					                                                            fsqltables.Add(fsqltablesLast);
 | 
				
			||||||
 | 
					                                                            fsqlWhere.Invoke(fsql, new object[] { Expression.Lambda(fsqlManyWhereExp, fsqlWhereParam) });
 | 
				
			||||||
 | 
					                                                            fsqltablesLast.NavigateCondition = fsqls0p._where.ToString();
 | 
				
			||||||
 | 
					                                                            if (fsqltablesLast.NavigateCondition.StartsWith(" AND (")) fsqltablesLast.NavigateCondition = fsqltablesLast.NavigateCondition.Substring(6, fsqltablesLast.NavigateCondition.Length - 7);
 | 
				
			||||||
 | 
					                                                            fsqls0p._where.Clear().Append(fsqls0pWhere);
 | 
				
			||||||
 | 
					                                                            var tsc3 = tsc.CloneDisableDiyParse();
 | 
				
			||||||
 | 
					                                                            tsc3._tables = tsc._tables.ToList();
 | 
				
			||||||
 | 
					                                                            var where2 = ExpressionLambdaToSql(Expression.Lambda(manySubSelectWhereExp, manySubSelectWhereParam), tsc3);
 | 
				
			||||||
 | 
					                                                            if (string.IsNullOrEmpty(where2) == false) fsqls0p._where.Append(" AND (").Append(where2).Append(")");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                                            switch (exp3.Method.Name)
 | 
				
			||||||
 | 
					                                                            {
 | 
				
			||||||
 | 
					                                                                case "Sum":
 | 
				
			||||||
 | 
					                                                                case "Min":
 | 
				
			||||||
 | 
					                                                                case "Max":
 | 
				
			||||||
 | 
					                                                                case "Avg":
 | 
				
			||||||
 | 
					                                                                    var map = new ReadAnonymousTypeInfo();
 | 
				
			||||||
 | 
					                                                                    var field = new StringBuilder();
 | 
				
			||||||
 | 
					                                                                    var index = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                                                    for (var a = 0; a < exp3Args0.Parameters.Count; a++) fsqls0p._tables[a].Parameter = exp3Args0.Parameters[a];
 | 
				
			||||||
 | 
					                                                                    ReadAnonymousField(fsqls0p._tables, field, map, ref index, exp3Args0, null, null, null, null, null, false);
 | 
				
			||||||
 | 
					                                                                    var fieldSql = field.Length > 0 ? field.Remove(0, 2).ToString() : null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                                                    var sql4 = fsqlType.GetMethod("ToSql", new Type[] { typeof(string) })?.Invoke(fsql, new object[] { $"{exp3.Method.Name.ToLower()}({fieldSql})" })?.ToString();
 | 
				
			||||||
 | 
					                                                                    asSelectBefores.Clear();
 | 
				
			||||||
 | 
					                                                                    return _common.IsNull($"({sql4.Replace(" \r\n", " \r\n    ")})", formatSql(exp3.Method.ReturnType.CreateInstanceGetDefaultValue(), exp3.Method.ReturnType, null, null));
 | 
				
			||||||
 | 
					                                                            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                                            var sql3 = manySubSelectAggMethod.Invoke(fsql, new object[] { exp3Args0, FieldAliasOptions.AsProperty }) as string;
 | 
				
			||||||
 | 
					                                                            asSelectBefores.Clear();
 | 
				
			||||||
 | 
					                                                            return $"({sql3.Replace(" \r\n", " \r\n    ")})";
 | 
				
			||||||
 | 
					                                                    }
 | 
				
			||||||
 | 
					                                                    asSelectBefores.Clear();
 | 
				
			||||||
 | 
					                                                    return ExpressionLambdaToSql(manySubSelectExpBoy, tsc);
 | 
				
			||||||
 | 
					                                                }
 | 
				
			||||||
                                                for (var mn = 0; mn < parm123Ref.Columns.Count; mn++)
 | 
					                                                for (var mn = 0; mn < parm123Ref.Columns.Count; mn++)
 | 
				
			||||||
                                                {
 | 
					                                                {
 | 
				
			||||||
                                                    var col1 = parm123Ref.MiddleColumns[mn];
 | 
					                                                    var col1 = parm123Ref.RefColumns[mn];
 | 
				
			||||||
                                                    var col2 = parm123Ref.Columns[mn];
 | 
					                                                    var col2 = parm123Ref.Columns[mn];
 | 
				
			||||||
                                                    var pexp1 = Expression.Property(manySubSelectWhereParam, col1.CsName);
 | 
					                                                    var pexp1 = Expression.Property(fsqlWhereParam, col1.CsName);
 | 
				
			||||||
                                                    var pexp2 = Expression.Property(asSelectParentExp, col2.CsName);
 | 
					                                                    var pexp2 = Expression.Property(asSelectParentExp, col2.CsName);
 | 
				
			||||||
                                                    if (col1.CsType != col2.CsType)
 | 
					                                                    if (col1.CsType != col2.CsType)
 | 
				
			||||||
                                                    {
 | 
					                                                    {
 | 
				
			||||||
@@ -1241,116 +1360,11 @@ namespace FreeSql.Internal
 | 
				
			|||||||
                                                        if (col2.CsType.IsNullableType()) pexp2 = Expression.Property(pexp2, _dicNullableValueProperty.GetOrAdd(col2.CsType, ct2 => ct2.GetProperty("Value")));
 | 
					                                                        if (col2.CsType.IsNullableType()) pexp2 = Expression.Property(pexp2, _dicNullableValueProperty.GetOrAdd(col2.CsType, ct2 => ct2.GetProperty("Value")));
 | 
				
			||||||
                                                    }
 | 
					                                                    }
 | 
				
			||||||
                                                    var tmpExp = Expression.Equal(pexp1, pexp2);
 | 
					                                                    var tmpExp = Expression.Equal(pexp1, pexp2);
 | 
				
			||||||
                                                    if (mn == 0) manySubSelectWhereExp = tmpExp;
 | 
					                                                    if (mn == 0) fsqlWhereExp = tmpExp;
 | 
				
			||||||
                                                    else manySubSelectWhereExp = Expression.AndAlso(manySubSelectWhereExp, tmpExp);
 | 
					                                                    else fsqlWhereExp = Expression.AndAlso(fsqlWhereExp, tmpExp);
 | 
				
			||||||
                                                }
 | 
					                                                }
 | 
				
			||||||
                                                var manySubSelectExpBoy = Expression.Call(
 | 
					                                                fsqlWhere.Invoke(fsql, new object[] { Expression.Lambda(fsqlWhereExp, fsqlWhereParam) });
 | 
				
			||||||
                                                    manySubSelectAsSelectExp,
 | 
					 | 
				
			||||||
                                                    manySubSelectWhere,
 | 
					 | 
				
			||||||
                                                    Expression.Lambda(
 | 
					 | 
				
			||||||
                                                        manySubSelectWhereExp,
 | 
					 | 
				
			||||||
                                                        manySubSelectWhereParam
 | 
					 | 
				
			||||||
                                                    )
 | 
					 | 
				
			||||||
                                                );
 | 
					 | 
				
			||||||
                                                Expression fsqlManyWhereExp = null;
 | 
					 | 
				
			||||||
                                                for (var mn = 0; mn < parm123Ref.RefColumns.Count; mn++)
 | 
					 | 
				
			||||||
                                                {
 | 
					 | 
				
			||||||
                                                    var col1 = parm123Ref.RefColumns[mn];
 | 
					 | 
				
			||||||
                                                    var col2 = parm123Ref.MiddleColumns[mn + parm123Ref.Columns.Count + mn];
 | 
					 | 
				
			||||||
                                                    var pexp1 = Expression.Property(fsqlWhereParam, col1.CsName);
 | 
					 | 
				
			||||||
                                                    var pexp2 = Expression.Property(manySubSelectWhereParam, col2.CsName);
 | 
					 | 
				
			||||||
                                                    if (col1.CsType != col2.CsType)
 | 
					 | 
				
			||||||
                                                    {
 | 
					 | 
				
			||||||
                                                        if (col1.CsType.IsNullableType()) pexp1 = Expression.Property(pexp1, _dicNullableValueProperty.GetOrAdd(col1.CsType, ct1 => ct1.GetProperty("Value")));
 | 
					 | 
				
			||||||
                                                        if (col2.CsType.IsNullableType()) pexp2 = Expression.Property(pexp2, _dicNullableValueProperty.GetOrAdd(col2.CsType, ct2 => ct2.GetProperty("Value")));
 | 
					 | 
				
			||||||
                                                    }
 | 
					 | 
				
			||||||
                                                    var tmpExp = Expression.Equal(pexp1, pexp2);
 | 
					 | 
				
			||||||
                                                    if (mn == 0) fsqlManyWhereExp = tmpExp;
 | 
					 | 
				
			||||||
                                                    else fsqlManyWhereExp = Expression.AndAlso(fsqlManyWhereExp, tmpExp);
 | 
					 | 
				
			||||||
                                                }
 | 
					 | 
				
			||||||
                                                MethodInfo manySubSelectAggMethod = null;
 | 
					 | 
				
			||||||
                                                switch (exp3.Method.Name) //https://github.com/dotnetcore/FreeSql/issues/362
 | 
					 | 
				
			||||||
                                                {
 | 
					 | 
				
			||||||
                                                    case "Any":
 | 
					 | 
				
			||||||
                                                    case "Count":
 | 
					 | 
				
			||||||
                                                        fsqltables.Add(new SelectTableInfo { Alias = manySubSelectWhereParam.Name, Parameter = manySubSelectWhereParam, Table = manyTb, Type = SelectTableInfoType.Parent });
 | 
					 | 
				
			||||||
                                                        fsqlWhere.Invoke(fsql, new object[] { Expression.Lambda(fsqlManyWhereExp, fsqlWhereParam) });
 | 
					 | 
				
			||||||
                                                        var sql2 = fsqlType.GetMethod("ToSql", new Type[] { typeof(string) })?.Invoke(fsql, new object[] { "1" })?.ToString();
 | 
					 | 
				
			||||||
                                                        if (string.IsNullOrEmpty(sql2) == false)
 | 
					 | 
				
			||||||
                                                            manySubSelectExpBoy = Expression.Call(manySubSelectExpBoy, manySubSelectWhereSql, Expression.Constant($"exists({sql2.Replace(" \r\n", " \r\n    ")})"), Expression.Constant(null));
 | 
					 | 
				
			||||||
                                                        manySubSelectAggMethod = _dicExpressionLambdaToSqlAsSelectAggMethodInfo.GetOrAdd(parm123Ref.RefMiddleEntityType, _ => new ConcurrentDictionary<string, MethodInfo>()).GetOrAdd(exp3.Method.Name, exp3MethodName =>
 | 
					 | 
				
			||||||
                                                            typeof(ISelect0<,>).MakeGenericType(typeof(ISelect<>).MakeGenericType(parm123Ref.RefMiddleEntityType), parm123Ref.RefMiddleEntityType).GetMethod(exp3MethodName, new Type[0]));
 | 
					 | 
				
			||||||
                                                        manySubSelectExpBoy = Expression.Call(manySubSelectExpBoy, manySubSelectAggMethod);
 | 
					 | 
				
			||||||
                                                        break;
 | 
					 | 
				
			||||||
                                                    case "Sum":
 | 
					 | 
				
			||||||
                                                    case "Min":
 | 
					 | 
				
			||||||
                                                    case "Max":
 | 
					 | 
				
			||||||
                                                    case "Avg":
 | 
					 | 
				
			||||||
                                                    case "ToList":
 | 
					 | 
				
			||||||
                                                    case "ToOne":
 | 
					 | 
				
			||||||
                                                    case "First":
 | 
					 | 
				
			||||||
                                                        //解析:string.Join(",", w.Roles.AsSelect().ToList(b => b.RoleName)
 | 
					 | 
				
			||||||
                                                        var exp3Args0 = (exp3.Arguments[0] as UnaryExpression)?.Operand as LambdaExpression;
 | 
					 | 
				
			||||||
                                                        manySubSelectAggMethod = _dicSelectMethodToSql.GetOrAdd(fsqlType, fsqlType2 =>
 | 
					 | 
				
			||||||
                                                            fsqlType2.GetMethods().Where(a => a.Name == "ToSql" && a.GetParameters().Length == 2 && a.GetParameters()[1].ParameterType == typeof(FieldAliasOptions) && a.GetGenericArguments().Length == 1).FirstOrDefault());
 | 
					 | 
				
			||||||
                                                        if (manySubSelectAggMethod == null || exp3Args0 == null) throw new ArgumentException(CoreStrings.ManyToMany_AsSelect_NotSupport_Sum_Avg_etc);
 | 
					 | 
				
			||||||
                                                        manySubSelectAggMethod = manySubSelectAggMethod.MakeGenericMethod(exp3Args0.ReturnType);
 | 
					 | 
				
			||||||
                                                        var fsqls0p = fsql as Select0Provider;
 | 
					 | 
				
			||||||
                                                        var fsqls0pWhere = fsqls0p._where.ToString();
 | 
					 | 
				
			||||||
                                                        fsqls0p._where.Clear();
 | 
					 | 
				
			||||||
                                                        var fsqltablesLast = new SelectTableInfo { Alias = manySubSelectWhereParam.Name, Parameter = manySubSelectWhereParam, Table = manyTb, Type = SelectTableInfoType.InnerJoin };
 | 
					 | 
				
			||||||
                                                        fsqltables.Add(fsqltablesLast);
 | 
					 | 
				
			||||||
                                                        fsqlWhere.Invoke(fsql, new object[] { Expression.Lambda(fsqlManyWhereExp, fsqlWhereParam) });
 | 
					 | 
				
			||||||
                                                        fsqltablesLast.NavigateCondition = fsqls0p._where.ToString();
 | 
					 | 
				
			||||||
                                                        if (fsqltablesLast.NavigateCondition.StartsWith(" AND (")) fsqltablesLast.NavigateCondition = fsqltablesLast.NavigateCondition.Substring(6, fsqltablesLast.NavigateCondition.Length - 7);
 | 
					 | 
				
			||||||
                                                        fsqls0p._where.Clear().Append(fsqls0pWhere);
 | 
					 | 
				
			||||||
                                                        var tsc3 = tsc.CloneDisableDiyParse();
 | 
					 | 
				
			||||||
                                                        tsc3._tables = tsc._tables.ToList();
 | 
					 | 
				
			||||||
                                                        var where2 = ExpressionLambdaToSql(Expression.Lambda(manySubSelectWhereExp, manySubSelectWhereParam), tsc3);
 | 
					 | 
				
			||||||
                                                        if (string.IsNullOrEmpty(where2) == false) fsqls0p._where.Append(" AND (").Append(where2).Append(")");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                                                        switch (exp3.Method.Name)
 | 
					 | 
				
			||||||
                                                        {
 | 
					 | 
				
			||||||
                                                            case "Sum":
 | 
					 | 
				
			||||||
                                                            case "Min":
 | 
					 | 
				
			||||||
                                                            case "Max":
 | 
					 | 
				
			||||||
                                                            case "Avg":
 | 
					 | 
				
			||||||
                                                                var map = new ReadAnonymousTypeInfo();
 | 
					 | 
				
			||||||
                                                                var field = new StringBuilder();
 | 
					 | 
				
			||||||
                                                                var index = -1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                                                                for (var a = 0; a < exp3Args0.Parameters.Count; a++) fsqls0p._tables[a].Parameter = exp3Args0.Parameters[a];
 | 
					 | 
				
			||||||
                                                                ReadAnonymousField(fsqls0p._tables, field, map, ref index, exp3Args0, null, null, null, null, null, false);
 | 
					 | 
				
			||||||
                                                                var fieldSql = field.Length > 0 ? field.Remove(0, 2).ToString() : null;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                                                                var sql4 = fsqlType.GetMethod("ToSql", new Type[] { typeof(string) })?.Invoke(fsql, new object[] { $"{exp3.Method.Name.ToLower()}({fieldSql})" })?.ToString();
 | 
					 | 
				
			||||||
                                                                asSelectBefores.Clear();
 | 
					 | 
				
			||||||
                                                                return _common.IsNull($"({sql4.Replace(" \r\n", " \r\n    ")})", formatSql(exp3.Method.ReturnType.CreateInstanceGetDefaultValue(), exp3.Method.ReturnType, null, null));
 | 
					 | 
				
			||||||
                                                        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                                                        var sql3 = manySubSelectAggMethod.Invoke(fsql, new object[] { exp3Args0, FieldAliasOptions.AsProperty }) as string;
 | 
					 | 
				
			||||||
                                                        asSelectBefores.Clear();
 | 
					 | 
				
			||||||
                                                        return $"({sql3.Replace(" \r\n", " \r\n    ")})";
 | 
					 | 
				
			||||||
                                                }
 | 
					 | 
				
			||||||
                                                asSelectBefores.Clear();
 | 
					 | 
				
			||||||
                                                return ExpressionLambdaToSql(manySubSelectExpBoy, tsc);
 | 
					 | 
				
			||||||
                                            }
 | 
					                                            }
 | 
				
			||||||
                                            for (var mn = 0; mn < parm123Ref.Columns.Count; mn++)
 | 
					 | 
				
			||||||
                                            {
 | 
					 | 
				
			||||||
                                                var col1 = parm123Ref.RefColumns[mn];
 | 
					 | 
				
			||||||
                                                var col2 = parm123Ref.Columns[mn];
 | 
					 | 
				
			||||||
                                                var pexp1 = Expression.Property(fsqlWhereParam, col1.CsName);
 | 
					 | 
				
			||||||
                                                var pexp2 = Expression.Property(asSelectParentExp, col2.CsName);
 | 
					 | 
				
			||||||
                                                if (col1.CsType != col2.CsType)
 | 
					 | 
				
			||||||
                                                {
 | 
					 | 
				
			||||||
                                                    if (col1.CsType.IsNullableType()) pexp1 = Expression.Property(pexp1, _dicNullableValueProperty.GetOrAdd(col1.CsType, ct1 => ct1.GetProperty("Value")));
 | 
					 | 
				
			||||||
                                                    if (col2.CsType.IsNullableType()) pexp2 = Expression.Property(pexp2, _dicNullableValueProperty.GetOrAdd(col2.CsType, ct2 => ct2.GetProperty("Value")));
 | 
					 | 
				
			||||||
                                                }
 | 
					 | 
				
			||||||
                                                var tmpExp = Expression.Equal(pexp1, pexp2);
 | 
					 | 
				
			||||||
                                                if (mn == 0) fsqlWhereExp = tmpExp;
 | 
					 | 
				
			||||||
                                                else fsqlWhereExp = Expression.AndAlso(fsqlWhereExp, tmpExp);
 | 
					 | 
				
			||||||
                                            }
 | 
					 | 
				
			||||||
                                            fsqlWhere.Invoke(fsql, new object[] { Expression.Lambda(fsqlWhereExp, fsqlWhereParam) });
 | 
					 | 
				
			||||||
                                        }
 | 
					                                        }
 | 
				
			||||||
                                    }
 | 
					                                    }
 | 
				
			||||||
                                    asSelectBefores.Clear();
 | 
					                                    asSelectBefores.Clear();
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user