diff --git a/src/Serenity.Net.Data/Serenity.Net.Data.csproj b/src/Serenity.Net.Data/Serenity.Net.Data.csproj index 4efa8ce3e5..44fbc9b6b6 100644 --- a/src/Serenity.Net.Data/Serenity.Net.Data.csproj +++ b/src/Serenity.Net.Data/Serenity.Net.Data.csproj @@ -9,6 +9,5 @@ - \ No newline at end of file diff --git a/src/Serenity.Net.Data/SqlHelpers/SqlCommandDumper.cs b/src/Serenity.Net.Data/SqlHelpers/SqlCommandDumper.cs index 9ddc6d9002..01ebf3dcb1 100644 --- a/src/Serenity.Net.Data/SqlHelpers/SqlCommandDumper.cs +++ b/src/Serenity.Net.Data/SqlHelpers/SqlCommandDumper.cs @@ -1,5 +1,3 @@ -using Microsoft.Data.SqlClient; - namespace Serenity.Data; /// @@ -12,13 +10,30 @@ public class SqlCommandDumper /// /// The SQL command. /// - public static string GetCommandText(SqlCommand sqc) + public static string GetCommandText(IDbCommand sqc) { var sbCommandText = new StringBuilder(); + bool initialized = false; + PropertyInfo sqlDbTypeProperty = null; + PropertyInfo sizeProperty = null; + // params - for (int i = 0; i < sqc.Parameters.Count; i++) - LogParameterToSqlBatch(sqc.Parameters[i], sbCommandText); + foreach (IDbDataParameter parameter in sqc.Parameters) + { + if (!initialized) + { + initialized = true; + var isSqlServer = parameter.GetType().FullName == "Microsoft.Data.SqlClient.SqlParameter" || + parameter.GetType().FullName == "System.Data.SqlClient.SqlParameter"; + if (!isSqlServer) + { + sqlDbTypeProperty = parameter.GetType().GetProperty("SqlDbType"); + sizeProperty = parameter.GetType().GetProperty("Size"); + } + } + LogParameterToSqlBatch(parameter, sbCommandText, sqlDbTypeProperty, sizeProperty); + } sbCommandText.AppendLine(""); @@ -28,9 +43,9 @@ public static string GetCommandText(SqlCommand sqc) sbCommandText.Append("EXEC "); bool hasReturnValue = false; - for (int i = 0; i < sqc.Parameters.Count; i++) + foreach (IDbDataParameter param in sqc.Parameters) { - if (sqc.Parameters[i].Direction == ParameterDirection.ReturnValue) + if (param.Direction == ParameterDirection.ReturnValue) hasReturnValue = true; } if (hasReturnValue) @@ -41,9 +56,8 @@ public static string GetCommandText(SqlCommand sqc) sbCommandText.Append(sqc.CommandText); bool hasPrev = false; - for (int i = 0; i < sqc.Parameters.Count; i++) + foreach (IDataParameter cParam in sqc.Parameters) { - var cParam = sqc.Parameters[i]; if (cParam.Direction != ParameterDirection.ReturnValue) { if (hasPrev) @@ -66,7 +80,7 @@ public static string GetCommandText(SqlCommand sqc) } bool anyOut = false; - foreach (SqlParameter p in sqc.Parameters) + foreach (IDataParameter p in sqc.Parameters) if (p.Direction == ParameterDirection.ReturnValue || p.Direction == ParameterDirection.Output) { @@ -78,10 +92,8 @@ public static string GetCommandText(SqlCommand sqc) { sbCommandText.AppendLine("-- RESULTS"); sbCommandText.Append("SELECT 1 as Executed"); - for (int i = 0; i < sqc.Parameters.Count; i++) + foreach (IDataParameter cParam in sqc.Parameters) { - var cParam = sqc.Parameters[i]; - if (cParam.Direction == ParameterDirection.ReturnValue) { sbCommandText.Append(", @returnValue as ReturnValue"); @@ -101,7 +113,8 @@ public static string GetCommandText(SqlCommand sqc) return sbCommandText.ToString(); } - private static void LogParameterToSqlBatch(SqlParameter param, StringBuilder sbCommandText) + private static void LogParameterToSqlBatch(IDbDataParameter param, StringBuilder sbCommandText, + PropertyInfo sqlDbTypeProperty, PropertyInfo sizeProperty) { sbCommandText.Append("DECLARE "); if (param.Direction == ParameterDirection.ReturnValue) @@ -113,18 +126,41 @@ private static void LogParameterToSqlBatch(SqlParameter param, StringBuilder sbC sbCommandText.Append(param.ParameterName); sbCommandText.Append(' '); - if (param.SqlDbType != SqlDbType.Structured) + SqlDbType? sqlDbType = null; + int? size = null; + if (sqlDbTypeProperty != null) { - LogParameterType(param, sbCommandText); - sbCommandText.Append(" = "); - LogQuotedParameterValue(param.Value, sbCommandText); + try + { + sqlDbType = sqlDbTypeProperty.GetValue(param) as SqlDbType?; + } + catch + { + } + } + if (sizeProperty != null) + { + try + { + size = sizeProperty.GetValue(param) as int?; + } + catch + { + } + } - sbCommandText.AppendLine(";"); + if (sqlDbType != null) + { + LogParamSqlDbType(sqlDbType.Value, size ?? 0, sbCommandText); } else { - throw new NotImplementedException(); + LogParamDbType(param, sbCommandText); } + + sbCommandText.Append(" = "); + LogQuotedParameterValue(param.Value, sbCommandText); + sbCommandText.AppendLine(";"); } } @@ -215,29 +251,27 @@ private static void LogQuotedParameterValue(object value, StringBuilder sbComman } } - private static void LogParameterType(SqlParameter param, StringBuilder sbCommandText) + private static void LogParamDbType(IDataParameter param, StringBuilder sbCommandText) + { + sbCommandText.Append(param.DbType.ToString()); + } + + private static void LogParamSqlDbType(SqlDbType sqlDbType, int size, StringBuilder sbCommandText) { - switch (param.SqlDbType) + switch (sqlDbType) { // variable length case SqlDbType.Char: case SqlDbType.NChar: case SqlDbType.Binary: - { - sbCommandText.Append(param.SqlDbType.ToString().ToUpperInvariant()); - sbCommandText.Append('('); - sbCommandText.Append(param.Size == 0 ? 1 : param.Size); - sbCommandText.Append(')'); - } - break; case SqlDbType.VarChar: case SqlDbType.NVarChar: case SqlDbType.VarBinary: { - sbCommandText.Append(param.SqlDbType.ToString().ToUpperInvariant()); - sbCommandText.Append("("); - sbCommandText.Append(param.Size == 0 ? 1 : param.Size); - sbCommandText.Append(")"); + sbCommandText.Append(sqlDbType.ToString().ToUpperInvariant()); + sbCommandText.Append('('); + sbCommandText.Append(size == 0 ? 1 : size); + sbCommandText.Append(')'); } break; // fixed length @@ -260,7 +294,7 @@ private static void LogParameterType(SqlParameter param, StringBuilder sbCommand case SqlDbType.UniqueIdentifier: case SqlDbType.Image: { - sbCommandText.Append(param.SqlDbType.ToString().ToUpperInvariant()); + sbCommandText.Append(sqlDbType.ToString().ToUpperInvariant()); } break; // Unknown @@ -268,9 +302,9 @@ private static void LogParameterType(SqlParameter param, StringBuilder sbCommand default: { sbCommandText.Append("/* UNKNOWN DATATYPE: "); - sbCommandText.Append(param.SqlDbType.ToString().ToUpperInvariant()); + sbCommandText.Append(sqlDbType.ToString().ToUpperInvariant()); sbCommandText.Append(" *" + "/ "); - sbCommandText.Append(param.SqlDbType.ToString().ToUpperInvariant()); + sbCommandText.Append(sqlDbType.ToString().ToUpperInvariant()); } break; } diff --git a/src/Serenity.Net.Data/SqlHelpers/SqlHelper.cs b/src/Serenity.Net.Data/SqlHelpers/SqlHelper.cs index e10f283669..6925b23266 100644 --- a/src/Serenity.Net.Data/SqlHelpers/SqlHelper.cs +++ b/src/Serenity.Net.Data/SqlHelpers/SqlHelper.cs @@ -1,6 +1,4 @@ -using Microsoft.Data.SqlClient; using Microsoft.Extensions.Logging; -using System.Data.Common; using System.IO; using Dictionary = System.Collections.Generic.Dictionary; @@ -70,31 +68,7 @@ public static void LogCommand(string method, IDbCommand command, ILogger logger) try { - if (command is SqlCommand sqlCmd) - { - logger.LogDebug("SQL - {method}[{uid}] - START\n{sql}", method, command.GetHashCode(), SqlCommandDumper.GetCommandText(sqlCmd)); - return; - } - - if (command.Parameters?.Count <= 0) - { - logger.LogDebug("SQL - {method}[{uid}] - START\n{sql}", method, command.GetHashCode(), command.CommandText); - return; - } - - StringBuilder sb = new(""); - foreach (DbParameter p in command.Parameters) - { - sb.Append(p.ParameterName); - sb.Append("="); - if (p.Value == null || p.Value == DBNull.Value) - sb.Append(""); - else - sb.Append(p.Value.ToString()); - sb.Append("; "); - } - - logger.LogDebug("SQL - {method}[{uid}] - START\n{sql}\n--PARAMS--\n{params}", method, command.GetHashCode(), command.CommandText, sb.ToString()); + logger.LogDebug("SQL - {method}[{uid}] - START\n{sql}", method, command.GetHashCode(), SqlCommandDumper.GetCommandText(command)); } catch (Exception ex) { @@ -222,19 +196,25 @@ public static IDbCommand NewCommand(IDbConnection connection, string commandText /// True if exception is 10054, e.g. connection pool. private static bool CheckConnectionPoolException(IDbConnection connection, Exception exception) { - if (exception is SqlException ex && ex.Number == 10054) - { - if ((connection is IHasOpenedOnce hoo && hoo.OpenedOnce) || - (connection is IHasCurrentTransaction hct && hct.CurrentTransaction != null)) - return false; + var exceptionType = exception.GetType(); - SqlConnection.ClearAllPools(); + if ((connection is IHasOpenedOnce hoo && hoo.OpenedOnce) || + (connection is IHasCurrentTransaction hct && hct.CurrentTransaction != null)) + return false; + + if (exceptionType.FullName == "Microsoft.Data.SqlException" || + exceptionType.FullName == "System.Data.SqlException" && + exceptionType.GetProperty("Number")?.GetValue(exception) is 10054) + { + var sqlConnectionType = exceptionType.Assembly.GetType(exceptionType.FullName.Replace("Exception", "Connection")); + var clearAllPools = sqlConnectionType?.GetMethod("ClearAllPools", BindingFlags.Static | BindingFlags.Public); + clearAllPools?.Invoke(null, null); connection.Close(); connection.Open(); return true; } - else - return false; + + return false; } /// @@ -268,7 +248,7 @@ public static int ExecuteNonQuery(IDbCommand command, ILogger logger = null) result = command.ExecuteNonQuery(); } - catch (SqlException ex) + catch (Exception ex) { if (CheckConnectionPoolException(command.Connection, ex)) return command.ExecuteNonQuery(); @@ -477,7 +457,7 @@ public static IDataReader ExecuteReader(IDbConnection connection, string command try { logger ??= connection.GetLogger(); - + if (logger?.IsEnabled(LogLevel.Debug) == true) LogCommand("ExecuteReader", command, logger); @@ -489,7 +469,7 @@ public static IDataReader ExecuteReader(IDbConnection connection, string command return result; } - catch (SqlException ex) + catch (Exception ex) { if (CheckConnectionPoolException(connection, ex)) return command.ExecuteReader(); @@ -564,7 +544,7 @@ public static object ExecuteScalar(IDbConnection connection, string commandText, return result; } - catch (SqlException ex) + catch (Exception ex) { if (CheckConnectionPoolException(connection, ex)) return command.ExecuteScalar();