Skip to content

Commit

Permalink
Remove direct dependency from Serenity.Data to Microsoft.Data.SqlClie…
Browse files Browse the repository at this point in the history
…nt by using reflection where required
  • Loading branch information
volkanceylan committed Oct 3, 2024
1 parent 0f87fca commit 0b246f5
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 76 deletions.
1 change: 0 additions & 1 deletion src/Serenity.Net.Data/Serenity.Net.Data.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,5 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Dapper" Version="2.1.35" />
<PackageReference Include="Microsoft.Data.SqlClient" Version="5.2.2" />
</ItemGroup>
</Project>
106 changes: 70 additions & 36 deletions src/Serenity.Net.Data/SqlHelpers/SqlCommandDumper.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
using Microsoft.Data.SqlClient;

namespace Serenity.Data;

/// <summary>
Expand All @@ -12,13 +10,30 @@ public class SqlCommandDumper
/// </summary>
/// <param name="sqc">The SQL command.</param>
/// <returns></returns>
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("");

Expand All @@ -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)
Expand All @@ -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)
Expand All @@ -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)
{
Expand All @@ -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");
Expand All @@ -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)
Expand All @@ -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(";");
}
}

Expand Down Expand Up @@ -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
Expand All @@ -260,17 +294,17 @@ 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
case SqlDbType.Timestamp:
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;
}
Expand Down
58 changes: 19 additions & 39 deletions src/Serenity.Net.Data/SqlHelpers/SqlHelper.cs
Original file line number Diff line number Diff line change
@@ -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<string, object>;

Expand Down Expand Up @@ -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("<NULL>");
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)
{
Expand Down Expand Up @@ -222,19 +196,25 @@ public static IDbCommand NewCommand(IDbConnection connection, string commandText
/// <returns>True if exception is 10054, e.g. connection pool.</returns>
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;
}

/// <summary>
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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);

Expand All @@ -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();
Expand Down Expand Up @@ -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();
Expand Down

0 comments on commit 0b246f5

Please sign in to comment.