From 89fa0dc9f6d00ee667da68825df99b57dd937f14 Mon Sep 17 00:00:00 2001
From: 2881099 <2881099@qq.com>
Date: Fri, 25 Dec 2020 14:31:57 +0800
Subject: [PATCH] =?UTF-8?q?-=20=E8=A1=A5=E5=85=85=20=E6=94=AF=E6=8C=81=20M?=
=?UTF-8?q?anyToMany=20=E5=AF=BC=E8=88=AA=E5=B1=9E=E6=80=A7=E5=AD=90?=
=?UTF-8?q?=E6=9F=A5=E8=AF=A2=20ToList=EF=BC=9B?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
FreeSql.DbContext/FreeSql.DbContext.xml | 9 -
.../SqlServerExpression/StringTest.cs | 144 ++++++++++++++
FreeSql/FreeSql.xml | 183 ------------------
FreeSql/Internal/CommonExpression.cs | 34 +++-
4 files changed, 172 insertions(+), 198 deletions(-)
diff --git a/FreeSql.DbContext/FreeSql.DbContext.xml b/FreeSql.DbContext/FreeSql.DbContext.xml
index 27909b2e..02eb0609 100644
--- a/FreeSql.DbContext/FreeSql.DbContext.xml
+++ b/FreeSql.DbContext/FreeSql.DbContext.xml
@@ -512,14 +512,5 @@
-
-
- 批量注入 Repository,可以参考代码自行调整
-
-
-
-
-
-
diff --git a/FreeSql.Tests/FreeSql.Tests/SqlServer/SqlServerExpression/StringTest.cs b/FreeSql.Tests/FreeSql.Tests/SqlServer/SqlServerExpression/StringTest.cs
index ad7714d9..48074e69 100644
--- a/FreeSql.Tests/FreeSql.Tests/SqlServer/SqlServerExpression/StringTest.cs
+++ b/FreeSql.Tests/FreeSql.Tests/SqlServer/SqlServerExpression/StringTest.cs
@@ -96,6 +96,150 @@ namespace FreeSql.Tests.SqlServerExpression
public string name { get; set; }
}
+ [Fact]
+ public void StringJoin02()
+ {
+ var fsql = g.sqlserver;
+ fsql.Delete().Where("1=1").ExecuteAffrows();
+ fsql.Delete().Where("1=1").ExecuteAffrows();
+ fsql.Delete().Where("1=1").ExecuteAffrows();
+
+ var users = fsql.Insert(new[]
+ {
+ new StringJoin02User { UserName = "user01" },
+ new StringJoin02User { UserName = "user02" }
+ }).ExecuteInserted();
+
+ var roles = fsql.Insert(new[]
+ {
+ new StringJoin02Role { RoleName = "role01" },
+ new StringJoin02Role { RoleName = "role02" },
+ new StringJoin02Role { RoleName = "role03" }
+ }).ExecuteInserted();
+
+ fsql.Insert(new[]
+ {
+ new StringJoin02UserRole{ UserId = users[0].Id, RoleId = roles[0].Id },
+ new StringJoin02UserRole{ UserId = users[0].Id, RoleId = roles[1].Id },
+ new StringJoin02UserRole{ UserId = users[0].Id, RoleId = roles[2].Id },
+
+ new StringJoin02UserRole{ UserId = users[1].Id, RoleId = roles[0].Id },
+ new StringJoin02UserRole{ UserId = users[1].Id, RoleId = roles[2].Id },
+ }).ExecuteAffrows();
+
+ var repo = fsql.GetRepository();
+ var result = repo.Select.ToList(w =>
+ new
+ {
+ w.Id,
+ w.UserName,
+ ǰɫ = string.Join(",", repo.Orm
+ .Select()
+ .LeftJoin((b, c) => b.RoleId == c.Id)
+ .Where((b, c) => b.UserId == w.Id)
+ .ToList((b, c) => c.RoleName))
+ });
+ Assert.Equal(2, result.Count);
+ Assert.Equal(users[0].Id, result[0].Id);
+ Assert.Equal("user01", result[0].UserName);
+ Assert.Equal("role01,role02,role03", result[0].ǰɫ);
+
+ Assert.Equal(users[1].Id, result[1].Id);
+ Assert.Equal("user02", result[1].UserName);
+ Assert.Equal("role01,role03", result[1].ǰɫ);
+ }
+ class StringJoin02User
+ {
+ [Column(IsIdentity = true)]
+ public int Id { get; set; }
+ public string UserName { get; set; }
+ }
+ class StringJoin02Role
+ {
+ [Column(IsIdentity = true)]
+ public int Id { get; set; }
+ public string RoleName { get; set; }
+ }
+ class StringJoin02UserRole
+ {
+ public int UserId { get; set; }
+ public int RoleId { get; set; }
+ }
+
+ [Fact]
+ public void StringJoin03()
+ {
+ var fsql = g.sqlserver;
+ fsql.Delete().Where("1=1").ExecuteAffrows();
+ fsql.Delete().Where("1=1").ExecuteAffrows();
+ fsql.Delete().Where("1=1").ExecuteAffrows();
+
+ var users = fsql.Insert(new[]
+ {
+ new StringJoin03User { UserName = "user01" },
+ new StringJoin03User { UserName = "user02" }
+ }).ExecuteInserted();
+
+ var roles = fsql.Insert(new[]
+ {
+ new StringJoin03Role { RoleName = "role01" },
+ new StringJoin03Role { RoleName = "role02" },
+ new StringJoin03Role { RoleName = "role03" }
+ }).ExecuteInserted();
+
+ fsql.Insert(new[]
+ {
+ new StringJoin03UserRole{ UserId = users[0].Id, RoleId = roles[0].Id },
+ new StringJoin03UserRole{ UserId = users[0].Id, RoleId = roles[1].Id },
+ new StringJoin03UserRole{ UserId = users[0].Id, RoleId = roles[2].Id },
+
+ new StringJoin03UserRole{ UserId = users[1].Id, RoleId = roles[0].Id },
+ new StringJoin03UserRole{ UserId = users[1].Id, RoleId = roles[2].Id },
+ }).ExecuteAffrows();
+
+ var repo = fsql.GetRepository();
+ var result = repo.Select.ToList(w =>
+ new
+ {
+ w.Id,
+ w.UserName,
+ ǰɫ = string.Join(",", w.Roles.AsSelect().ToList(b => b.RoleName))
+ });
+ Assert.Equal(2, result.Count);
+ Assert.Equal(users[0].Id, result[0].Id);
+ Assert.Equal("user01", result[0].UserName);
+ Assert.Equal("role01,role02,role03", result[0].ǰɫ);
+
+ Assert.Equal(users[1].Id, result[1].Id);
+ Assert.Equal("user02", result[1].UserName);
+ Assert.Equal("role01,role03", result[1].ǰɫ);
+ }
+ class StringJoin03User
+ {
+ [Column(IsIdentity = true)]
+ public int Id { get; set; }
+ public string UserName { get; set; }
+
+ [Navigate(ManyToMany = typeof(StringJoin03UserRole))]
+ public List Roles { get; set; }
+ }
+ class StringJoin03Role
+ {
+ [Column(IsIdentity = true)]
+ public int Id { get; set; }
+ public string RoleName { get; set; }
+
+ [Navigate(ManyToMany = typeof(StringJoin03UserRole))]
+ public List Users { get; set; }
+ }
+ class StringJoin03UserRole
+ {
+ public int UserId { get; set; }
+ public int RoleId { get; set; }
+ public StringJoin03User User { get; set; }
+ public StringJoin03Role Role { get; set; }
+ }
+
[Fact]
public void First()
{
diff --git a/FreeSql/FreeSql.xml b/FreeSql/FreeSql.xml
index 7f84d792..d8ca0ba3 100644
--- a/FreeSql/FreeSql.xml
+++ b/FreeSql/FreeSql.xml
@@ -3133,177 +3133,6 @@
-
-
- 测试数据库是否连接正确,本方法执行如下命令:
- MySql/SqlServer/PostgreSQL/达梦/人大金仓/神通: SELECT 1
- Oracle: SELECT 1 FROM dual
-
- 命令超时设置(秒)
-
- true: 成功, false: 失败
-
-
-
- 查询,若使用读写分离,查询【从库】条件cmdText.StartsWith("SELECT "),否则查询【主库】
-
-
-
-
-
-
-
-
-
- 查询,ExecuteReaderAsync(dr => {}, "select * from user where age > @age", new { age = 25 })
- 提示:parms 参数还可以传 Dictionary<string, object>
-
-
-
-
-
-
-
-
- 查询
-
-
-
-
-
-
-
-
- 查询,ExecuteArrayAsync("select * from user where age > @age", new { age = 25 })
- 提示:parms 参数还可以传 Dictionary<string, object>
-
-
-
-
-
-
-
-
- 查询
-
-
-
-
-
-
-
-
- 查询,ExecuteDataSetAsync("select * from user where age > @age; select 2", new { age = 25 })
- 提示:parms 参数还可以传 Dictionary<string, object>
-
-
-
-
-
-
-
-
- 查询
-
-
-
-
-
-
-
-
- 查询,ExecuteDataTableAsync("select * from user where age > @age", new { age = 25 })
- 提示:parms 参数还可以传 Dictionary<string, object>
-
-
-
-
-
-
-
-
- 在【主库】执行
-
-
-
-
-
-
-
-
- 在【主库】执行,ExecuteNonQueryAsync("delete from user where age > @age", new { age = 25 })
- 提示:parms 参数还可以传 Dictionary<string, object>
-
-
-
-
-
-
-
-
- 在【主库】执行
-
-
-
-
-
-
-
-
- 在【主库】执行,ExecuteScalarAsync("select 1 from user where age > @age", new { age = 25 })
- 提示:parms 参数还可以传 Dictionary<string, object>
-
-
-
-
-
-
-
-
- 执行SQL返回对象集合,QueryAsync<User>("select * from user where age > @age", new SqlParameter { ParameterName = "age", Value = 25 })
-
-
-
-
-
-
-
-
-
-
- 执行SQL返回对象集合,QueryAsync<User>("select * from user where age > @age", new { age = 25 })
- 提示:parms 参数还可以传 Dictionary<string, object>
-
-
-
-
-
-
-
-
-
- 执行SQL返回对象集合,Query<User>("select * from user where age > @age; select * from address", new SqlParameter { ParameterName = "age", Value = 25 })
-
-
-
-
-
-
-
-
-
-
-
- 执行SQL返回对象集合,Query<User, Address>("select * from user where age > @age; select * from address", new { age = 25 })
- 提示:parms 参数还可以传 Dictionary<string, object>
-
-
-
-
-
-
-
-
可自定义解析表达式
@@ -4137,12 +3966,6 @@
超时
-
-
- 获取资源
-
-
-
使用完毕后,归还资源
@@ -4213,12 +4036,6 @@
资源对象
-
-
- 从对象池获取对象成功的时候触发,通过该方法统计或初始化对象
-
- 资源对象
-
归还对象给对象池的时候触发
diff --git a/FreeSql/Internal/CommonExpression.cs b/FreeSql/Internal/CommonExpression.cs
index 103fefa8..1858e48e 100644
--- a/FreeSql/Internal/CommonExpression.cs
+++ b/FreeSql/Internal/CommonExpression.cs
@@ -700,6 +700,7 @@ namespace FreeSql.Internal
static ConcurrentDictionary> _dicMethodExistsExpressionCallAttribute = new ConcurrentDictionary>();
static ConcurrentDictionary _dicTypeExpressionCallClassContextFields = new ConcurrentDictionary();
static ThreadLocal> _subSelectParentDiyMemExps = new ThreadLocal>(); //子查询的所有父自定义查询,比如分组之后的子查询
+ static ConcurrentDictionary _dicSelectMethodToSql = new ConcurrentDictionary();
public string ExpressionLambdaToSql(Expression exp, ExpTSC tsc)
{
if (exp == null) return "";
@@ -1161,16 +1162,16 @@ namespace FreeSql.Internal
if (mn == 0) fsqlManyWhereExp = tmpExp;
else fsqlManyWhereExp = Expression.AndAlso(fsqlManyWhereExp, tmpExp);
}
- 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));
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()).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);
@@ -1182,7 +1183,28 @@ namespace FreeSql.Internal
case "ToList":
case "ToOne":
case "First":
- throw new ArgumentException($"ManyToMany 导航属性 .AsSelect() 暂时不可用于 Sum/Avg/Max/Min/First/ToOne/ToList 方法");
+ //解析: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($"ManyToMany 导航属性 .AsSelect() 暂时不可用于 Sum/Avg/Max/Min/First/ToOne/ToList 方法");
+ 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(")");
+ 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);