mirror of
https://github.com/nsnail/FreeSql.git
synced 2025-04-22 10:42:52 +08:00
- 增加 Array.Any(x => x.id == a.Id && ..) 表达式树解析;#243
This commit is contained in:
parent
5a9c92bc54
commit
3a7533246e
@ -786,5 +786,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>
|
||||||
|
@ -15,6 +15,75 @@ namespace FreeSql.Tests.SqliteExpression
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ArrayAny()
|
||||||
|
{
|
||||||
|
var fsql = g.sqlite;
|
||||||
|
fsql.Delete<ArrayAny01>().Where("1=1").ExecuteAffrows();
|
||||||
|
|
||||||
|
var t1 = fsql.Select<ArrayAny01>().Where(a => new[] {
|
||||||
|
new ArrayAny02 { Name1 = "name01", Click1 = 1 },
|
||||||
|
}.Any(b => b.Name1 == a.Name && b.Click1 == a.Click || a.Click > 10)).ToSql();
|
||||||
|
Assert.Equal(@"SELECT a.""Id"", a.""Name"", a.""Click""
|
||||||
|
FROM ""ArrayAny01"" a
|
||||||
|
WHERE (('name01' = a.""Name"" AND 1 = a.""Click"" OR a.""Click"" > 10))", t1);
|
||||||
|
|
||||||
|
var t2 = fsql.Select<ArrayAny01>().Where(a => new[] {
|
||||||
|
new ArrayAny02 { Name1 = "name01", Click1 = 1 },
|
||||||
|
new ArrayAny02 { Name1 = "name02", Click1 = 2 },
|
||||||
|
}.Any(b => b.Name1 == a.Name && b.Click1 == a.Click || a.Click > 10)).ToSql();
|
||||||
|
Assert.Equal(@"SELECT a.""Id"", a.""Name"", a.""Click""
|
||||||
|
FROM ""ArrayAny01"" a
|
||||||
|
WHERE (('name01' = a.""Name"" AND 1 = a.""Click"" OR a.""Click"" > 10) OR ('name02' = a.""Name"" AND 2 = a.""Click"" OR a.""Click"" > 10))", t1);
|
||||||
|
|
||||||
|
var aa03 = new[] {
|
||||||
|
new ArrayAny02 { Name1 = "name01", Click1 = 1 },
|
||||||
|
};
|
||||||
|
var t3 = fsql.Select<ArrayAny01>().Where(a => aa03.Any(b => b.Name1 == a.Name && b.Click1 == a.Click || a.Click > 10)).ToSql();
|
||||||
|
Assert.Equal(@"SELECT a.""Id"", a.""Name"", a.""Click""
|
||||||
|
FROM ""ArrayAny01"" a
|
||||||
|
WHERE (('name01' = a.""Name"" AND 1 = a.""Click"" OR a.""Click"" > 10))", t1);
|
||||||
|
|
||||||
|
var aa04 = new[] {
|
||||||
|
new ArrayAny02 { Name1 = "name01", Click1 = 1 },
|
||||||
|
new ArrayAny02 { Name1 = "name02", Click1 = 2 },
|
||||||
|
};
|
||||||
|
var t4 = fsql.Select<ArrayAny01>().Where(a => aa04.Any(b => b.Name1 == a.Name && b.Click1 == a.Click || a.Click > 10)).ToSql();
|
||||||
|
Assert.Equal(@"SELECT a.""Id"", a.""Name"", a.""Click""
|
||||||
|
FROM ""ArrayAny01"" a
|
||||||
|
WHERE (('name01' = a.""Name"" AND 1 = a.""Click"" OR a.""Click"" > 10) OR ('name02' = a.""Name"" AND 2 = a.""Click"" OR a.""Click"" > 10))", t1);
|
||||||
|
|
||||||
|
// List
|
||||||
|
|
||||||
|
var aa05 = new List<ArrayAny02> {
|
||||||
|
new ArrayAny02 { Name1 = "name01", Click1 = 1 },
|
||||||
|
};
|
||||||
|
var t5 = fsql.Select<ArrayAny01>().Where(a => aa05.Any(b => b.Name1 == a.Name && b.Click1 == a.Click || a.Click > 10)).ToSql();
|
||||||
|
Assert.Equal(@"SELECT a.""Id"", a.""Name"", a.""Click""
|
||||||
|
FROM ""ArrayAny01"" a
|
||||||
|
WHERE (('name01' = a.""Name"" AND 1 = a.""Click"" OR a.""Click"" > 10))", t1);
|
||||||
|
|
||||||
|
var aa06 = new List<ArrayAny02> {
|
||||||
|
new ArrayAny02 { Name1 = "name01", Click1 = 1 },
|
||||||
|
new ArrayAny02 { Name1 = "name02", Click1 = 2 },
|
||||||
|
};
|
||||||
|
var t6 = fsql.Select<ArrayAny01>().Where(a => aa06.Any(b => b.Name1 == a.Name && b.Click1 == a.Click || a.Click > 10)).ToSql();
|
||||||
|
Assert.Equal(@"SELECT a.""Id"", a.""Name"", a.""Click""
|
||||||
|
FROM ""ArrayAny01"" a
|
||||||
|
WHERE (('name01' = a.""Name"" AND 1 = a.""Click"" OR a.""Click"" > 10) OR ('name02' = a.""Name"" AND 2 = a.""Click"" OR a.""Click"" > 10))", t1);
|
||||||
|
}
|
||||||
|
class ArrayAny01
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
public string Name { get; set; }
|
||||||
|
public long Click { get; set; }
|
||||||
|
}
|
||||||
|
class ArrayAny02
|
||||||
|
{
|
||||||
|
public string Name1 { get; set; }
|
||||||
|
public long Click1 { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Div()
|
public void Div()
|
||||||
{
|
{
|
||||||
|
@ -906,6 +906,30 @@ namespace FreeSql.Internal
|
|||||||
if (exp3.Arguments.Count > 0 && exp3.Object != null) return ExpressionBinary("=", exp3.Object, exp3.Arguments[0], tsc);
|
if (exp3.Arguments.Count > 0 && exp3.Object != null) return ExpressionBinary("=", exp3.Object, exp3.Arguments[0], tsc);
|
||||||
if (exp3.Arguments.Count > 1 && exp3.Method.DeclaringType == typeof(object)) return ExpressionBinary("=", exp3.Arguments[0], exp3.Arguments[1], tsc);
|
if (exp3.Arguments.Count > 1 && exp3.Method.DeclaringType == typeof(object)) return ExpressionBinary("=", exp3.Arguments[0], exp3.Arguments[1], tsc);
|
||||||
}
|
}
|
||||||
|
if (exp3.Method.Name == "Any" && exp3.Method.DeclaringType == typeof(Enumerable))
|
||||||
|
{
|
||||||
|
//Where(a => idArray.Any(p => (a.Id == p.Key || a.RoleName == p.Key) && a.RoleType == p.Type))
|
||||||
|
var exp3MethodGenArgs = exp3.Method.GetGenericArguments();
|
||||||
|
var exp3MethodArgs = exp3.Method.GetParameters();
|
||||||
|
if (exp3MethodGenArgs.Length == 1 && exp3MethodArgs.Length == 2 && exp3MethodArgs[1].ParameterType == typeof(Func<,>).MakeGenericType(exp3MethodGenArgs[0], typeof(bool)))
|
||||||
|
{
|
||||||
|
var exp3Value = ExpressionGetValue(exp3.Arguments[0], out var exp3ValueSuccess);
|
||||||
|
if (exp3ValueSuccess)
|
||||||
|
{
|
||||||
|
if (exp3Value == null) return "1=2";
|
||||||
|
var exp3ValueIE = exp3Value as IEnumerable;
|
||||||
|
var exp3NewExpVisitor = new ReplaceParameterVisitor();
|
||||||
|
var exp3sb = new StringBuilder();
|
||||||
|
foreach (var exp3ValueItem in exp3ValueIE)
|
||||||
|
{
|
||||||
|
var exp3NewExp = exp3NewExpVisitor.Modify(exp3.Arguments[1] as LambdaExpression, Expression.Constant(exp3ValueItem, exp3MethodGenArgs[0]));
|
||||||
|
exp3sb.Append(" OR ").Append(ExpressionLambdaToSql(exp3NewExp, tsc));
|
||||||
|
}
|
||||||
|
if (exp3sb.Length == 0) return "1=2";
|
||||||
|
return exp3sb.Remove(0, 4).ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if (callType.FullName.StartsWith("FreeSql.ISelectGroupingAggregate`"))
|
if (callType.FullName.StartsWith("FreeSql.ISelectGroupingAggregate`"))
|
||||||
{
|
{
|
||||||
switch (exp3.Method.Name)
|
switch (exp3.Method.Name)
|
||||||
@ -1736,6 +1760,86 @@ namespace FreeSql.Internal
|
|||||||
public abstract string ExpressionLambdaToSqlOther(Expression exp, ExpTSC tsc);
|
public abstract string ExpressionLambdaToSqlOther(Expression exp, ExpTSC tsc);
|
||||||
public string ExpressionConstDateTime(Expression exp) => exp is ConstantExpression operandExpConst ? formatSql(Utils.GetDataReaderValue(typeof(DateTime), operandExpConst.Value), null, null, null) : null;
|
public string ExpressionConstDateTime(Expression exp) => exp is ConstantExpression operandExpConst ? formatSql(Utils.GetDataReaderValue(typeof(DateTime), operandExpConst.Value), null, null, null) : null;
|
||||||
|
|
||||||
|
public static object ExpressionGetValue(Expression exp, out bool success)
|
||||||
|
{
|
||||||
|
success = true;
|
||||||
|
var expStack = new Stack<Expression>();
|
||||||
|
var expStackConstOrMemberCount = 1;
|
||||||
|
var exp2 = exp;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
switch (exp2?.NodeType)
|
||||||
|
{
|
||||||
|
case ExpressionType.Constant:
|
||||||
|
expStack.Push(exp2);
|
||||||
|
expStackConstOrMemberCount++;
|
||||||
|
break;
|
||||||
|
case ExpressionType.Parameter:
|
||||||
|
expStack.Push(exp2);
|
||||||
|
break;
|
||||||
|
case ExpressionType.MemberAccess:
|
||||||
|
expStack.Push(exp2);
|
||||||
|
exp2 = (exp2 as MemberExpression).Expression;
|
||||||
|
expStackConstOrMemberCount++;
|
||||||
|
if (exp2 == null) break;
|
||||||
|
continue;
|
||||||
|
case ExpressionType.Call:
|
||||||
|
var callExp = exp2 as MethodCallExpression;
|
||||||
|
expStack.Push(exp2);
|
||||||
|
exp2 = callExp.Object;
|
||||||
|
if (exp2 == null) break;
|
||||||
|
continue;
|
||||||
|
case ExpressionType.TypeAs:
|
||||||
|
case ExpressionType.Convert:
|
||||||
|
var oper2 = (exp2 as UnaryExpression).Operand;
|
||||||
|
if (oper2.NodeType == ExpressionType.Parameter)
|
||||||
|
{
|
||||||
|
var oper2Parm = oper2 as ParameterExpression;
|
||||||
|
expStack.Push(exp2.Type.IsAbstract || exp2.Type.IsInterface ? oper2Parm : Expression.Parameter(exp2.Type, oper2Parm.Name));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
expStack.Push(oper2);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (expStack.Any() && expStack.First().NodeType != ExpressionType.Parameter)
|
||||||
|
{
|
||||||
|
if (expStackConstOrMemberCount == expStack.Count)
|
||||||
|
{
|
||||||
|
object firstValue = null;
|
||||||
|
switch (expStack.First().NodeType)
|
||||||
|
{
|
||||||
|
case ExpressionType.Constant:
|
||||||
|
var expStackFirst = expStack.Pop() as ConstantExpression;
|
||||||
|
firstValue = expStackFirst?.Value;
|
||||||
|
break;
|
||||||
|
case ExpressionType.MemberAccess:
|
||||||
|
var expStackFirstMem = expStack.First() as MemberExpression;
|
||||||
|
if (expStackFirstMem.Expression?.NodeType == ExpressionType.Constant)
|
||||||
|
firstValue = (expStackFirstMem.Expression as ConstantExpression)?.Value;
|
||||||
|
else
|
||||||
|
return Expression.Lambda(exp).Compile().DynamicInvoke();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
while (expStack.Any())
|
||||||
|
{
|
||||||
|
var expStackItem = expStack.Pop() as MemberExpression;
|
||||||
|
if (expStackItem.Member.MemberType == MemberTypes.Property)
|
||||||
|
firstValue = ((PropertyInfo)expStackItem.Member).GetValue(firstValue, null);
|
||||||
|
else if (expStackItem.Member.MemberType == MemberTypes.Field)
|
||||||
|
firstValue = ((FieldInfo)expStackItem.Member).GetValue(firstValue);
|
||||||
|
}
|
||||||
|
return firstValue;
|
||||||
|
}
|
||||||
|
return Expression.Lambda(exp).Compile().DynamicInvoke();
|
||||||
|
}
|
||||||
|
if (exp.IsParameter() == false)
|
||||||
|
return Expression.Lambda(exp).Compile().DynamicInvoke();
|
||||||
|
success = false;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
public enum ExpressionStyle
|
public enum ExpressionStyle
|
||||||
{
|
{
|
||||||
Where, AsSelect, SelectColumns
|
Where, AsSelect, SelectColumns
|
||||||
@ -1889,18 +1993,18 @@ namespace FreeSql.Internal
|
|||||||
}
|
}
|
||||||
public class ReplaceParameterVisitor : ExpressionVisitor
|
public class ReplaceParameterVisitor : ExpressionVisitor
|
||||||
{
|
{
|
||||||
private ParameterExpression parameter;
|
private Expression _replaceExp;
|
||||||
private ParameterExpression oldParameter;
|
private ParameterExpression oldParameter;
|
||||||
public Expression Modify(LambdaExpression lambda, ParameterExpression parameter)
|
public Expression Modify(LambdaExpression lambda, Expression replaceExp)
|
||||||
{
|
{
|
||||||
this.parameter = parameter;
|
this._replaceExp = replaceExp;
|
||||||
this.oldParameter = lambda.Parameters.FirstOrDefault();
|
this.oldParameter = lambda.Parameters.FirstOrDefault();
|
||||||
return Visit(lambda.Body);
|
return Visit(lambda.Body);
|
||||||
}
|
}
|
||||||
protected override Expression VisitMember(MemberExpression node)
|
protected override Expression VisitMember(MemberExpression node)
|
||||||
{
|
{
|
||||||
if (node.Expression?.NodeType == ExpressionType.Parameter && node.Expression == oldParameter)
|
if (node.Expression?.NodeType == ExpressionType.Parameter && node.Expression == oldParameter)
|
||||||
return Expression.Property(parameter, node.Member.Name);
|
return Expression.Property(_replaceExp, node.Member.Name);
|
||||||
return base.VisitMember(node);
|
return base.VisitMember(node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user