Skip to content

Commit 1a8c7ce

Browse files
2881028810
28810
authored and
28810
committed
- 增加 SqlServer lambda 表达式树解析子查询 ToList + string.Join() 产生 类似 group_concat 的效果;#405
1 parent 25e7311 commit 1a8c7ce

File tree

4 files changed

+68
-0
lines changed

4 files changed

+68
-0
lines changed

FreeSql.Tests/FreeSql.Tests/SqlServer/SqlServerExpression/StringTest.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,24 @@ public void Equals__()
6666
list.Add(select.Where(a => a.TitleVarchar == "aaa").ToList());
6767
}
6868

69+
[Fact]
70+
public void StringJoin()
71+
{
72+
var fsql = g.sqlserver;
73+
fsql.Delete<StringJoin01>().Where("1=1").ExecuteAffrows();
74+
fsql.Insert(new[] { new StringJoin01 { name = "北京" }, new StringJoin01 { name = "上海" }, new StringJoin01 { name = "深圳" }, }).ExecuteAffrows();
75+
76+
var val1 = string.Join(",", fsql.Select<StringJoin01>().ToList(a => a.name)) + ",";
77+
var val2 = fsql.Select<StringJoin01>().ToList(a => string.Join(",", fsql.Select<StringJoin01>().As("b").ToList(b => b.name)));
78+
Assert.Equal(val1, val2[0]);
79+
}
80+
class StringJoin01
81+
{
82+
[Column(IsIdentity = true)]
83+
public int id { get; set; }
84+
public string name { get; set; }
85+
}
86+
6987
[Fact]
7088
public void First()
7189
{

FreeSql/Extensions/FreeSqlGlobalExpressionCallExtensions.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,18 @@ public static class SqlExt
114114
/// <param name="column"></param>
115115
/// <returns></returns>
116116
public static IGroupConcat GroupConcat(object column) => SqlExtExtensions.GroupConcat(column);
117+
118+
/// <summary>
119+
/// PostgreSQL string_agg(.., ..)
120+
/// </summary>
121+
/// <param name="column"></param>
122+
/// <param name="delimiter"></param>
123+
/// <returns></returns>
124+
public static string StringAgg(object column, object delimiter)
125+
{
126+
expContext.Value.Result = $"string_agg({expContext.Value.ParsedContent["column"]}, {expContext.Value.ParsedContent["delimiter"]})";
127+
return "";
128+
}
117129
}
118130

119131
[ExpressionCall]

FreeSql/Extensions/LambadaExpressionExtensions.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,26 @@ internal static bool IsParameter(this Expression exp)
233233
test.Visit(exp);
234234
return test.Result;
235235
}
236+
237+
public static bool IsStringJoin(this MethodCallExpression exp, out MethodCallExpression joinExpArgs1Out, out LambdaExpression joinExpArgs1Args0Out)
238+
{
239+
if (exp.Arguments.Count == 2 &&
240+
exp.Arguments[1].NodeType == ExpressionType.Call &&
241+
exp.Arguments[1].Type.FullName.StartsWith("System.Collections.Generic.List`1") &&
242+
exp.Arguments[1] is MethodCallExpression joinExpArgs1 &&
243+
joinExpArgs1.Method.Name == "ToList" &&
244+
joinExpArgs1.Arguments.Count == 1 &&
245+
joinExpArgs1.Arguments[0] is UnaryExpression joinExpArgs1Args0Tmp &&
246+
joinExpArgs1Args0Tmp.Operand is LambdaExpression joinExpArgs1Args0)
247+
{
248+
joinExpArgs1Out = joinExpArgs1;
249+
joinExpArgs1Args0Out = joinExpArgs1Args0;
250+
return true;
251+
}
252+
joinExpArgs1Out = null;
253+
joinExpArgs1Args0Out = null;
254+
return false;
255+
}
236256
}
237257

238258
internal class NewExpressionVisitor : ExpressionVisitor

Providers/FreeSql.Provider.SqlServer/SqlServerExpression.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,24 @@ public override string ExpressionLambdaToSqlCallString(MethodCallExpression exp,
283283
return $"'+{_common.IsNull($"cast({ExpressionLambdaToSql(a, tsc)} as nvarchar(max))", "''")}+{nchar}'";
284284
}).ToArray();
285285
return string.Format(expArgs0, expArgs);
286+
case "Join":
287+
if (exp.IsStringJoin(out var joinExpArgs1, out var joinExpArgs1Args0))
288+
{
289+
var newToListArgs0 = Expression.Call(joinExpArgs1.Object, joinExpArgs1.Method,
290+
Expression.Lambda(
291+
Expression.Call(
292+
typeof(string).GetMethod("Concat", new[] { typeof(object), typeof(object) }),
293+
Expression.Convert(joinExpArgs1Args0.Body, typeof(object)),
294+
Expression.Convert(exp.Arguments[0], typeof(object))),
295+
joinExpArgs1Args0.Parameters));
296+
var newToListSql = getExp(newToListArgs0);
297+
if (string.IsNullOrEmpty(newToListSql) == false && newToListSql.StartsWith("(") && newToListSql.EndsWith(")"))
298+
{
299+
newToListSql = $"{newToListSql.Substring(0, newToListSql.Length - 1)} FOR XML PATH(''))";
300+
return newToListSql;
301+
}
302+
}
303+
break;
286304
}
287305
}
288306
else

0 commit comments

Comments
 (0)