From 96a944c534745cfb9ee32d4ccd84dde8473cad4c Mon Sep 17 00:00:00 2001 From: 28810 <28810@YEXIANGQIN> Date: Sat, 29 Dec 2018 11:53:39 +0800 Subject: [PATCH] in/not in --- Docs/expression.md | 39 ++++- .../MySql/MySqlExpression/OtherTest.cs | 92 +++++++++++ .../MySql/MySqlExpression/StringTest.cs | 8 + .../PostgreSQLExpression/OtherTest.cs | 10 ++ .../PostgreSQLExpression/StringTest.cs | 8 + .../SqlServerExpression/OtherTest.cs | 88 ++++++++++ .../SqlServerExpression/StringTest.cs | 10 +- FreeSql/Internal/CommonExpression.cs | 1 + .../CommonProvider/AdoProvider/AdoProvider.cs | 76 +++++---- .../AdoProvider/AdoProviderAsync.cs | 51 +++--- FreeSql/MySql/MySqlExpression.cs | 156 +++++++++++------- FreeSql/PostgreSQL/PostgreSQLExpression.cs | 150 ++++++++++------- FreeSql/SqlServer/SqlServerExpression.cs | 124 +++++++++----- 13 files changed, 588 insertions(+), 225 deletions(-) create mode 100644 FreeSql.Tests/MySql/MySqlExpression/OtherTest.cs create mode 100644 FreeSql.Tests/SqlServer/SqlServerExpression/OtherTest.cs diff --git a/Docs/expression.md b/Docs/expression.md index ec52ba3b..ebf31343 100644 --- a/Docs/expression.md +++ b/Docs/expression.md @@ -1,21 +1,54 @@ # 表达式函数 | 表达式 | MySql | SqlServer | PostgreSQL | 功能说明 | | - | - | - | - | - | -| a ? b : c | case when a then b else c end | case when a then b else c end | - | a成立时取b值,否则取c值 | +| a ? b : c | case when athen b else c end | case when athen b else c end | case when athen b else c end | a成立时取b值,否则取c值 | | a ?? b | ifnull(a, b) | isnull(a, b) | coalesce(a, b) | 当a为null时,取b值 | | 数字 + 数字 | a + b | a + b | a + b | 数字相加 | -| 数字 + 字符串 | concat(a, b) | cast(a as varchar) + cast(b as varchar) | case(a as varchar) \|\| b | 字符串相加,a或b任意一个为字符串时 | +| 数字 + 字符串 | concat(a, b) | cast(a as varchar) + cast(b as varchar) | case(a as varchar)\|\| b | 字符串相加,a或b任意一个为字符串时 | | a - b | a - b | a - b | a - b | 减 | a * b | a * b | a * b | a * b | 乘 | a / b | a / b | a / b | a / b | 乘 -| a % b | a mod b | a mod b | a mod b | 模 +| a % b | a % b | a % b | a % b | 模 > 等等... +### 数组 +| 表达式 | MySql | SqlServer | PostgreSQL | 功能说明 | +| - | - | - | - | - | +| a.Length | - | - | case when a is null then 0 else array_length(a,1) end | 数组长度 | +| 常量数组.Length | - | - | array_length(array[常量数组元素逗号分割],1) | 数组长度 | +| a.Any() | - | - | case when a is null then 0 else array_length(a,1) end > 0 | 数组是否为空 | +| 常量数组.Contains(b) | b in (常量数组元素逗号分割) | b in (常量数组元素逗号分割) | b in (常量数组元素逗号分割) | IN查询 | +| a.Contains(b) | - | - | a @> array[b] | a数组是否包含b元素 | +| a.Concat(b) | - | - | a \|\| b | 数组相连 | +| a.Count() | - | - | 同 Length | 数组长度 | + +### 字典 Dictionary +| 表达式 | MySql | SqlServer | PostgreSQL | 功能说明 | +| - | - | - | - | - | +| a.Count | - | - | case when a is null then 0 else array_length(akeys(a),1) end | 字典长度 | +| a.Keys | - | - | akeys(a) | 返回字典所有key数组 | +| a.Values | - | - | avals(a) | 返回字典所有value数组 | +| a.Contains(b) | - | - | a @> b | 字典是否包含b +| a.ContainsKey(b) | - | - | a? b | 字典是否包含key +| a.Concat(b) | - | - | a \|\| b | 字典相连 | +| a.Count() | - | - | 同 Count | 字典长度 | + +### JSON JToken/JObject/JArray +| 表达式 | MySql | SqlServer | PostgreSQL | 功能说明 | +| - | - | - | - | - | +| a.Count | - | - | jsonb_array_length(coalesce(a, '[])) | json数组类型的长度 | +| a.Any() | - | - | jsonb_array_length(coalesce(a, '[])) > 0 | json数组类型,是否为空 | +| a.Contains(b) | - | - | coalesce(a, '{}') @> b::jsonb | json中是否包含b | +| a.ContainsKey(b) | - | - | coalesce(a, '{}') ? b | json中是否包含键b | +| a.Concat(b) | - | - | coalesce(a, '{}') || b::jsonb | 连接两个json | +| Parse(a) | - | - | a::jsonb | 转化字符串为json类型 | + ### 字符串对象 | 表达式 | MySql | SqlServer | PostgreSQL | 功能说明 | | - | - | - | - | - | | string.Empty | '' | '' | '' | 空字符串表示 | +| string.IsNullOrEmpty(a) | (a is null or a = '') | (a is null or a = '') | (a is null or a = '') | 空字符串表示 | | a.CompareTo(b) | strcmp(a, b) | - | - | 比较a和b大小 | | a.Contains('b') | a like '%b%' | a like '%b%' | - | a是否包含b | | a.EndsWith('b') | a like '%b' | a like '%b' | - | a尾部是否包含b | diff --git a/FreeSql.Tests/MySql/MySqlExpression/OtherTest.cs b/FreeSql.Tests/MySql/MySqlExpression/OtherTest.cs new file mode 100644 index 00000000..8d2919ff --- /dev/null +++ b/FreeSql.Tests/MySql/MySqlExpression/OtherTest.cs @@ -0,0 +1,92 @@ +using FreeSql.DataAnnotations; +using Newtonsoft.Json.Linq; +using Npgsql; +using Npgsql.LegacyPostgis; +using NpgsqlTypes; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Net.NetworkInformation; +using Xunit; + +namespace FreeSql.Tests.MySqlExpression { + public class OtherTest { + + ISelect select => g.mysql.Select(); + + public OtherTest() { + NpgsqlConnection.GlobalTypeMapper.UseLegacyPostgis(); + } + + + [Fact] + public void Array() { + //in not in + var sql111 = select.Where(a => new[] { 1, 2, 3 }.Contains(a.testFieldInt)).ToList(); + var sql112 = select.Where(a => new[] { 1, 2, 3 }.Contains(a.testFieldInt) == false).ToList(); + var sql113 = select.Where(a => !new[] { 1, 2, 3 }.Contains(a.testFieldInt)).ToList(); + + var inarray = new[] { 1, 2, 3 }; + var sql1111 = select.Where(a => inarray.Contains(a.testFieldInt)).ToList(); + var sql1122 = select.Where(a => inarray.Contains(a.testFieldInt) == false).ToList(); + var sql1133 = select.Where(a => !inarray.Contains(a.testFieldInt)).ToList(); + } + + [Table(Name = "tb_alltype")] + class TableAllType { + [Column(IsIdentity = true, IsPrimary = true)] + public int Id { get; set; } + + public bool testFieldBool { get; set; } + public sbyte testFieldSByte { get; set; } + public short testFieldShort { get; set; } + public int testFieldInt { get; set; } + public long testFieldLong { get; set; } + public byte testFieldByte { get; set; } + public ushort testFieldUShort { get; set; } + public uint testFieldUInt { get; set; } + public ulong testFieldULong { get; set; } + public double testFieldDouble { get; set; } + public float testFieldFloat { get; set; } + public decimal testFieldDecimal { get; set; } + public TimeSpan testFieldTimeSpan { get; set; } + public DateTime testFieldDateTime { get; set; } + public byte[] testFieldBytes { get; set; } + public string testFieldString { get; set; } + public Guid testFieldGuid { get; set; } + + public bool? testFieldBoolNullable { get; set; } + public sbyte? testFieldSByteNullable { get; set; } + public short? testFieldShortNullable { get; set; } + public int? testFieldIntNullable { get; set; } + public long? testFielLongNullable { get; set; } + public byte? testFieldByteNullable { get; set; } + public ushort? testFieldUShortNullable { get; set; } + public uint? testFieldUIntNullable { get; set; } + public ulong? testFieldULongNullable { get; set; } + public double? testFieldDoubleNullable { get; set; } + public float? testFieldFloatNullable { get; set; } + public decimal? testFieldDecimalNullable { get; set; } + public TimeSpan? testFieldTimeSpanNullable { get; set; } + public DateTime? testFieldDateTimeNullable { get; set; } + public Guid? testFieldGuidNullable { get; set; } + + public MygisPoint testFieldPoint { get; set; } + public MygisLineString testFieldLineString { get; set; } + public MygisPolygon testFieldPolygon { get; set; } + public MygisMultiPoint testFieldMultiPoint { get; set; } + public MygisMultiLineString testFieldMultiLineString { get; set; } + public MygisMultiPolygon testFieldMultiPolygon { get; set; } + + public TableAllTypeEnumType1 testFieldEnum1 { get; set; } + public TableAllTypeEnumType1? testFieldEnum1Nullable { get; set; } + public TableAllTypeEnumType2 testFieldEnum2 { get; set; } + public TableAllTypeEnumType2? testFieldEnum2Nullable { get; set; } + } + + public enum TableAllTypeEnumType1 { e1, e2, e3, e5 } + [Flags] public enum TableAllTypeEnumType2 { f1, f2, f3 } + } +} diff --git a/FreeSql.Tests/MySql/MySqlExpression/StringTest.cs b/FreeSql.Tests/MySql/MySqlExpression/StringTest.cs index db5707c5..b0331377 100644 --- a/FreeSql.Tests/MySql/MySqlExpression/StringTest.cs +++ b/FreeSql.Tests/MySql/MySqlExpression/StringTest.cs @@ -671,5 +671,13 @@ namespace FreeSql.Tests.MySqlExpression { //FROM `tb_topic` a, `TestTypeInfo` a__Type //WHERE (strcmp(concat(a.`Title`, 'aaa'), a__Type.`Name`) = 0) } + + [Fact] + public void string_IsNullOrEmpty() { + var data = new List(); + data.Add(select.Where(a => string.IsNullOrEmpty(a.Title)).ToList()); + data.Add(select.Where(a => string.IsNullOrEmpty(a.Title) == false).ToList()); + data.Add(select.Where(a => !string.IsNullOrEmpty(a.Title)).ToList()); + } } } diff --git a/FreeSql.Tests/PostgreSQL/PostgreSQLExpression/OtherTest.cs b/FreeSql.Tests/PostgreSQL/PostgreSQLExpression/OtherTest.cs index 91e392aa..52be9d2f 100644 --- a/FreeSql.Tests/PostgreSQL/PostgreSQLExpression/OtherTest.cs +++ b/FreeSql.Tests/PostgreSQL/PostgreSQLExpression/OtherTest.cs @@ -27,6 +27,16 @@ namespace FreeSql.Tests.PostgreSQLExpression { var sql1 = select.Where(a => a.testFieldIntArray.Contains(1)).ToList(); var sql2 = select.Where(a => a.testFieldIntArray.Contains(1) == false).ToList(); + //in not in + var sql111 = select.Where(a => new[] { 1, 2, 3 }.Contains(a.testFieldInt)).ToList(); + var sql112 = select.Where(a => new[] { 1, 2, 3 }.Contains(a.testFieldInt) == false).ToList(); + var sql113 = select.Where(a => !new[] { 1, 2, 3 }.Contains(a.testFieldInt)).ToList(); + + var inarray = new[] { 1, 2, 3 }; + var sql1111 = select.Where(a => inarray.Contains(a.testFieldInt)).ToSql(); + var sql1122 = select.Where(a => inarray.Contains(a.testFieldInt) == false).ToSql(); + var sql1133 = select.Where(a => !inarray.Contains(a.testFieldInt)).ToSql(); + var sql3 = select.Where(a => a.testFieldIntArray.Any()).ToList(); var sql4 = select.Where(a => a.testFieldIntArray.Any() == false).ToList(); diff --git a/FreeSql.Tests/PostgreSQL/PostgreSQLExpression/StringTest.cs b/FreeSql.Tests/PostgreSQL/PostgreSQLExpression/StringTest.cs index 17686173..e3f53b68 100644 --- a/FreeSql.Tests/PostgreSQL/PostgreSQLExpression/StringTest.cs +++ b/FreeSql.Tests/PostgreSQL/PostgreSQLExpression/StringTest.cs @@ -671,5 +671,13 @@ namespace FreeSql.Tests.PostgreSQLExpression { //FROM `tb_topic` a, `TestTypeInfo` a__Type //WHERE (strcmp(concat(a.`Title`, 'aaa'), a__Type.`Name`) = 0) } + + [Fact] + public void string_IsNullOrEmpty() { + var data = new List(); + data.Add(select.Where(a => string.IsNullOrEmpty(a.Title)).ToList()); + data.Add(select.Where(a => string.IsNullOrEmpty(a.Title) == false).ToList()); + data.Add(select.Where(a => !string.IsNullOrEmpty(a.Title)).ToList()); + } } } diff --git a/FreeSql.Tests/SqlServer/SqlServerExpression/OtherTest.cs b/FreeSql.Tests/SqlServer/SqlServerExpression/OtherTest.cs new file mode 100644 index 00000000..a78123f3 --- /dev/null +++ b/FreeSql.Tests/SqlServer/SqlServerExpression/OtherTest.cs @@ -0,0 +1,88 @@ +using FreeSql.DataAnnotations; +using Newtonsoft.Json.Linq; +using Npgsql; +using Npgsql.LegacyPostgis; +using NpgsqlTypes; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Net.NetworkInformation; +using Xunit; + +namespace FreeSql.Tests.SqlServerExpression { + public class OtherTest { + + ISelect select => g.sqlserver.Select(); + + public OtherTest() { + NpgsqlConnection.GlobalTypeMapper.UseLegacyPostgis(); + } + + + [Fact] + public void Array() { + //in not in + var sql111 = select.Where(a => new[] { 1, 2, 3 }.Contains(a.testFieldInt)).ToList(); + //var sql112 = select.Where(a => new[] { 1, 2, 3 }.Contains(a.testFieldInt) == false).ToList(); + var sql113 = select.Where(a => !new[] { 1, 2, 3 }.Contains(a.testFieldInt)).ToList(); + + var inarray = new[] { 1, 2, 3 }; + var sql1111 = select.Where(a => inarray.Contains(a.testFieldInt)).ToList(); + //var sql1122 = select.Where(a => inarray.Contains(a.testFieldInt) == false).ToList(); + var sql1133 = select.Where(a => !inarray.Contains(a.testFieldInt)).ToList(); + } + + [Table(Name = "tb_alltype")] + class TableAllType { + [Column(IsIdentity = true, IsPrimary = true)] + public int Id { get; set; } + + [Column(Name = "testFieldBool1111")] + public bool testFieldBool { get; set; } + public sbyte testFieldSByte { get; set; } + public short testFieldShort { get; set; } + public int testFieldInt { get; set; } + public long testFieldLong { get; set; } + public byte testFieldByte { get; set; } + public ushort testFieldUShort { get; set; } + public uint testFieldUInt { get; set; } + public ulong testFieldULong { get; set; } + public double testFieldDouble { get; set; } + public float testFieldFloat { get; set; } + public decimal testFieldDecimal { get; set; } + public TimeSpan testFieldTimeSpan { get; set; } + public DateTime testFieldDateTime { get; set; } + public DateTimeOffset testFieldDateTimeOffset { get; set; } + public byte[] testFieldBytes { get; set; } + public string testFieldString { get; set; } + public Guid testFieldGuid { get; set; } + + public bool? testFieldBoolNullable { get; set; } + public sbyte? testFieldSByteNullable { get; set; } + public short? testFieldShortNullable { get; set; } + public int? testFieldIntNullable { get; set; } + public long? testFielLongNullable { get; set; } + public byte? testFieldByteNullable { get; set; } + public ushort? testFieldUShortNullable { get; set; } + public uint? testFieldUIntNullable { get; set; } + public ulong? testFieldULongNullable { get; set; } + public double? testFieldDoubleNullable { get; set; } + public float? testFieldFloatNullable { get; set; } + public decimal? testFieldDecimalNullable { get; set; } + public TimeSpan? testFieldTimeSpanNullable { get; set; } + public DateTime? testFieldDateTimeNullable { get; set; } + public DateTimeOffset? testFieldDateTimeNullableOffset { get; set; } + public Guid? testFieldGuidNullable { get; set; } + + public TableAllTypeEnumType1 testFieldEnum1 { get; set; } + public TableAllTypeEnumType1? testFieldEnum1Nullable { get; set; } + public TableAllTypeEnumType2 testFieldEnum2 { get; set; } + public TableAllTypeEnumType2? testFieldEnum2Nullable { get; set; } + } + + public enum TableAllTypeEnumType1 { e1, e2, e3, e5 } + [Flags] public enum TableAllTypeEnumType2 { f1, f2, f3 } + } +} diff --git a/FreeSql.Tests/SqlServer/SqlServerExpression/StringTest.cs b/FreeSql.Tests/SqlServer/SqlServerExpression/StringTest.cs index 1b6324eb..f7a5a1fc 100644 --- a/FreeSql.Tests/SqlServer/SqlServerExpression/StringTest.cs +++ b/FreeSql.Tests/SqlServer/SqlServerExpression/StringTest.cs @@ -227,11 +227,19 @@ namespace FreeSql.Tests.SqlServerExpression { //data.Add(select.Where(a => a.Title.CompareTo(a.Title) > 0).ToList()); //data.Add(select.Where(a => a.Title.CompareTo(a.Title + 1) == 0).ToList()); //data.Add(select.Where(a => a.Title.CompareTo(a.Title + a.Type.Name) == 0).ToList()); - + //data.Add(select.Where(a => (a.Title + "aaa").CompareTo("aaa") == 0).ToList()); //data.Add(select.Where(a => (a.Title + "aaa").CompareTo(a.Title) > 0).ToList()); //data.Add(select.Where(a => (a.Title + "aaa").CompareTo(a.Title + 1) == 0).ToList()); //data.Add(select.Where(a => (a.Title + "aaa").CompareTo(a.Type.Name) == 0).ToList()); } + + [Fact] + public void string_IsNullOrEmpty() { + var data = new List(); + data.Add(select.Where(a => string.IsNullOrEmpty(a.Title)).ToList()); + //data.Add(select.Where(a => string.IsNullOrEmpty(a.Title) == false).ToList()); + data.Add(select.Where(a => !string.IsNullOrEmpty(a.Title)).ToList()); + } } } diff --git a/FreeSql/Internal/CommonExpression.cs b/FreeSql/Internal/CommonExpression.cs index e7c24a54..f24d78fd 100644 --- a/FreeSql/Internal/CommonExpression.cs +++ b/FreeSql/Internal/CommonExpression.cs @@ -194,6 +194,7 @@ namespace FreeSql.Internal { internal string ExpressionLambdaToSql(Expression exp, List _tables, List _selectColumnMap, Func getSelectGroupingMapString, SelectTableInfoType tbtype, bool isQuoteName) { switch (exp.NodeType) { + case ExpressionType.Not: return $"not({ExpressionLambdaToSql((exp as UnaryExpression)?.Operand, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; case ExpressionType.Quote: return ExpressionLambdaToSql((exp as UnaryExpression)?.Operand, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); case ExpressionType.Lambda: return ExpressionLambdaToSql((exp as LambdaExpression)?.Body, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); case ExpressionType.Convert: return ExpressionLambdaToSql((exp as UnaryExpression)?.Operand, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); diff --git a/FreeSql/Internal/CommonProvider/AdoProvider/AdoProvider.cs b/FreeSql/Internal/CommonProvider/AdoProvider/AdoProvider.cs index 227547cc..39fe7a17 100644 --- a/FreeSql/Internal/CommonProvider/AdoProvider/AdoProvider.cs +++ b/FreeSql/Internal/CommonProvider/AdoProvider/AdoProvider.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Data; using System.Data.Common; using System.Linq; +using System.Text; namespace FreeSql.Internal.CommonProvider { abstract partial class AdoProvider : IAdo { @@ -30,28 +31,31 @@ namespace FreeSql.Internal.CommonProvider { this._log = log; } - void LoggerException(ObjectPool pool, DbCommand cmd, Exception e, DateTime dt, string logtxt, bool isThrowException = true) { + void LoggerException(ObjectPool pool, DbCommand cmd, Exception e, DateTime dt, StringBuilder logtxt, bool isThrowException = true) { if (IsTracePerformance) { TimeSpan ts = DateTime.Now.Subtract(dt); if (e == null && ts.TotalMilliseconds > 100) - _log.LogWarning(logtxt = $"{pool.Policy.Name}执行SQL语句耗时过长{ts.TotalMilliseconds}ms\r\n{cmd.CommandText}\r\n{logtxt}"); + _log.LogWarning(logtxt.Insert(0, $"{pool.Policy.Name}(执行SQL)语句耗时过长{ts.TotalMilliseconds}ms\r\n{cmd.CommandText}\r\n").ToString()); + else + logtxt.Insert(0, $"{pool.Policy.Name}(执行SQL)耗时{ts.TotalMilliseconds}ms\r\n{cmd.CommandText}\r\n").ToString(); } if (e == null) { - AopCommandExecuted?.Invoke(cmd, logtxt); + AopCommandExecuted?.Invoke(cmd, logtxt.ToString()); return; } - string log = $"{pool.Policy.Name}数据库出错(执行SQL)〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓\r\n{cmd.CommandText}\r\n"; + StringBuilder log = new StringBuilder(); + log.Append(pool.Policy.Name).Append("数据库出错(执行SQL)〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓\r\n").Append(cmd.CommandText).Append("\r\n"); foreach (DbParameter parm in cmd.Parameters) - log += parm.ParameterName.PadRight(20, ' ') + " = " + ((parm.Value ?? DBNull.Value) == DBNull.Value ? "NULL" : parm.Value) + "\r\n"; + log.Append(parm.ParameterName.PadRight(20, ' ')).Append(" = ").Append((parm.Value ?? DBNull.Value) == DBNull.Value ? "NULL" : parm.Value).Append("\r\n"); - log += e.Message; - _log.LogError(log); + log.Append(e.Message); + _log.LogError(log.ToString()); RollbackTransaction(); - AopCommandExecuted?.Invoke(cmd, log); + AopCommandExecuted?.Invoke(cmd, log.ToString()); cmd.Parameters.Clear(); if (isThrowException) throw e; @@ -77,11 +81,11 @@ namespace FreeSql.Internal.CommonProvider { } public void ExecuteReader(Action readerHander, string sql, object parms = null) => ExecuteReader(readerHander, CommandType.Text, sql, GetDbParamtersByObject(sql, parms)); public void ExecuteReader(Action readerHander, CommandType cmdType, string cmdText, params DbParameter[] cmdParms) { - DateTime dt = DateTime.Now; - string logtxt = ""; - DateTime logtxt_dt = DateTime.Now; + var dt = DateTime.Now; + var logtxt = new StringBuilder(); + var logtxt_dt = DateTime.Now; var pool = this.MasterPool; - bool isSlave = false; + var isSlave = false; //读写分离规则 if (this.SlavePools.Any() && cmdText.StartsWith("SELECT ", StringComparison.CurrentCultureIgnoreCase)) { @@ -99,8 +103,8 @@ namespace FreeSql.Internal.CommonProvider { } Object conn = null; - var pc = PrepareCommand(cmdType, cmdText, cmdParms, ref logtxt); - if (IsTracePerformance) logtxt += $"PrepareCommand: {DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds}ms Total: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms\r\n"; + var pc = PrepareCommand(cmdType, cmdText, cmdParms, logtxt); + if (IsTracePerformance) logtxt.Append("PrepareCommand: ").Append(DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds).Append("ms Total: ").Append(DateTime.Now.Subtract(dt).TotalMilliseconds).Append("ms\r\n"); Exception ex = null; try { if (IsTracePerformance) logtxt_dt = DateTime.Now; @@ -117,7 +121,7 @@ namespace FreeSql.Internal.CommonProvider { if (conn != null) { if (IsTracePerformance) logtxt_dt = DateTime.Now; ReturnConnection(pool, conn, ex); //pool.Return(conn, ex); - if (IsTracePerformance) logtxt += $"ReleaseConnection: {DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds}ms Total: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms"; + if (IsTracePerformance) logtxt.Append("ReleaseConnection: ").Append(DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds).Append("ms Total: ").Append(DateTime.Now.Subtract(dt).TotalMilliseconds).Append("ms"); } LoggerException(pool, pc.cmd, new Exception($"连接失败,准备切换其他可用服务器"), dt, logtxt, false); pc.cmd.Parameters.Clear(); @@ -129,15 +133,15 @@ namespace FreeSql.Internal.CommonProvider { if (pc.cmd.Connection == null) pc.cmd.Connection = (conn = pool.Get()).Value; } if (IsTracePerformance) { - logtxt += $"Open: {DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds}ms Total: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms\r\n"; + logtxt.Append("Open: ").Append(DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds).Append("ms Total: ").Append(DateTime.Now.Subtract(dt).TotalMilliseconds).Append("ms\r\n"); logtxt_dt = DateTime.Now; } using (var dr = pc.cmd.ExecuteReader()) { - if (IsTracePerformance) logtxt += $"ExecuteReader: {DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds}ms Total: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms\r\n"; + if (IsTracePerformance) logtxt.Append("ExecuteReader: ").Append(DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds).Append("ms Total: ").Append(DateTime.Now.Subtract(dt).TotalMilliseconds).Append("ms\r\n"); while (true) { if (IsTracePerformance) logtxt_dt = DateTime.Now; bool isread = dr.Read(); - if (IsTracePerformance) logtxt += $" dr.Read: {DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds}ms Total: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms\r\n"; + if (IsTracePerformance) logtxt.Append(" dr.Read: ").Append(DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds).Append("ms Total: ").Append(DateTime.Now.Subtract(dt).TotalMilliseconds).Append("ms\r\n"); if (isread == false) break; if (readerHander != null) { @@ -146,17 +150,17 @@ namespace FreeSql.Internal.CommonProvider { logtxt_dt = DateTime.Now; values = new object[dr.FieldCount]; dr.GetValues(values); - logtxt += $" dr.GetValues: {DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds}ms Total: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms\r\n"; + logtxt.Append(" dr.GetValues: ").Append(DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds).Append("ms Total: ").Append(DateTime.Now.Subtract(dt).TotalMilliseconds).Append("ms\r\n"); logtxt_dt = DateTime.Now; } readerHander(dr); - if (IsTracePerformance) logtxt += $" readerHander: {DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds}ms Total: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms ({string.Join(",", values)})\r\n"; + if (IsTracePerformance) logtxt.Append(" readerHander: ").Append(DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds).Append("ms Total: ").Append(DateTime.Now.Subtract(dt).TotalMilliseconds).Append("ms (").Append(string.Join(", ", values)).Append(")\r\n"); } } if (IsTracePerformance) logtxt_dt = DateTime.Now; dr.Close(); } - if (IsTracePerformance) logtxt += $"ExecuteReader_dispose: {DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds}ms Total: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms\r\n"; + if (IsTracePerformance) logtxt.Append("ExecuteReader_dispose: ").Append(DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds).Append("ms Total: ").Append(DateTime.Now.Subtract(dt).TotalMilliseconds).Append("ms\r\n"); } catch (Exception ex2) { ex = ex2; } @@ -164,7 +168,7 @@ namespace FreeSql.Internal.CommonProvider { if (conn != null) { if (IsTracePerformance) logtxt_dt = DateTime.Now; ReturnConnection(pool, conn, ex); //pool.Return(conn, ex); - if (IsTracePerformance) logtxt += $"ReleaseConnection: {DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds}ms Total: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms"; + if (IsTracePerformance) logtxt.Append("ReleaseConnection: ").Append(DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds).Append("ms Total: ").Append(DateTime.Now.Subtract(dt).TotalMilliseconds).Append("ms"); } LoggerException(pool, pc.cmd, ex, dt, logtxt); pc.cmd.Parameters.Clear(); @@ -193,11 +197,11 @@ namespace FreeSql.Internal.CommonProvider { } public int ExecuteNonQuery(string sql, object parms = null) => ExecuteNonQuery(CommandType.Text, sql, GetDbParamtersByObject(sql, parms)); public int ExecuteNonQuery(CommandType cmdType, string cmdText, params DbParameter[] cmdParms) { - DateTime dt = DateTime.Now; - string logtxt = ""; - DateTime logtxt_dt = DateTime.Now; + var dt = DateTime.Now; + var logtxt = new StringBuilder(); + var logtxt_dt = DateTime.Now; Object conn = null; - var pc = PrepareCommand(cmdType, cmdText, cmdParms, ref logtxt); + var pc = PrepareCommand(cmdType, cmdText, cmdParms, logtxt); int val = 0; Exception ex = null; try { @@ -210,7 +214,7 @@ namespace FreeSql.Internal.CommonProvider { if (conn != null) { if (IsTracePerformance) logtxt_dt = DateTime.Now; ReturnConnection(MasterPool, conn, ex); //this.MasterPool.Return(conn, ex); - if (IsTracePerformance) logtxt += $"ReleaseConnection: {DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds}ms Total: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms"; + if (IsTracePerformance) logtxt.Append("ReleaseConnection: ").Append(DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds).Append("ms Total: ").Append(DateTime.Now.Subtract(dt).TotalMilliseconds).Append("ms"); } LoggerException(this.MasterPool, pc.cmd, ex, dt, logtxt); pc.cmd.Parameters.Clear(); @@ -218,11 +222,11 @@ namespace FreeSql.Internal.CommonProvider { } public object ExecuteScalar(string sql, object parms = null) => ExecuteScalar(CommandType.Text, sql, GetDbParamtersByObject(sql, parms)); public object ExecuteScalar(CommandType cmdType, string cmdText, params DbParameter[] cmdParms) { - DateTime dt = DateTime.Now; - string logtxt = ""; - DateTime logtxt_dt = DateTime.Now; + var dt = DateTime.Now; + var logtxt = new StringBuilder(); + var logtxt_dt = DateTime.Now; Object conn = null; - var pc = PrepareCommand(cmdType, cmdText, cmdParms, ref logtxt); + var pc = PrepareCommand(cmdType, cmdText, cmdParms, logtxt); object val = null; Exception ex = null; try { @@ -235,14 +239,14 @@ namespace FreeSql.Internal.CommonProvider { if (conn != null) { if (IsTracePerformance) logtxt_dt = DateTime.Now; ReturnConnection(MasterPool, conn, ex); //this.MasterPool.Return(conn, ex); - if (IsTracePerformance) logtxt += $"ReleaseConnection: {DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds}ms Total: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms"; + if (IsTracePerformance) logtxt.Append("ReleaseConnection: ").Append(DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds).Append("ms Total: ").Append(DateTime.Now.Subtract(dt).TotalMilliseconds).Append("ms"); } LoggerException(this.MasterPool, pc.cmd, ex, dt, logtxt); pc.cmd.Parameters.Clear(); return val; } - private (DbTransaction tran, DbCommand cmd) PrepareCommand(CommandType cmdType, string cmdText, DbParameter[] cmdParms, ref string logtxt) { + private (DbTransaction tran, DbCommand cmd) PrepareCommand(CommandType cmdType, string cmdText, DbParameter[] cmdParms, StringBuilder logtxt) { var dt = DateTime.Now; DbCommand cmd = CreateCommand(); cmd.CommandType = cmdType; @@ -257,18 +261,18 @@ namespace FreeSql.Internal.CommonProvider { } var tran = TransactionCurrentThread; - if (IsTracePerformance) logtxt += $" PrepareCommand_part1: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms cmdParms: {cmd.Parameters.Count}\r\n"; + if (IsTracePerformance) logtxt.Append(" PrepareCommand_part1: ").Append(DateTime.Now.Subtract(dt).TotalMilliseconds).Append("ms cmdParms: ").Append(cmd.Parameters.Count).Append("\r\n"); if (tran != null) { if (IsTracePerformance) dt = DateTime.Now; cmd.Connection = tran.Connection; cmd.Transaction = tran; - if (IsTracePerformance) logtxt += $" PrepareCommand_tran!=null: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms\r\n"; + if (IsTracePerformance) logtxt.Append(" PrepareCommand_tran!=null: ").Append(DateTime.Now.Subtract(dt).TotalMilliseconds).Append("ms\r\n"); } if (IsTracePerformance) dt = DateTime.Now; AutoCommitTransaction(); - if (IsTracePerformance) logtxt += $" AutoCommitTransaction: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms\r\n"; + if (IsTracePerformance) logtxt.Append(" AutoCommitTransaction: ").Append(DateTime.Now.Subtract(dt).TotalMilliseconds).Append("ms\r\n"); AopCommandExecuting?.Invoke(cmd); return (tran, cmd); diff --git a/FreeSql/Internal/CommonProvider/AdoProvider/AdoProviderAsync.cs b/FreeSql/Internal/CommonProvider/AdoProvider/AdoProviderAsync.cs index 2cf1c1d0..965ff392 100644 --- a/FreeSql/Internal/CommonProvider/AdoProvider/AdoProviderAsync.cs +++ b/FreeSql/Internal/CommonProvider/AdoProvider/AdoProviderAsync.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Data; using System.Data.Common; using System.Linq; +using System.Text; using System.Threading.Tasks; namespace FreeSql.Internal.CommonProvider { @@ -28,11 +29,11 @@ namespace FreeSql.Internal.CommonProvider { } public Task ExecuteReaderAsync(Func readerHander, string sql, object parms = null) => ExecuteReaderAsync(readerHander, CommandType.Text, sql, GetDbParamtersByObject(sql, parms)); async public Task ExecuteReaderAsync(Func readerHander, CommandType cmdType, string cmdText, params DbParameter[] cmdParms) { - DateTime dt = DateTime.Now; - string logtxt = ""; - DateTime logtxt_dt = DateTime.Now; + var dt = DateTime.Now; + var logtxt = new StringBuilder(); + var logtxt_dt = DateTime.Now; var pool = this.MasterPool; - bool isSlave = false; + var isSlave = false; //读写分离规则 if (this.SlavePools.Any() && cmdText.StartsWith("SELECT ", StringComparison.CurrentCultureIgnoreCase)) { @@ -50,8 +51,8 @@ namespace FreeSql.Internal.CommonProvider { } Object conn = null; - var cmd = PrepareCommandAsync(cmdType, cmdText, cmdParms, ref logtxt); - if (IsTracePerformance) logtxt += $"PrepareCommand: {DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds}ms Total: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms\r\n"; + var cmd = PrepareCommandAsync(cmdType, cmdText, cmdParms, logtxt); + if (IsTracePerformance) logtxt.Append("PrepareCommandAsync: ").Append(DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds).Append("ms Total: ").Append(DateTime.Now.Subtract(dt).TotalMilliseconds).Append("ms\r\n"); Exception ex = null; try { if (IsTracePerformance) logtxt_dt = DateTime.Now; @@ -68,7 +69,7 @@ namespace FreeSql.Internal.CommonProvider { if (conn != null) { if (IsTracePerformance) logtxt_dt = DateTime.Now; ReturnConnection(pool, conn, ex); //pool.Return(conn, ex); - if (IsTracePerformance) logtxt += $"ReleaseConnection: {DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds}ms Total: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms"; + if (IsTracePerformance) logtxt.Append("ReleaseConnection: ").Append(DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds).Append("ms Total: ").Append(DateTime.Now.Subtract(dt).TotalMilliseconds).Append("ms"); } LoggerException(pool, cmd, new Exception($"连接失败,准备切换其他可用服务器"), dt, logtxt, false); cmd.Parameters.Clear(); @@ -80,15 +81,15 @@ namespace FreeSql.Internal.CommonProvider { if (cmd.Connection == null) cmd.Connection = (conn = await pool.GetAsync()).Value; } if (IsTracePerformance) { - logtxt += $"Open: {DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds}ms Total: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms\r\n"; + logtxt.Append("OpenAsync: ").Append(DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds).Append("ms Total: ").Append(DateTime.Now.Subtract(dt).TotalMilliseconds).Append("ms\r\n"); logtxt_dt = DateTime.Now; } using (var dr = await cmd.ExecuteReaderAsync()) { - if (IsTracePerformance) logtxt += $"ExecuteReader: {DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds}ms Total: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms\r\n"; + if (IsTracePerformance) logtxt.Append("ExecuteReaderAsync: ").Append(DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds).Append("ms Total: ").Append(DateTime.Now.Subtract(dt).TotalMilliseconds).Append("ms\r\n"); while (true) { if (IsTracePerformance) logtxt_dt = DateTime.Now; bool isread = await dr.ReadAsync(); - if (IsTracePerformance) logtxt += $" dr.Read: {DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds}ms Total: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms\r\n"; + if (IsTracePerformance) logtxt.Append(" dr.ReadAsync: ").Append(DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds).Append("ms Total: ").Append(DateTime.Now.Subtract(dt).TotalMilliseconds).Append("ms\r\n"); if (isread == false) break; if (readerHander != null) { @@ -97,17 +98,17 @@ namespace FreeSql.Internal.CommonProvider { logtxt_dt = DateTime.Now; values = new object[dr.FieldCount]; for (int a = 0; a < values.Length; a++) if (!await dr.IsDBNullAsync(a)) values[a] = await dr.GetFieldValueAsync(a); - logtxt += $" dr.GetValues: {DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds}ms Total: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms\r\n"; + logtxt.Append(" dr.GetValues: ").Append(DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds).Append("ms Total: ").Append(DateTime.Now.Subtract(dt).TotalMilliseconds).Append("ms\r\n"); logtxt_dt = DateTime.Now; } await readerHander(dr); - if (IsTracePerformance) logtxt += $" readerHander: {DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds}ms Total: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms ({string.Join(",", values)})\r\n"; + if (IsTracePerformance) logtxt.Append(" readerHanderAsync: ").Append(DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds).Append("ms Total: ").Append(DateTime.Now.Subtract(dt).TotalMilliseconds).Append("ms (").Append(string.Join(", ", values)).Append(")\r\n"); } } if (IsTracePerformance) logtxt_dt = DateTime.Now; dr.Close(); } - if (IsTracePerformance) logtxt += $"ExecuteReader_dispose: {DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds}ms Total: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms\r\n"; + if (IsTracePerformance) logtxt.Append("ExecuteReaderAsync_dispose: ").Append(DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds).Append("ms Total: ").Append(DateTime.Now.Subtract(dt).TotalMilliseconds).Append("ms\r\n"); } catch (Exception ex2) { ex = ex2; } @@ -115,7 +116,7 @@ namespace FreeSql.Internal.CommonProvider { if (conn != null) { if (IsTracePerformance) logtxt_dt = DateTime.Now; ReturnConnection(pool, conn, ex); //pool.Return(conn, ex); - if (IsTracePerformance) logtxt += $"ReleaseConnection: {DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds}ms Total: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms"; + if (IsTracePerformance) logtxt.Append("ReleaseConnection: ").Append(DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds).Append("ms Total: ").Append(DateTime.Now.Subtract(dt).TotalMilliseconds).Append("ms"); } LoggerException(pool, cmd, ex, dt, logtxt); cmd.Parameters.Clear(); @@ -144,11 +145,11 @@ namespace FreeSql.Internal.CommonProvider { } public Task ExecuteNonQueryAsync(string sql, object parms = null) => ExecuteNonQueryAsync(CommandType.Text, sql, GetDbParamtersByObject(sql, parms)); async public Task ExecuteNonQueryAsync(CommandType cmdType, string cmdText, params DbParameter[] cmdParms) { - DateTime dt = DateTime.Now; - string logtxt = ""; - Object conn = null; - var cmd = PrepareCommandAsync(cmdType, cmdText, cmdParms, ref logtxt); + var dt = DateTime.Now; + var logtxt = new StringBuilder(); var logtxt_dt = DateTime.Now; + Object conn = null; + var cmd = PrepareCommandAsync(cmdType, cmdText, cmdParms, logtxt); int val = 0; Exception ex = null; try { @@ -161,7 +162,7 @@ namespace FreeSql.Internal.CommonProvider { if (conn != null) { if (IsTracePerformance) logtxt_dt = DateTime.Now; ReturnConnection(MasterPool, conn, ex); //this.MasterPool.Return(conn, ex); - if (IsTracePerformance) logtxt += $"ReleaseConnection: {DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds}ms Total: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms"; + if (IsTracePerformance) logtxt.Append("ReleaseConnection: ").Append(DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds).Append("ms Total: ").Append(DateTime.Now.Subtract(dt).TotalMilliseconds).Append("ms"); } LoggerException(this.MasterPool, cmd, ex, dt, logtxt); cmd.Parameters.Clear(); @@ -170,10 +171,10 @@ namespace FreeSql.Internal.CommonProvider { public Task ExecuteScalarAsync(string sql, object parms = null) => ExecuteScalarAsync(CommandType.Text, sql, GetDbParamtersByObject(sql, parms)); async public Task ExecuteScalarAsync(CommandType cmdType, string cmdText, params DbParameter[] cmdParms) { var dt = DateTime.Now; - var logtxt = ""; - Object conn = null; - var cmd = PrepareCommandAsync(cmdType, cmdText, cmdParms, ref logtxt); + var logtxt = new StringBuilder(); var logtxt_dt = DateTime.Now; + Object conn = null; + var cmd = PrepareCommandAsync(cmdType, cmdText, cmdParms, logtxt); object val = null; Exception ex = null; try { @@ -186,14 +187,14 @@ namespace FreeSql.Internal.CommonProvider { if (conn != null) { if (IsTracePerformance) logtxt_dt = DateTime.Now; ReturnConnection(MasterPool, conn, ex); //this.MasterPool.Return(conn, ex); - if (IsTracePerformance) logtxt += $"ReleaseConnection: {DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds}ms Total: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms"; + if (IsTracePerformance) logtxt.Append("ReleaseConnection: ").Append(DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds).Append("ms Total: ").Append(DateTime.Now.Subtract(dt).TotalMilliseconds).Append("ms"); } LoggerException(this.MasterPool, cmd, ex, dt, logtxt); cmd.Parameters.Clear(); return val; } - private DbCommand PrepareCommandAsync(CommandType cmdType, string cmdText, DbParameter[] cmdParms, ref string logtxt) { + private DbCommand PrepareCommandAsync(CommandType cmdType, string cmdText, DbParameter[] cmdParms, StringBuilder logtxt) { DateTime dt = DateTime.Now; DbCommand cmd = CreateCommand(); cmd.CommandType = cmdType; @@ -207,7 +208,7 @@ namespace FreeSql.Internal.CommonProvider { } } - if (IsTracePerformance) logtxt += $" PrepareCommand_tran==null: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms cmdParms: {cmd.Parameters.Count}\r\n"; + if (IsTracePerformance) logtxt.Append(" PrepareCommand_tran==null: ").Append(DateTime.Now.Subtract(dt).TotalMilliseconds).Append("ms cmdParms: ").Append(cmd.Parameters.Count).Append("\r\n"); AopCommandExecuting?.Invoke(cmd); return cmd; diff --git a/FreeSql/MySql/MySqlExpression.cs b/FreeSql/MySql/MySqlExpression.cs index f26d57da0..2f770e97 100644 --- a/FreeSql/MySql/MySqlExpression.cs +++ b/FreeSql/MySql/MySqlExpression.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; +using System.Text; namespace FreeSql.MySql { class MySqlExpression : CommonExpression { @@ -11,6 +12,41 @@ namespace FreeSql.MySql { public MySqlExpression(CommonUtils common) : base(common) { } internal override string ExpressionLambdaToSqlOther(Expression exp, List _tables, List _selectColumnMap, Func getSelectGroupingMapString, SelectTableInfoType tbtype, bool isQuoteName) { + switch (exp.NodeType) { + case ExpressionType.Call: + var callExp = exp as MethodCallExpression; + var objExp = callExp.Object; + var objType = objExp?.Type; + if (objType?.FullName == "System.Byte[]") return null; + + var argIndex = 0; + if (objType == null && callExp.Method.DeclaringType.FullName == typeof(Enumerable).FullName) { + objExp = callExp.Arguments.FirstOrDefault(); + objType = objExp?.Type; + argIndex++; + } + if (objType == null) objType = callExp.Method.DeclaringType; + if (objType != null) { + var left = objExp == null ? null : ExpressionLambdaToSql(objExp, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); + if (objType.IsArray == true) { + switch (callExp.Method.Name) { + case "Contains": + //判断 in + return $"({ExpressionLambdaToSql(callExp.Arguments[argIndex], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)}) in {left}"; + } + } + } + break; + case ExpressionType.NewArrayInit: + var arrExp = exp as NewArrayExpression; + var arrSb = new StringBuilder(); + arrSb.Append("("); + for (var a = 0; a < arrExp.Expressions.Count; a++) { + if (a > 0) arrSb.Append(","); + arrSb.Append(ExpressionLambdaToSql(arrExp.Expressions[a], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)); + } + return arrSb.Append(")").ToString(); + } return null; } @@ -82,64 +118,72 @@ namespace FreeSql.MySql { } internal override string ExpressionLambdaToSqlCallString(MethodCallExpression exp, List _tables, List _selectColumnMap, Func getSelectGroupingMapString, SelectTableInfoType tbtype, bool isQuoteName) { - var left = ExpressionLambdaToSql(exp.Object, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); - switch (exp.Method.Name) { - case "StartsWith": - case "EndsWith": - case "Contains": - var args0Value = ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); - if (args0Value == "NULL") return $"({left}) IS NULL"; - if (exp.Method.Name == "StartsWith") return $"({left}) LIKE {(args0Value.EndsWith("'") ? args0Value.Insert(args0Value.Length - 1, "%") : $"concat({args0Value}, '%')")}"; - if (exp.Method.Name == "EndsWith") return $"({left}) LIKE {(args0Value.StartsWith("'") ? args0Value.Insert(1, "%") : $"concat('%', {args0Value})")}"; - if (args0Value.StartsWith("'") && args0Value.EndsWith("'")) return $"({left}) LIKE {args0Value.Insert(1, "%").Insert(args0Value.Length, "%")}"; - return $"({left}) LIKE concat('%', {args0Value}, '%')"; - case "ToLower": return $"lower({left})"; - case "ToUpper": return $"upper({left})"; - case "Substring": - var substrArgs1 = ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); - if (long.TryParse(substrArgs1, out var testtrylng1)) substrArgs1 = (testtrylng1 + 1).ToString(); - else substrArgs1 += "+1"; - if (exp.Arguments.Count == 1) return $"substr({left}, {substrArgs1})"; - return $"substr({left}, {substrArgs1}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; - case "IndexOf": - var indexOfFindStr = ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); - if (exp.Arguments.Count > 1 && exp.Arguments[1].Type.FullName == "System.Int32") { - var locateArgs1 = ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); - if (long.TryParse(locateArgs1, out var testtrylng2)) locateArgs1 = (testtrylng2 + 1).ToString(); - else locateArgs1 += "+1"; - return $"(locate({left}, {indexOfFindStr}, {locateArgs1})-1)"; - } - return $"(locate({left}, {indexOfFindStr})-1)"; - case "PadLeft": - if (exp.Arguments.Count == 1) return $"lpad({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; - return $"lpad({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; - case "PadRight": - if (exp.Arguments.Count == 1) return $"rpad({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; - return $"rpad({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; - case "Trim": - case "TrimStart": - case "TrimEnd": - if (exp.Arguments.Count == 0) { - if (exp.Method.Name == "Trim") return $"trim({left})"; - if (exp.Method.Name == "TrimStart") return $"ltrim({left})"; - if (exp.Method.Name == "TrimEnd") return $"rtrim({left})"; - } - foreach (var argsTrim02 in exp.Arguments) { - var argsTrim01s = new[] { argsTrim02 }; - if (argsTrim02.NodeType == ExpressionType.NewArrayInit) { - var arritem = argsTrim02 as NewArrayExpression; - argsTrim01s = arritem.Expressions.ToArray(); + if (exp.Object == null) { + switch (exp.Method.Name) { + case "IsNullOrEmpty": + var arg1 = ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); + return $"({arg1} is null or {arg1} = '')"; + } + } else { + var left = ExpressionLambdaToSql(exp.Object, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); + switch (exp.Method.Name) { + case "StartsWith": + case "EndsWith": + case "Contains": + var args0Value = ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); + if (args0Value == "NULL") return $"({left}) IS NULL"; + if (exp.Method.Name == "StartsWith") return $"({left}) LIKE {(args0Value.EndsWith("'") ? args0Value.Insert(args0Value.Length - 1, "%") : $"concat({args0Value}, '%')")}"; + if (exp.Method.Name == "EndsWith") return $"({left}) LIKE {(args0Value.StartsWith("'") ? args0Value.Insert(1, "%") : $"concat('%', {args0Value})")}"; + if (args0Value.StartsWith("'") && args0Value.EndsWith("'")) return $"({left}) LIKE {args0Value.Insert(1, "%").Insert(args0Value.Length, "%")}"; + return $"({left}) LIKE concat('%', {args0Value}, '%')"; + case "ToLower": return $"lower({left})"; + case "ToUpper": return $"upper({left})"; + case "Substring": + var substrArgs1 = ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); + if (long.TryParse(substrArgs1, out var testtrylng1)) substrArgs1 = (testtrylng1 + 1).ToString(); + else substrArgs1 += "+1"; + if (exp.Arguments.Count == 1) return $"substr({left}, {substrArgs1})"; + return $"substr({left}, {substrArgs1}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + case "IndexOf": + var indexOfFindStr = ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); + if (exp.Arguments.Count > 1 && exp.Arguments[1].Type.FullName == "System.Int32") { + var locateArgs1 = ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); + if (long.TryParse(locateArgs1, out var testtrylng2)) locateArgs1 = (testtrylng2 + 1).ToString(); + else locateArgs1 += "+1"; + return $"(locate({left}, {indexOfFindStr}, {locateArgs1})-1)"; } - foreach (var argsTrim01 in argsTrim01s) { - if (exp.Method.Name == "Trim") left = $"trim({ExpressionLambdaToSql(argsTrim01, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)} from {left})"; - if (exp.Method.Name == "TrimStart") left = $"trim(leading {ExpressionLambdaToSql(argsTrim01, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)} from {left})"; - if (exp.Method.Name == "TrimEnd") left = $"trim(trailing {ExpressionLambdaToSql(argsTrim01, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)} from {left})"; + return $"(locate({left}, {indexOfFindStr})-1)"; + case "PadLeft": + if (exp.Arguments.Count == 1) return $"lpad({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + return $"lpad({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + case "PadRight": + if (exp.Arguments.Count == 1) return $"rpad({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + return $"rpad({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + case "Trim": + case "TrimStart": + case "TrimEnd": + if (exp.Arguments.Count == 0) { + if (exp.Method.Name == "Trim") return $"trim({left})"; + if (exp.Method.Name == "TrimStart") return $"ltrim({left})"; + if (exp.Method.Name == "TrimEnd") return $"rtrim({left})"; } - } - return left; - case "Replace": return $"replace({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; - case "CompareTo": return $"strcmp({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; - case "Equals": return $"({left} = {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + foreach (var argsTrim02 in exp.Arguments) { + var argsTrim01s = new[] { argsTrim02 }; + if (argsTrim02.NodeType == ExpressionType.NewArrayInit) { + var arritem = argsTrim02 as NewArrayExpression; + argsTrim01s = arritem.Expressions.ToArray(); + } + foreach (var argsTrim01 in argsTrim01s) { + if (exp.Method.Name == "Trim") left = $"trim({ExpressionLambdaToSql(argsTrim01, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)} from {left})"; + if (exp.Method.Name == "TrimStart") left = $"trim(leading {ExpressionLambdaToSql(argsTrim01, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)} from {left})"; + if (exp.Method.Name == "TrimEnd") left = $"trim(trailing {ExpressionLambdaToSql(argsTrim01, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)} from {left})"; + } + } + return left; + case "Replace": return $"replace({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + case "CompareTo": return $"strcmp({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + case "Equals": return $"({left} = {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + } } throw new Exception($"MySqlExpression 未现实函数表达式 {exp} 解析"); } diff --git a/FreeSql/PostgreSQL/PostgreSQLExpression.cs b/FreeSql/PostgreSQL/PostgreSQLExpression.cs index ad11884c..97568ea1 100644 --- a/FreeSql/PostgreSQL/PostgreSQLExpression.cs +++ b/FreeSql/PostgreSQL/PostgreSQLExpression.cs @@ -16,7 +16,7 @@ namespace FreeSql.PostgreSQL { switch (exp.NodeType) { case ExpressionType.ArrayLength: var arrOperExp = ExpressionLambdaToSql((exp as UnaryExpression).Operand, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); - if (arrOperExp.StartsWith("(") || arrOperExp.EndsWith(")")) return $"array_length(array[{arrOperExp.TrimStart('(').TrimEnd(')')}])"; + if (arrOperExp.StartsWith("(") || arrOperExp.EndsWith(")")) return $"array_length(array[{arrOperExp.TrimStart('(').TrimEnd(')')}],1)"; return $"case when {arrOperExp} is null then 0 else array_length({arrOperExp},1) end"; case ExpressionType.Call: var callExp = exp as MethodCallExpression; @@ -34,18 +34,30 @@ namespace FreeSql.PostgreSQL { if (objType != null) { var left = objExp == null ? null : ExpressionLambdaToSql(objExp, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); if (objType.IsArray == true) { - if (left.StartsWith("(") || left.EndsWith(")")) left = $"array[{left.TrimStart('(').TrimEnd(')')}]"; switch (callExp.Method.Name) { - case "Any": return $"(case when {left} is null then 0 else array_length({left},1) end > 0)"; - case "Contains": return $"({left} @> array[{ExpressionLambdaToSql(callExp.Arguments[argIndex], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)}])"; + case "Any": + if (left.StartsWith("(") || left.EndsWith(")")) left = $"array[{left.TrimStart('(').TrimEnd(')')}]"; + return $"(case when {left} is null then 0 else array_length({left},1) end > 0)"; + case "Contains": + //判断 in 或 array @> array + var right1 = ExpressionLambdaToSql(callExp.Arguments[argIndex], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); + if (left.StartsWith("array[") || left.EndsWith("]")) + return $"{right1} in ({left.Substring(6, left.Length - 7)})"; + if (left.StartsWith("(") || left.EndsWith(")")) + return $"{right1} in {left}"; + if (right1.StartsWith("(") || right1.EndsWith(")")) right1 = $"array[{right1.TrimStart('(').TrimEnd(')')}]"; + return $"({left} @> array[{right1}])"; case "Concat": + if (left.StartsWith("(") || left.EndsWith(")")) left = $"array[{left.TrimStart('(').TrimEnd(')')}]"; var right2 = ExpressionLambdaToSql(callExp.Arguments[argIndex], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); if (right2.StartsWith("(") || right2.EndsWith(")")) right2 = $"array[{right2.TrimStart('(').TrimEnd(')')}]"; return $"({left} || {right2})"; case "GetLength": case "GetLongLength": case "Length": - case "Count": return $"case when {left} is null then 0 else array_length({left},1) end"; + case "Count": + if (left.StartsWith("(") || left.EndsWith(")")) left = $"array[{left.TrimStart('(').TrimEnd(')')}]"; + return $"case when {left} is null then 0 else array_length({left},1) end"; } } switch (objType.FullName) { @@ -92,8 +104,8 @@ namespace FreeSql.PostgreSQL { var memParentExp = memExp.Expression?.Type; if (memParentExp?.FullName == "System.Byte[]") return null; if (memParentExp != null) { - var left = ExpressionLambdaToSql(memExp.Expression, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); if (memParentExp.IsArray == true) { + var left = ExpressionLambdaToSql(memExp.Expression, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); if (left.StartsWith("(") || left.EndsWith(")")) left = $"array[{left.TrimStart('(').TrimEnd(')')}]"; switch (memExp.Member.Name) { case "Length": @@ -104,12 +116,14 @@ namespace FreeSql.PostgreSQL { case "Newtonsoft.Json.Linq.JToken": case "Newtonsoft.Json.Linq.JObject": case "Newtonsoft.Json.Linq.JArray": + var left = ExpressionLambdaToSql(memExp.Expression, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); switch (memExp.Member.Name) { case "Count": return $"jsonb_array_length(coalesce({left},'[]'))"; } break; } if (memParentExp.FullName == typeof(Dictionary).FullName) { + var left = ExpressionLambdaToSql(memExp.Expression, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); switch (memExp.Member.Name) { case "Count": return $"case when {left} is null then 0 else array_length(akeys({left}),1) end"; case "Keys": return $"akeys({left})"; @@ -199,66 +213,74 @@ namespace FreeSql.PostgreSQL { } internal override string ExpressionLambdaToSqlCallString(MethodCallExpression exp, List _tables, List _selectColumnMap, Func getSelectGroupingMapString, SelectTableInfoType tbtype, bool isQuoteName) { - var left = ExpressionLambdaToSql(exp.Object, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); - switch (exp.Method.Name) { - case "StartsWith": - case "EndsWith": - case "Contains": - var args0Value = ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); - if (args0Value == "NULL") return $"({left}) IS NULL"; - var likeOpt = "LIKE"; - if (exp.Arguments.Count > 1) { - if (exp.Arguments[1].Type == typeof(bool) || - exp.Arguments[1].Type == typeof(StringComparison) && ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName).Contains("IgnoreCase")) likeOpt = "ILIKE"; - } - if (exp.Method.Name == "StartsWith") return $"({left}) {likeOpt} {(args0Value.EndsWith("'") ? args0Value.Insert(args0Value.Length - 1, "%") : $"(({args0Value})::varchar || '%')")}"; - if (exp.Method.Name == "EndsWith") return $"({left}) {likeOpt} {(args0Value.StartsWith("'") ? args0Value.Insert(1, "%") : $"('%' || ({args0Value})::varchar)")}"; - if (args0Value.StartsWith("'") && args0Value.EndsWith("'")) return $"({left}) {likeOpt} {args0Value.Insert(1, "%").Insert(args0Value.Length, "%")}"; - return $"({left}) {likeOpt} ('%' || ({args0Value})::varchar || '%')"; - case "ToLower": return $"lower({left})"; - case "ToUpper": return $"upper({left})"; - case "Substring": - var substrArgs1 = ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); - if (long.TryParse(substrArgs1, out var testtrylng1)) substrArgs1 = (testtrylng1 + 1).ToString(); - else substrArgs1 += "+1"; - if (exp.Arguments.Count == 1) return $"substr({left}, {substrArgs1})"; - return $"substr({left}, {substrArgs1}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; - case "IndexOf": return $"(strpos({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})-1)"; - case "PadLeft": - if (exp.Arguments.Count == 1) return $"lpad({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; - return $"lpad({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; - case "PadRight": - if (exp.Arguments.Count == 1) return $"rpad({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; - return $"rpad({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; - case "Trim": - case "TrimStart": - case "TrimEnd": - if (exp.Arguments.Count == 0) { - if (exp.Method.Name == "Trim") return $"trim({left})"; - if (exp.Method.Name == "TrimStart") return $"ltrim({left})"; - if (exp.Method.Name == "TrimEnd") return $"rtrim({left})"; - } - var trimArg1 = ""; - var trimArg2 = ""; - foreach (var argsTrim02 in exp.Arguments) { - var argsTrim01s = new[] { argsTrim02 }; - if (argsTrim02.NodeType == ExpressionType.NewArrayInit) { - var arritem = argsTrim02 as NewArrayExpression; - argsTrim01s = arritem.Expressions.ToArray(); + if (exp.Object == null) { + switch (exp.Method.Name) { + case "IsNullOrEmpty": + var arg1 = ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); + return $"({arg1} is null or {arg1} = '')"; + } + } else { + var left = ExpressionLambdaToSql(exp.Object, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); + switch (exp.Method.Name) { + case "StartsWith": + case "EndsWith": + case "Contains": + var args0Value = ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); + if (args0Value == "NULL") return $"({left}) IS NULL"; + var likeOpt = "LIKE"; + if (exp.Arguments.Count > 1) { + if (exp.Arguments[1].Type == typeof(bool) || + exp.Arguments[1].Type == typeof(StringComparison) && ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName).Contains("IgnoreCase")) likeOpt = "ILIKE"; } - foreach (var argsTrim01 in argsTrim01s) { - var trimChr = ExpressionLambdaToSql(argsTrim01, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName).Trim('\''); - if (trimChr.Length == 1) trimArg1 += trimChr; - else trimArg2 += $" || ({trimChr})"; + if (exp.Method.Name == "StartsWith") return $"({left}) {likeOpt} {(args0Value.EndsWith("'") ? args0Value.Insert(args0Value.Length - 1, "%") : $"(({args0Value})::varchar || '%')")}"; + if (exp.Method.Name == "EndsWith") return $"({left}) {likeOpt} {(args0Value.StartsWith("'") ? args0Value.Insert(1, "%") : $"('%' || ({args0Value})::varchar)")}"; + if (args0Value.StartsWith("'") && args0Value.EndsWith("'")) return $"({left}) {likeOpt} {args0Value.Insert(1, "%").Insert(args0Value.Length, "%")}"; + return $"({left}) {likeOpt} ('%' || ({args0Value})::varchar || '%')"; + case "ToLower": return $"lower({left})"; + case "ToUpper": return $"upper({left})"; + case "Substring": + var substrArgs1 = ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); + if (long.TryParse(substrArgs1, out var testtrylng1)) substrArgs1 = (testtrylng1 + 1).ToString(); + else substrArgs1 += "+1"; + if (exp.Arguments.Count == 1) return $"substr({left}, {substrArgs1})"; + return $"substr({left}, {substrArgs1}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + case "IndexOf": return $"(strpos({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})-1)"; + case "PadLeft": + if (exp.Arguments.Count == 1) return $"lpad({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + return $"lpad({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + case "PadRight": + if (exp.Arguments.Count == 1) return $"rpad({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + return $"rpad({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + case "Trim": + case "TrimStart": + case "TrimEnd": + if (exp.Arguments.Count == 0) { + if (exp.Method.Name == "Trim") return $"trim({left})"; + if (exp.Method.Name == "TrimStart") return $"ltrim({left})"; + if (exp.Method.Name == "TrimEnd") return $"rtrim({left})"; } - } - if (exp.Method.Name == "Trim") left = $"trim({left}, {_common.FormatSql("{0}", trimArg1)}{trimArg2})"; - if (exp.Method.Name == "TrimStart") left = $"ltrim({left}, {_common.FormatSql("{0}", trimArg1)}{trimArg2})"; - if (exp.Method.Name == "TrimEnd") left = $"rtrim({left}, {_common.FormatSql("{0}", trimArg1)}{trimArg2})"; - return left; - case "Replace": return $"replace({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; - case "CompareTo": return $"case when {left} = {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)} then 0 when {left} > {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)} then 1 else -1 end"; - case "Equals": return $"({left} = ({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})::varchar)"; + var trimArg1 = ""; + var trimArg2 = ""; + foreach (var argsTrim02 in exp.Arguments) { + var argsTrim01s = new[] { argsTrim02 }; + if (argsTrim02.NodeType == ExpressionType.NewArrayInit) { + var arritem = argsTrim02 as NewArrayExpression; + argsTrim01s = arritem.Expressions.ToArray(); + } + foreach (var argsTrim01 in argsTrim01s) { + var trimChr = ExpressionLambdaToSql(argsTrim01, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName).Trim('\''); + if (trimChr.Length == 1) trimArg1 += trimChr; + else trimArg2 += $" || ({trimChr})"; + } + } + if (exp.Method.Name == "Trim") left = $"trim({left}, {_common.FormatSql("{0}", trimArg1)}{trimArg2})"; + if (exp.Method.Name == "TrimStart") left = $"ltrim({left}, {_common.FormatSql("{0}", trimArg1)}{trimArg2})"; + if (exp.Method.Name == "TrimEnd") left = $"rtrim({left}, {_common.FormatSql("{0}", trimArg1)}{trimArg2})"; + return left; + case "Replace": return $"replace({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + case "CompareTo": return $"case when {left} = {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)} then 0 when {left} > {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)} then 1 else -1 end"; + case "Equals": return $"({left} = ({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})::varchar)"; + } } throw new Exception($"PostgreSQLExpression 未现实函数表达式 {exp} 解析"); } diff --git a/FreeSql/SqlServer/SqlServerExpression.cs b/FreeSql/SqlServer/SqlServerExpression.cs index d864afda..e969b9a7 100644 --- a/FreeSql/SqlServer/SqlServerExpression.cs +++ b/FreeSql/SqlServer/SqlServerExpression.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; +using System.Text; namespace FreeSql.SqlServer { class SqlServerExpression : CommonExpression { @@ -11,6 +12,41 @@ namespace FreeSql.SqlServer { public SqlServerExpression(CommonUtils common) : base(common) { } internal override string ExpressionLambdaToSqlOther(Expression exp, List _tables, List _selectColumnMap, Func getSelectGroupingMapString, SelectTableInfoType tbtype, bool isQuoteName) { + switch (exp.NodeType) { + case ExpressionType.Call: + var callExp = exp as MethodCallExpression; + var objExp = callExp.Object; + var objType = objExp?.Type; + if (objType?.FullName == "System.Byte[]") return null; + + var argIndex = 0; + if (objType == null && callExp.Method.DeclaringType.FullName == typeof(Enumerable).FullName) { + objExp = callExp.Arguments.FirstOrDefault(); + objType = objExp?.Type; + argIndex++; + } + if (objType == null) objType = callExp.Method.DeclaringType; + if (objType != null) { + var left = objExp == null ? null : ExpressionLambdaToSql(objExp, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); + if (objType.IsArray == true) { + switch (callExp.Method.Name) { + case "Contains": + //判断 in + return $"({ExpressionLambdaToSql(callExp.Arguments[argIndex], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)}) in {left}"; + } + } + } + break; + case ExpressionType.NewArrayInit: + var arrExp = exp as NewArrayExpression; + var arrSb = new StringBuilder(); + arrSb.Append("("); + for (var a = 0; a < arrExp.Expressions.Count; a++) { + if (a > 0) arrSb.Append(","); + arrSb.Append(ExpressionLambdaToSql(arrExp.Expressions[a], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)); + } + return arrSb.Append(")").ToString(); + } return null; } @@ -82,46 +118,54 @@ namespace FreeSql.SqlServer { } internal override string ExpressionLambdaToSqlCallString(MethodCallExpression exp, List _tables, List _selectColumnMap, Func getSelectGroupingMapString, SelectTableInfoType tbtype, bool isQuoteName) { - var left = ExpressionLambdaToSql(exp.Object, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); - switch (exp.Method.Name) { - case "StartsWith": - case "EndsWith": - case "Contains": - var args0Value = ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); - if (args0Value == "NULL") return $"({left}) IS NULL"; - if (exp.Method.Name == "StartsWith") return $"({left}) LIKE {(args0Value.EndsWith("'") ? args0Value.Insert(args0Value.Length - 1, "%") : $"(cast({args0Value} as nvarchar)+'%')")}"; - if (exp.Method.Name == "EndsWith") return $"({left}) LIKE {(args0Value.StartsWith("'") ? args0Value.Insert(1, "%") : $"('%'+cast({args0Value} as nvarchar))")}"; - if (args0Value.StartsWith("'") && args0Value.EndsWith("'")) return $"({left}) LIKE {args0Value.Insert(1, "%").Insert(args0Value.Length, "%")}"; - return $"({left}) LIKE ('%'+cast({args0Value} as nvarchar)+'%')"; - case "ToLower": return $"lower({left})"; - case "ToUpper": return $"upper({left})"; - case "Substring": - var substrArgs1 = ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); - if (long.TryParse(substrArgs1, out var testtrylng1)) substrArgs1 = (testtrylng1 + 1).ToString(); - else substrArgs1 += "+1"; - if (exp.Arguments.Count == 1) return $"left({left}, {substrArgs1})"; - return $"substring({left}, {substrArgs1}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; - case "IndexOf": - var indexOfFindStr = ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); - if (exp.Arguments.Count > 1 && exp.Arguments[1].Type.FullName == "System.Int32") { - var locateArgs1 = ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); - if (long.TryParse(locateArgs1, out var testtrylng2)) locateArgs1 = (testtrylng2 + 1).ToString(); - else locateArgs1 += "+1"; - return $"(charindex({left}, {indexOfFindStr}, {locateArgs1})-1)"; - } - return $"(charindex({left}, {indexOfFindStr})-1)"; - case "PadLeft": - if (exp.Arguments.Count == 1) return $"lpad({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; - return $"lpad({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; - case "PadRight": - if (exp.Arguments.Count == 1) return $"rpad({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; - return $"rpad({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; - case "Trim": return $"ltrim(rtrim({left}))"; - case "TrimStart": return $"ltrim({left})"; - case "TrimEnd": return $"rtrim({left})"; - case "Replace": return $"replace({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; - case "CompareTo": return $"({left} - {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; - case "Equals": return $"({left} = {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + if (exp.Object == null) { + switch (exp.Method.Name) { + case "IsNullOrEmpty": + var arg1 = ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); + return $"({arg1} is null or {arg1} = '')"; + } + } else { + var left = ExpressionLambdaToSql(exp.Object, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); + switch (exp.Method.Name) { + case "StartsWith": + case "EndsWith": + case "Contains": + var args0Value = ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); + if (args0Value == "NULL") return $"({left}) IS NULL"; + if (exp.Method.Name == "StartsWith") return $"({left}) LIKE {(args0Value.EndsWith("'") ? args0Value.Insert(args0Value.Length - 1, "%") : $"(cast({args0Value} as nvarchar)+'%')")}"; + if (exp.Method.Name == "EndsWith") return $"({left}) LIKE {(args0Value.StartsWith("'") ? args0Value.Insert(1, "%") : $"('%'+cast({args0Value} as nvarchar))")}"; + if (args0Value.StartsWith("'") && args0Value.EndsWith("'")) return $"({left}) LIKE {args0Value.Insert(1, "%").Insert(args0Value.Length, "%")}"; + return $"({left}) LIKE ('%'+cast({args0Value} as nvarchar)+'%')"; + case "ToLower": return $"lower({left})"; + case "ToUpper": return $"upper({left})"; + case "Substring": + var substrArgs1 = ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); + if (long.TryParse(substrArgs1, out var testtrylng1)) substrArgs1 = (testtrylng1 + 1).ToString(); + else substrArgs1 += "+1"; + if (exp.Arguments.Count == 1) return $"left({left}, {substrArgs1})"; + return $"substring({left}, {substrArgs1}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + case "IndexOf": + var indexOfFindStr = ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); + if (exp.Arguments.Count > 1 && exp.Arguments[1].Type.FullName == "System.Int32") { + var locateArgs1 = ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); + if (long.TryParse(locateArgs1, out var testtrylng2)) locateArgs1 = (testtrylng2 + 1).ToString(); + else locateArgs1 += "+1"; + return $"(charindex({left}, {indexOfFindStr}, {locateArgs1})-1)"; + } + return $"(charindex({left}, {indexOfFindStr})-1)"; + case "PadLeft": + if (exp.Arguments.Count == 1) return $"lpad({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + return $"lpad({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + case "PadRight": + if (exp.Arguments.Count == 1) return $"rpad({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + return $"rpad({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + case "Trim": return $"ltrim(rtrim({left}))"; + case "TrimStart": return $"ltrim({left})"; + case "TrimEnd": return $"rtrim({left})"; + case "Replace": return $"replace({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + case "CompareTo": return $"({left} - {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + case "Equals": return $"({left} = {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + } } throw new Exception($"SqlServerExpression 未现实函数表达式 {exp} 解析"); }