From 8b5b23202c00672b0c8e514f6f08f498fb0d9fd8 Mon Sep 17 00:00:00 2001 From: 2881099 <2881099@qq.com> Date: Fri, 3 Mar 2023 00:37:18 +0800 Subject: [PATCH] =?UTF-8?q?-=20=E5=A2=9E=E5=8A=A0=20ISelect=20FromQuery?= =?UTF-8?q?=20=E9=87=8D=E8=BD=BD=E5=A4=9A=E8=A1=A8=E5=B5=8C=E5=A5=97?= =?UTF-8?q?=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- FreeSql.DbContext/FreeSql.DbContext.xml | 9 - .../Curd/SqlServerSelectWithTempQueryTest.cs | 33 ++ FreeSql/FreeSql.xml | 402 ++++++++++-------- FreeSql/Interface/Curd/ISelect/ISelect1.cs | 3 + .../SelectProvider/Select0Provider.cs | 10 +- .../SelectProvider/Select1Provider.cs | 88 +++- 6 files changed, 348 insertions(+), 197 deletions(-) diff --git a/FreeSql.DbContext/FreeSql.DbContext.xml b/FreeSql.DbContext/FreeSql.DbContext.xml index 26522f10..537315e2 100644 --- a/FreeSql.DbContext/FreeSql.DbContext.xml +++ b/FreeSql.DbContext/FreeSql.DbContext.xml @@ -800,14 +800,5 @@ - - - 批量注入 Repository,可以参考代码自行调整 - - - - - - diff --git a/FreeSql.Tests/FreeSql.Tests/SqlServer/Curd/SqlServerSelectWithTempQueryTest.cs b/FreeSql.Tests/FreeSql.Tests/SqlServer/Curd/SqlServerSelectWithTempQueryTest.cs index 08ca5d12..1503fd6d 100644 --- a/FreeSql.Tests/FreeSql.Tests/SqlServer/Curd/SqlServerSelectWithTempQueryTest.cs +++ b/FreeSql.Tests/FreeSql.Tests/SqlServer/Curd/SqlServerSelectWithTempQueryTest.cs @@ -51,6 +51,39 @@ FROM ( INNER JOIN [Instruction] c ON b.[InstructionNo] = c.[InstructionNo] ) b ON a.[SeqNoLog] = b.[SeqNoLog] ) a INNER JOIN [Unit] b ON a.[UnitId] = b.[UnitId] WHERE (a.[RN] < 2)", sql); + + sql = fsql.Select().FromQuery( + fsql.Select() + .InnerJoin((a, b, c) => a.LoadNo == b.LoadNo && a.UnitTransactionType == "TO") + .InnerJoin((a, b, c) => b.InstructionNo == c.InstructionNo) + .WithTempQuery((a, b, c) => new + { + a.LoadNo, + a.SeqNoLog, + c.DeliveryInstractionStatus, + c.UpTime, + RN = SqlExt.RowNumber().Over().PartitionBy(a.UnitId).OrderByDescending(a.SeqNoLog).ToValue() + }), + fsql.Select()) + .InnerJoin((a,b,c) => a.SeqNoLog == b.SeqNoLog) + .InnerJoin((a,b,c) => a.UnitId == c.UnitId) + .Where((a,b,c) => b.RN < 2) + .ToSql((a,b,c) => new MB51_View + { + //CkassIfCation = a.Item1.CkassIfCation, + PGI = b.DeliveryInstractionStatus, + PGITime = b.UpTime, + IsDelayPGI = true, + RunNo = c.RunNo + }); + Assert.Equal(@"SELECT a.[CkassIfCation] as1, b.[DeliveryInstractionStatus] as2, b.[UpTime] as3, 1 as4, c.[RunNo] as5 +FROM [UnitLog] a +INNER JOIN (SELECT a.[LoadNo], a.[SeqNoLog], c.[DeliveryInstractionStatus], c.[UpTime], row_number() over( partition by a.[UnitId] order by a.[SeqNoLog] desc) [RN] + FROM [UnitLog] a + INNER JOIN [LoadPlan] b ON a.[LoadNo] = b.[LoadNo] AND a.[UnitTransactionType] = N'TO' + INNER JOIN [Instruction] c ON b.[InstructionNo] = c.[InstructionNo] ) b ON a.[SeqNoLog] = b.[SeqNoLog] +INNER JOIN [Unit] c ON a.[UnitId] = c.[UnitId] +WHERE (b.[RN] < 2)", sql); } class MB51_View { diff --git a/FreeSql/FreeSql.xml b/FreeSql/FreeSql.xml index 9ee27a8e..89bb8aa1 100644 --- a/FreeSql/FreeSql.xml +++ b/FreeSql/FreeSql.xml @@ -3349,177 +3349,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> - - - - - - - - 可自定义解析表达式 @@ -4510,12 +4339,6 @@ 超时 - - - 获取资源 - - - 使用完毕后,归还资源 @@ -4591,12 +4414,6 @@ 资源对象 - - - 从对象池获取对象成功的时候触发,通过该方法统计或初始化对象 - - 资源对象 - 归还对象给对象池的时候触发 @@ -6038,3 +5855,222 @@ +ystem.Boolean}})"> + + 使用 and 拼接两个 lambda 表达式 + + + true 时生效 + + + + + + 使用 or 拼接两个 lambda 表达式 + + + + + + 使用 or 拼接两个 lambda 表达式 + + + true 时生效 + + + + + + 将 lambda 表达式取反 + + + true 时生效 + + + + + 使用 and 拼接两个 lambda 表达式 + + + + + + 使用 and 拼接两个 lambda 表达式 + + + true 时生效 + + + + + + 使用 or 拼接两个 lambda 表达式 + + + + + + 使用 or 拼接两个 lambda 表达式 + + + true 时生效 + + + + + + 将 lambda 表达式取反 + + + true 时生效 + + + + + 生成类似Mongodb的ObjectId有序、不重复Guid + + + + + + 插入数据 + + + + + + + 插入数据,传入实体 + + + + + + + + 插入数据,传入实体数组 + + + + + + + + 插入数据,传入实体集合 + + + + + + + + 插入数据,传入实体集合 + + + + + + + + 插入或更新数据,此功能依赖数据库特性(低版本可能不支持),参考如下: + MySql 5.6+: on duplicate key update + PostgreSQL 9.4+: on conflict do update + SqlServer 2008+: merge into + Oracle 11+: merge into + Sqlite: replace into + 达梦: merge into + 人大金仓:on conflict do update + 神通:merge into + MsAccess:不支持 + 注意区别:FreeSql.Repository 仓储也有 InsertOrUpdate 方法(不依赖数据库特性) + + + + + + + 修改数据 + + + + + + + 修改数据,传入动态条件,如:主键值 | new[]{主键值1,主键值2} | TEntity1 | new[]{TEntity1,TEntity2} | new{id=1} + + + 主键值、主键值集合、实体、实体集合、匿名对象、匿名对象集合 + + + + + 查询数据 + + + + + + + 查询数据,传入动态条件,如:主键值 | new[]{主键值1,主键值2} | TEntity1 | new[]{TEntity1,TEntity2} | new{id=1} + + + 主键值、主键值集合、实体、实体集合、匿名对象、匿名对象集合 + + + + + 删除数据 + + + + + + + 删除数据,传入动态条件,如:主键值 | new[]{主键值1,主键值2} | TEntity1 | new[]{TEntity1,TEntity2} | new{id=1} + + + 主键值、主键值集合、实体、实体集合、匿名对象、匿名对象集合 + + + + + 开启事务(不支持异步) + v1.5.0 关闭了线程事务超时自动提交的机制 + + 事务体 () => {} + + + + 开启事务(不支持异步) + v1.5.0 关闭了线程事务超时自动提交的机制 + + + 事务体 () => {} + + + + 数据库访问对象 + + + + + 所有拦截方法都在这里 + + + + + CodeFirst 模式开发相关方法 + + + + + DbFirst 模式开发相关方法 + + + + + 全局过滤设置,可默认附加为 Select/Update/Delete 条件 + + + + diff --git a/FreeSql/Interface/Curd/ISelect/ISelect1.cs b/FreeSql/Interface/Curd/ISelect/ISelect1.cs index d4ac0bb3..60adfdb8 100644 --- a/FreeSql/Interface/Curd/ISelect/ISelect1.cs +++ b/FreeSql/Interface/Curd/ISelect/ISelect1.cs @@ -193,6 +193,9 @@ namespace FreeSql ISelect From(Expression, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, ISelectFromExpression>> exp = null) where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : class where T9 : class where T10 : class where T11 : class where T12 : class where T13 : class where T14 : class where T15 : class where T16 : class; ISelect FromQuery(ISelect select2) where T2 : class; + ISelect FromQuery(ISelect select2, ISelect select3) where T2 : class where T3 : class; + ISelect FromQuery(ISelect select2, ISelect select3, ISelect select4) where T2 : class where T3 : class where T4 : class; + ISelect FromQuery(ISelect select2, ISelect select3, ISelect select4, ISelect select5) where T2 : class where T3 : class where T4 : class where T5 : class; ISelect UnionAll(params ISelect[] querys); /// diff --git a/FreeSql/Internal/CommonProvider/SelectProvider/Select0Provider.cs b/FreeSql/Internal/CommonProvider/SelectProvider/Select0Provider.cs index 81dd39d6..a8e21139 100644 --- a/FreeSql/Internal/CommonProvider/SelectProvider/Select0Provider.cs +++ b/FreeSql/Internal/CommonProvider/SelectProvider/Select0Provider.cs @@ -80,6 +80,9 @@ namespace FreeSql.Internal.CommonProvider _diymemexpWithTempQuery = null; } + public abstract string ToSqlBase(string field = null); + public abstract void AsTableBase(Func tableRule); + public static void CopyData(Select0Provider from, Select0Provider to, ReadOnlyCollection lambParms) { if (to == null) return; @@ -221,9 +224,10 @@ namespace FreeSql.Internal.CommonProvider } } - public WithTempQueryParser Append(ISelect select, SelectTableInfo outsideTable) + public WithTempQueryParser Append(Select0Provider select, SelectTableInfo outsideTable) { - if (outsideTable != null && (select as Select0Provider)?._diymemexpWithTempQuery is WithTempQueryParser withTempQuery) + //select is ISelect + if (outsideTable != null && select?._diymemexpWithTempQuery is WithTempQueryParser withTempQuery) { _insideSelectList.Add(withTempQuery._insideSelectList[0]); _outsideTable.Add(outsideTable); @@ -927,6 +931,7 @@ namespace FreeSql.Internal.CommonProvider } return unions; } + public override void AsTableBase(Func tableRule) => AsTable(tableRule); public TSelect AsTable(Func tableRule) { if (_tableRules.Count == 1 && _diymemexpWithTempQuery != null && _diymemexpWithTempQuery is WithTempQueryParser tempQueryParser) @@ -958,6 +963,7 @@ namespace FreeSql.Internal.CommonProvider if (_orm.CodeFirst.IsAutoSyncStructure) _orm.CodeFirst.SyncStructure(entityType); return this as TSelect; } + public override string ToSqlBase(string field = null) => ToSql(field); public abstract string ToSql(string field = null); public TSelect Where(string sql, object parms = null) => this.WhereIf(true, sql, parms); diff --git a/FreeSql/Internal/CommonProvider/SelectProvider/Select1Provider.cs b/FreeSql/Internal/CommonProvider/SelectProvider/Select1Provider.cs index 786d0943..1173fef2 100644 --- a/FreeSql/Internal/CommonProvider/SelectProvider/Select1Provider.cs +++ b/FreeSql/Internal/CommonProvider/SelectProvider/Select1Provider.cs @@ -123,15 +123,14 @@ namespace FreeSql.Internal.CommonProvider public abstract ISelect From(Expression, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, ISelectFromExpression>> exp = null) where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : class where T9 : class where T10 : class where T11 : class where T12 : class where T13 : class where T14 : class where T15 : class; public abstract ISelect From(Expression, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, ISelectFromExpression>> exp = null) where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : class where T9 : class where T10 : class where T11 : class where T12 : class where T13 : class where T14 : class where T15 : class where T16 : class; - public ISelect FromQuery(ISelect select2) where T2 : class { var ret = From(); var retsp = ret as Select0Provider; var rettbs = retsp._tables; if (rettbs[1].Table == null) rettbs[1].Table = TableInfo.GetDefaultTable(typeof(T2)); - (_diymemexpWithTempQuery as WithTempQueryParser)?.Append(select2, rettbs[1]); var select2sp = select2 as Select0Provider; + (_diymemexpWithTempQuery as WithTempQueryParser)?.Append(select2sp, rettbs[1]); string sql2 = null; if (select2sp._diymemexpWithTempQuery == null) { @@ -142,7 +141,7 @@ namespace FreeSql.Internal.CommonProvider else { if (retsp._diymemexpWithTempQuery == null) - retsp._diymemexpWithTempQuery = new WithTempQueryParser(null, null, null, null).Append(select2, rettbs[1]); + retsp._diymemexpWithTempQuery = new WithTempQueryParser(null, null, null, null).Append(select2sp, rettbs[1]); if (select2sp._tableRule != null && select2sp.IsDefaultSqlContent == true) { sql2 = select2sp._tableRule(select2sp._tables[0].Table.Type, null); @@ -172,6 +171,89 @@ namespace FreeSql.Internal.CommonProvider if (retsp._tableRules.Count == 0) ret.WithSql(null, $" \r\n{sql2}"); return ret; } + + public TQuery FromQueryMulti(TQuery ret, Type[] entityTypes, Select0Provider[] querys) + { + var retsp = ret as Select0Provider; + var rettbs = retsp._tables; + var sql2List = new string[rettbs.Count - 1]; + for (var a = 1; a < rettbs.Count; a++) + { + var select2 = querys[a - 1]; + var entityType2 = entityTypes[a - 1]; + var rettb2 = rettbs[a]; + if (rettb2.Table == null) rettb2.Table = TableInfo.GetDefaultTable(entityType2); + (_diymemexpWithTempQuery as WithTempQueryParser)?.Append(select2, rettb2); + string sql2 = null; + if (select2._diymemexpWithTempQuery == null) + { + if (select2._tableRule == null && select2._tables[0].Table.Type == entityType2 && select2.IsDefaultSqlContent == true) + continue; + var selectorParameter = Expression.Parameter(entityType2); + var selector = Expression.Lambda(selectorParameter, selectorParameter); + select2._tables[0].Parameter = selectorParameter; + var af = this.GetExpressionField(selector, FieldAliasOptions.AsProperty); + sql2 = this.ToSql(af.field); + } + else + { + if (retsp._diymemexpWithTempQuery == null) + retsp._diymemexpWithTempQuery = new WithTempQueryParser(null, null, null, null).Append(select2, rettb2); + if (select2._tableRule != null && select2.IsDefaultSqlContent == true) + { + sql2 = select2._tableRule(select2._tables[0].Table.Type, null); + if (sql2.StartsWith("(") && sql2.EndsWith(")")) sql2 = sql2.Substring(1, sql2.Length - 2); + if (sql2.StartsWith(" \r\n")) sql2 = sql2.Substring(3); + } + if (string.IsNullOrWhiteSpace(sql2)) + sql2 = select2.ToSqlBase("*"); + } + sql2List[a - 1] = sql2; + } + if (retsp._tableRules.Count > 0) + { + var tbrules = retsp._tableRules.ToList(); + retsp._tableRules.Clear(); + tbrules.ForEach(tbrule => + { + var tbruler1 = tbrule(typeof(T1), retsp._tables[0].Table.DbName); + if (string.IsNullOrWhiteSpace(tbruler1) == false) + retsp._tableRules.Add((type, old) => + { + if (type == typeof(T1)) return tbruler1; + for (var a = 0; a < entityTypes.Length; a++) + if (entityTypes[a] == type) return string.IsNullOrWhiteSpace(sql2List[a]) ? old : $"( \r\n{sql2List[a]})"; + return old; + }); + }); + } + if (retsp._tableRules.Count == 0) + { + retsp.AsTableBase((type, old) => + { + for (var a = 0; a < entityTypes.Length; a++) + if (entityTypes[a] == type) return string.IsNullOrWhiteSpace(sql2List[a]) ? old : $"({sql2List[a]})"; + return old; + }); + } + return ret; + } + public ISelect FromQuery(ISelect select2, ISelect select3) where T2 : class where T3 : class + { + var ret = From(); + return FromQueryMulti(ret, new[] { typeof(T2), typeof(T3) }, new[] { select2 as Select0Provider, select3 as Select0Provider }); + } + public ISelect FromQuery(ISelect select2, ISelect select3, ISelect select4) where T2 : class where T3 : class where T4 : class + { + var ret = From(); + return FromQueryMulti(ret, new[] { typeof(T2), typeof(T3), typeof(T4) }, new[] { select2 as Select0Provider, select3 as Select0Provider, select4 as Select0Provider }); + } + public ISelect FromQuery(ISelect select2, ISelect select3, ISelect select4, ISelect select5) where T2 : class where T3 : class where T4 : class where T5 : class + { + var ret = From(); + return FromQueryMulti(ret, new[] { typeof(T2), typeof(T3), typeof(T4), typeof(T5) }, new[] { select2 as Select0Provider, select3 as Select0Provider, select4 as Select0Provider, select5 as Select0Provider }); + } + public ISelect UnionAll(params ISelect[] querys) { var sql1 = this.ToSql();