- 增加 SqlServer lambda 表达式树解析子查询 ToList + string.Join() 产生 类似 group_concat 的效果;#405

This commit is contained in:
28810 2020-08-08 00:53:27 +08:00
parent 25e73117b1
commit 1a8c7ce86d
4 changed files with 68 additions and 0 deletions

View File

@ -66,6 +66,24 @@ namespace FreeSql.Tests.SqlServerExpression
list.Add(select.Where(a => a.TitleVarchar == "aaa").ToList()); list.Add(select.Where(a => a.TitleVarchar == "aaa").ToList());
} }
[Fact]
public void StringJoin()
{
var fsql = g.sqlserver;
fsql.Delete<StringJoin01>().Where("1=1").ExecuteAffrows();
fsql.Insert(new[] { new StringJoin01 { name = "±±¾©" }, new StringJoin01 { name = "ÉϺ£" }, new StringJoin01 { name = "ÉîÛÚ" }, }).ExecuteAffrows();
var val1 = string.Join(",", fsql.Select<StringJoin01>().ToList(a => a.name)) + ",";
var val2 = fsql.Select<StringJoin01>().ToList(a => string.Join(",", fsql.Select<StringJoin01>().As("b").ToList(b => b.name)));
Assert.Equal(val1, val2[0]);
}
class StringJoin01
{
[Column(IsIdentity = true)]
public int id { get; set; }
public string name { get; set; }
}
[Fact] [Fact]
public void First() public void First()
{ {

View File

@ -114,6 +114,18 @@ namespace FreeSql
/// <param name="column"></param> /// <param name="column"></param>
/// <returns></returns> /// <returns></returns>
public static IGroupConcat GroupConcat(object column) => SqlExtExtensions.GroupConcat(column); public static IGroupConcat GroupConcat(object column) => SqlExtExtensions.GroupConcat(column);
/// <summary>
/// PostgreSQL string_agg(.., ..)
/// </summary>
/// <param name="column"></param>
/// <param name="delimiter"></param>
/// <returns></returns>
public static string StringAgg(object column, object delimiter)
{
expContext.Value.Result = $"string_agg({expContext.Value.ParsedContent["column"]}, {expContext.Value.ParsedContent["delimiter"]})";
return "";
}
} }
[ExpressionCall] [ExpressionCall]

View File

@ -233,6 +233,26 @@ namespace System.Linq.Expressions
test.Visit(exp); test.Visit(exp);
return test.Result; return test.Result;
} }
public static bool IsStringJoin(this MethodCallExpression exp, out MethodCallExpression joinExpArgs1Out, out LambdaExpression joinExpArgs1Args0Out)
{
if (exp.Arguments.Count == 2 &&
exp.Arguments[1].NodeType == ExpressionType.Call &&
exp.Arguments[1].Type.FullName.StartsWith("System.Collections.Generic.List`1") &&
exp.Arguments[1] is MethodCallExpression joinExpArgs1 &&
joinExpArgs1.Method.Name == "ToList" &&
joinExpArgs1.Arguments.Count == 1 &&
joinExpArgs1.Arguments[0] is UnaryExpression joinExpArgs1Args0Tmp &&
joinExpArgs1Args0Tmp.Operand is LambdaExpression joinExpArgs1Args0)
{
joinExpArgs1Out = joinExpArgs1;
joinExpArgs1Args0Out = joinExpArgs1Args0;
return true;
}
joinExpArgs1Out = null;
joinExpArgs1Args0Out = null;
return false;
}
} }
internal class NewExpressionVisitor : ExpressionVisitor internal class NewExpressionVisitor : ExpressionVisitor

View File

@ -283,6 +283,24 @@ namespace FreeSql.SqlServer
return $"'+{_common.IsNull($"cast({ExpressionLambdaToSql(a, tsc)} as nvarchar(max))", "''")}+{nchar}'"; return $"'+{_common.IsNull($"cast({ExpressionLambdaToSql(a, tsc)} as nvarchar(max))", "''")}+{nchar}'";
}).ToArray(); }).ToArray();
return string.Format(expArgs0, expArgs); return string.Format(expArgs0, expArgs);
case "Join":
if (exp.IsStringJoin(out var joinExpArgs1, out var joinExpArgs1Args0))
{
var newToListArgs0 = Expression.Call(joinExpArgs1.Object, joinExpArgs1.Method,
Expression.Lambda(
Expression.Call(
typeof(string).GetMethod("Concat", new[] { typeof(object), typeof(object) }),
Expression.Convert(joinExpArgs1Args0.Body, typeof(object)),
Expression.Convert(exp.Arguments[0], typeof(object))),
joinExpArgs1Args0.Parameters));
var newToListSql = getExp(newToListArgs0);
if (string.IsNullOrEmpty(newToListSql) == false && newToListSql.StartsWith("(") && newToListSql.EndsWith(")"))
{
newToListSql = $"{newToListSql.Substring(0, newToListSql.Length - 1)} FOR XML PATH(''))";
return newToListSql;
}
}
break;
} }
} }
else else