diff --git a/FreeSql/Extensions/FreeSqlGlobalExpressionCallExtensions.cs b/FreeSql/Extensions/FreeSqlGlobalExpressionCallExtensions.cs index eb3ebb16a..6ce95002e 100644 --- a/FreeSql/Extensions/FreeSqlGlobalExpressionCallExtensions.cs +++ b/FreeSql/Extensions/FreeSqlGlobalExpressionCallExtensions.cs @@ -1,12 +1,25 @@ using FreeSql.DataAnnotations; using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Text; using System.Threading; +using System.Xml.Linq; using static FreeSql.SqlExtExtensions; +internal static class FreeSqlInternalExpressionCallExtensions +{ + static ConcurrentDictionary _dicTypeExistsExpressionCallAttribute = new ConcurrentDictionary(); + public static bool IsExpressionCall(this MethodCallExpression node) + { + return node.Object == null && ( + _dicTypeExistsExpressionCallAttribute.GetOrAdd(node.Method.DeclaringType, dttp => dttp.GetCustomAttributes(typeof(ExpressionCallAttribute), true).Any()) || + node.Method.GetCustomAttributes(typeof(ExpressionCallAttribute), true).Any()); + } +} + [ExpressionCall] public static class FreeSqlGlobalExpressionCallExtensions { @@ -24,10 +37,10 @@ public static bool Between(this DateTime that, DateTime between, DateTime and) { if (expContext.IsValueCreated == false || expContext.Value == null || expContext.Value.ParsedContent == null) return that >= between && that <= and; - var time1 = expContext.Value.RawExpression["between"].IsParameter() == false ? + var time1 = expContext.Value.RawExpression["between"].CanDynamicInvoke() ? expContext.Value.FormatSql(Expression.Lambda(expContext.Value.RawExpression["between"]).Compile().DynamicInvoke()) : expContext.Value.ParsedContent["between"]; - var time2 = expContext.Value.RawExpression["and"].IsParameter() == false ? + var time2 = expContext.Value.RawExpression["and"].CanDynamicInvoke() ? expContext.Value.FormatSql(Expression.Lambda(expContext.Value.RawExpression["and"]).Compile().DynamicInvoke()) : expContext.Value.ParsedContent["and"]; expContext.Value.Result = $"{expContext.Value.ParsedContent["that"]} between {time1} and {time2}"; @@ -47,10 +60,10 @@ public static bool BetweenEnd(this DateTime that, DateTime start, DateTime end) { if (expContext.IsValueCreated == false || expContext.Value == null || expContext.Value.ParsedContent == null) return that >= start && that < end; - var time1 = expContext.Value.RawExpression["start"].IsParameter() == false ? + var time1 = expContext.Value.RawExpression["start"].CanDynamicInvoke() ? expContext.Value.FormatSql(Expression.Lambda(expContext.Value.RawExpression["start"]).Compile().DynamicInvoke()) : expContext.Value.ParsedContent["start"]; - var time2 = expContext.Value.RawExpression["end"].IsParameter() == false ? + var time2 = expContext.Value.RawExpression["end"].CanDynamicInvoke() ? expContext.Value.FormatSql(Expression.Lambda(expContext.Value.RawExpression["end"]).Compile().DynamicInvoke()) : expContext.Value.ParsedContent["end"]; expContext.Value.Result = $"{expContext.Value.ParsedContent["that"]} >= {time1} and {expContext.Value.ParsedContent["that"]} < {time2}"; diff --git a/FreeSql/Extensions/LambadaExpressionExtensions.cs b/FreeSql/Extensions/LambadaExpressionExtensions.cs index 9f2191948..1a49167dd 100644 --- a/FreeSql/Extensions/LambadaExpressionExtensions.cs +++ b/FreeSql/Extensions/LambadaExpressionExtensions.cs @@ -1,4 +1,6 @@ using FreeSql; +using FreeSql.DataAnnotations; +using FreeSql.Internal; using System; using System.Collections.Concurrent; using System.Collections.Generic; @@ -227,6 +229,12 @@ static LambdaExpression InternalNotExpression(bool condition, LambdaExpression e public static Expression> Not(this Expression> exp, bool condition = true) => (Expression>)InternalNotExpression(condition, exp); #endregion + public static bool CanDynamicInvoke(this Expression exp) + { + var test = new TestCanDynamicInvokeExpressionVisitor(); + test.Visit(exp); + return test.Result; + } public static bool IsParameter(this Expression exp) { var test = new TestParameterExpressionVisitor(); @@ -364,6 +372,23 @@ protected override Expression VisitParameter(ParameterExpression node) } } + internal class TestCanDynamicInvokeExpressionVisitor : ExpressionVisitor + { + public bool Result { get; private set; } = true; + + protected override Expression VisitParameter(ParameterExpression node) + { + if (Result) Result = false; + return node; + } + + protected override Expression VisitMethodCall(MethodCallExpression node) + { + if (Result && node.IsExpressionCall()) Result = false; + return base.VisitMethodCall(node); + } + } + internal class GetParameterExpressionVisitor : ExpressionVisitor { public ParameterExpression Result { get; private set; } diff --git a/FreeSql/Internal/CommonExpression.cs b/FreeSql/Internal/CommonExpression.cs index 5cc620377..b05aee762 100644 --- a/FreeSql/Internal/CommonExpression.cs +++ b/FreeSql/Internal/CommonExpression.cs @@ -136,7 +136,7 @@ void LocalSetFieldAlias(ref int localIndex, bool isdiymemexp) return false; case ExpressionType.Conditional: var condExp = exp as ConditionalExpression; - if (condExp.Test.IsParameter() == false) return ReadAnonymousField(_tables, _tableRule, field, parent, ref index, + if (condExp.Test.CanDynamicInvoke()) return ReadAnonymousField(_tables, _tableRule, field, parent, ref index, (bool)Expression.Lambda(condExp.Test).Compile().DynamicInvoke() ? condExp.IfTrue : condExp.IfFalse, select, diymemexp, whereGlobalFilter, findIncludeMany, findSubSelectMany, isAllDtoMap); break; case ExpressionType.Call: @@ -871,7 +871,7 @@ rightExp is UnaryExpression rightExpUexp && if (isLeftMapType) oldMapType = tsc.SetMapTypeReturnOld(leftMapColumn.Attribute.MapType); var right = (leftMapColumn != null && - (leftMapColumn.Table.AsTableColumn == leftMapColumn && rightExp.IsParameter() == false)) ? //自动分表 + (leftMapColumn.Table.AsTableColumn == leftMapColumn && rightExp.CanDynamicInvoke())) ? //自动分表 formatSql(Expression.Lambda(rightExp).Compile().DynamicInvoke(), leftMapColumn.Attribute.MapType, leftMapColumn, tsc.dbParams) : ExpressionLambdaToSql(rightExp, tsc); if (right != "NULL" && isLeftMapType && @@ -897,7 +897,7 @@ rightExp is UnaryExpression rightExpUexp && { oldMapType = tsc.SetMapTypeReturnOld(rightMapColumn.Attribute.MapType); left = (rightMapColumn != null && - (rightMapColumn.Table.AsTableColumn == rightMapColumn && leftExp.IsParameter() == false)) ? //自动分表 + (rightMapColumn.Table.AsTableColumn == rightMapColumn && leftExp.CanDynamicInvoke())) ? //自动分表 formatSql(Expression.Lambda(leftExp).Compile().DynamicInvoke(), rightMapColumn.Attribute.MapType, rightMapColumn, tsc.dbParams) : ExpressionLambdaToSql(leftExp, tsc); if (left != "NULL" && isRightMapType && @@ -963,7 +963,6 @@ rightExp is UnaryExpression rightExpUexp && tsc.SetMapColumnTmp(null).SetMapTypeReturnOld(oldMapType); return $"{left} {oper} {right}"; } - static ConcurrentDictionary _dicTypeExistsExpressionCallAttribute = new ConcurrentDictionary(); static ConcurrentDictionary> _dicMethodExistsExpressionCallAttribute = new ConcurrentDictionary>(); static ConcurrentDictionary _dicTypeExpressionCallClassContextFields = new ConcurrentDictionary(); static ThreadLocal> _subSelectParentDiyMemExps = new ThreadLocal>(); //子查询的所有父自定义查询,比如分组之后的子查询 @@ -1019,7 +1018,7 @@ public string ExpressionLambdaToSql(Expression exp, ExpTSC tsc) //var othercExp = ExpressionLambdaToSqlOther(exp, tsc); //if (string.IsNullOrEmpty(othercExp) == false) return othercExp; var expOperand = (exp as UnaryExpression)?.Operand; - if (expOperand.Type.NullableTypeOrThis().IsEnum && exp.IsParameter() == false) + if (expOperand.Type.NullableTypeOrThis().IsEnum && exp.CanDynamicInvoke()) return formatSql(Expression.Lambda(exp).Compile().DynamicInvoke(), tsc.mapType, tsc.mapColumnTmp, tsc.dbParams); //bug: Where(a => a.Id = (int)enum) return ExpressionLambdaToSql(expOperand, tsc); case ExpressionType.Negate: @@ -1028,7 +1027,7 @@ public string ExpressionLambdaToSql(Expression exp, ExpTSC tsc) case ExpressionType.Conditional: var condExp = exp as ConditionalExpression; var conditionalTestOldMapType = tsc.SetMapTypeReturnOld(null); - if (condExp.Test.IsParameter()) + if (condExp.Test.CanDynamicInvoke() == false) { var condExp2 = condExp.Test; if (condExp2.NodeType == ExpressionType.MemberAccess) condExp2 = Expression.Equal(condExp2, Expression.Constant(true)); @@ -1055,10 +1054,7 @@ public string ExpressionLambdaToSql(Expression exp, ExpTSC tsc) case ExpressionType.Call: tsc.mapType = null; var exp3 = exp as MethodCallExpression; - if (exp3.Object == null && ( - _dicTypeExistsExpressionCallAttribute.GetOrAdd(exp3.Method.DeclaringType, dttp => dttp.GetCustomAttributes(typeof(ExpressionCallAttribute), true).Any()) || - exp3.Method.GetCustomAttributes(typeof(ExpressionCallAttribute), true).Any() - )) + if (exp3.IsExpressionCall()) { var ecc = new ExpressionCallContext { @@ -1097,10 +1093,7 @@ public string ExpressionLambdaToSql(Expression exp, ExpTSC tsc) if (exp3.Arguments[a].NodeType == ExpressionType.Call) //判断如果参数也是标记 ExpressionCall { var exp3ArgsACallExp = exp3.Arguments[a] as MethodCallExpression; - if (exp3ArgsACallExp.Object == null && ( - _dicTypeExistsExpressionCallAttribute.GetOrAdd(exp3ArgsACallExp.Method.DeclaringType, dttp => dttp.GetCustomAttributes(typeof(ExpressionCallAttribute), true).Any()) || - exp3ArgsACallExp.Method.GetCustomAttributes(typeof(ExpressionCallAttribute), true).Any() - )) + if (exp3ArgsACallExp.IsExpressionCall()) isdyInvoke = false; } if (isdyInvoke) @@ -1824,7 +1817,7 @@ public string ExpressionLambdaToSql(Expression exp, ExpTSC tsc) } other3Exp = ExpressionLambdaToSqlOther(exp3, tsc); if (string.IsNullOrEmpty(other3Exp) == false) return other3Exp; - if (exp3.IsParameter() == false) return formatSql(Expression.Lambda(exp3).Compile().DynamicInvoke(), tsc.mapType, tsc.mapColumnTmp, tsc.dbParams); + if (exp3.CanDynamicInvoke()) return formatSql(Expression.Lambda(exp3).Compile().DynamicInvoke(), tsc.mapType, tsc.mapColumnTmp, tsc.dbParams); if (exp3.Method.DeclaringType == typeof(Enumerable)) throw new Exception(CoreStrings.Not_Implemented_Expression_UseAsSelect(exp3, exp3.Method.Name, (exp3.Arguments.Count > 1 ? "..." : ""))); throw new Exception(CoreStrings.Not_Implemented_Expression(exp3)); case ExpressionType.Parameter: @@ -2230,7 +2223,7 @@ exp4.Expression is MethodCallExpression exp4CallExp && } if (dicExpressionOperator.TryGetValue(expBinary.NodeType, out var tryoper) == false) { - if (exp.IsParameter() == false) return formatSql(Expression.Lambda(exp).Compile().DynamicInvoke(), tsc.mapType, tsc.mapColumnTmp, tsc.dbParams); + if (exp.CanDynamicInvoke()) return formatSql(Expression.Lambda(exp).Compile().DynamicInvoke(), tsc.mapType, tsc.mapColumnTmp, tsc.dbParams); return ""; } switch (expBinary.NodeType) @@ -2392,11 +2385,11 @@ public static object ExpressionGetValue(Expression exp, out bool success) var expStackFirstMem = expStack.First() as MemberExpression; if (expStackFirstMem.Expression?.NodeType == ExpressionType.Constant) firstValue = (expStackFirstMem.Expression as ConstantExpression)?.Value; - else if (exp.IsParameter() == false) + else if (exp.CanDynamicInvoke()) return Expression.Lambda(exp).Compile().DynamicInvoke(); break; case ExpressionType.Call: - if (exp.IsParameter() == false) + if (exp.CanDynamicInvoke()) return Expression.Lambda(exp).Compile().DynamicInvoke(); break; } @@ -2417,7 +2410,7 @@ public static object ExpressionGetValue(Expression exp, out bool success) } return Expression.Lambda(exp).Compile().DynamicInvoke(); } - if (exp.IsParameter() == false) + if (exp.CanDynamicInvoke()) return Expression.Lambda(exp).Compile().DynamicInvoke(); success = false; return null;