diff --git a/src/FluentCommand.Generators/Properties/launchSettings.json b/src/FluentCommand.Generators/Properties/launchSettings.json
index 5fc31d63..4365fc4d 100644
--- a/src/FluentCommand.Generators/Properties/launchSettings.json
+++ b/src/FluentCommand.Generators/Properties/launchSettings.json
@@ -3,6 +3,10 @@
"FluentCommand.Tests": {
"commandName": "DebugRoslynComponent",
"targetProject": "..\\..\\test\\FluentCommand.Tests\\FluentCommand.Tests.csproj"
+ },
+ "FluentCommand.Entities": {
+ "commandName": "DebugRoslynComponent",
+ "targetProject": "..\\..\\test\\FluentCommand.Entities\\FluentCommand.Entities.csproj"
}
}
}
diff --git a/src/FluentCommand/DataQueryLogger.cs b/src/FluentCommand/DataQueryLogger.cs
index 1195ba81..cef737be 100644
--- a/src/FluentCommand/DataQueryLogger.cs
+++ b/src/FluentCommand/DataQueryLogger.cs
@@ -1,29 +1,31 @@
using System.Data;
+using System.Text;
+
+using FluentCommand.Extensions;
+using FluentCommand.Internal;
using Microsoft.Extensions.Logging;
namespace FluentCommand;
///
-/// A class for logging queries
+/// A class for logging queries
///
///
public partial class DataQueryLogger : IDataQueryLogger
{
- private readonly ILogger _logger;
- private readonly IDataQueryFormatter _formatter;
///
/// Initializes a new instance of the class.
///
/// The logger.
- /// The formatter for the data command
- public DataQueryLogger(ILogger logger, IDataQueryFormatter formatter)
+ public DataQueryLogger(ILogger logger)
{
- _logger = logger;
- _formatter = formatter;
+ Logger = logger;
}
+ protected ILogger Logger { get; }
+
///
/// Log the current specified
///
@@ -34,23 +36,69 @@ public DataQueryLogger(ILogger logger, IDataQueryFormatter form
/// command
public virtual void LogCommand(IDbCommand command, TimeSpan duration, Exception exception = null, object state = null)
{
- if (_logger == null)
+ if (Logger == null)
return;
if (command is null)
throw new ArgumentNullException(nameof(command));
- var output = _formatter.FormatCommand(command, duration, exception);
+ var elapsed = duration.TotalMilliseconds;
+ var commandType = command.CommandType;
+ var commandTimeout = command.CommandTimeout;
+ var commandText = command.CommandText;
+ var parameterText = FormatParameters(command);
if (exception == null)
- LogCommand(output);
+ LogCommand(Logger, elapsed, commandType, commandTimeout, commandText, parameterText);
else
- LogError(output, exception);
+ LogError(Logger, elapsed, commandType, commandTimeout, commandText, parameterText, exception);
+ }
+
+ protected static string FormatParameters(IDbCommand command)
+ {
+ if (command is null || command.Parameters == null || command.Parameters.Count == 0)
+ return string.Empty;
+
+ var parameterText = StringBuilderCache.Acquire();
+
+ foreach (IDataParameter parameter in command.Parameters)
+ {
+ int precision = 0;
+ int scale = 0;
+ int size = 0;
+
+ if (parameter is IDbDataParameter dataParameter)
+ {
+ precision = dataParameter.Precision;
+ scale = dataParameter.Scale;
+ size = dataParameter.Size;
+ }
+
+ parameterText
+ .AppendLineIf(() => parameterText.Length > 0)
+ .Append("-- ")
+ .Append(parameter.ParameterName)
+ .Append(": ")
+ .Append(parameter.Direction)
+ .Append(" ")
+ .Append(parameter.DbType)
+ .Append("(Size=")
+ .Append(size)
+ .Append("; Precision=")
+ .Append(precision)
+ .Append("; Scale=")
+ .Append(scale)
+ .Append(") [")
+ .Append(parameter.Value)
+ .Append("]");
+ }
+
+ return parameterText.ToString();
}
- [LoggerMessage(0, LogLevel.Debug, "{output}")]
- private partial void LogCommand(string output);
+ [LoggerMessage(0, LogLevel.Debug, "Executed DbCommand ({Elapsed} ms) [CommandType='{CommandType}', CommandTimeout='{CommandTimeout}']\r\n{CommandText}\r\n{ParameterText}")]
+ protected static partial void LogCommand(ILogger logger, double elapsed, CommandType commandType, int commandTimeout, string commandText, string parameterText);
- [LoggerMessage(1, LogLevel.Error, "{output}")]
- private partial void LogError(string output, Exception exception);
+ [LoggerMessage(1, LogLevel.Error, "Error Executing DbCommand ({Elapsed} ms) [CommandType='{CommandType}', CommandTimeout='{CommandTimeout}']\r\n{CommandText}\r\n{ParameterText}")]
+ protected static partial void LogError(ILogger logger, double elapsed, CommandType commandType, int commandTimeout, string commandText, string parameterText, Exception exception);
}
diff --git a/src/FluentCommand/Extensions/StringBuilderExtensions.cs b/src/FluentCommand/Extensions/StringBuilderExtensions.cs
new file mode 100644
index 00000000..45b485dd
--- /dev/null
+++ b/src/FluentCommand/Extensions/StringBuilderExtensions.cs
@@ -0,0 +1,113 @@
+using System.Text;
+
+namespace FluentCommand.Extensions;
+
+///
+/// extension methods
+///
+public static class StringBuilderExtensions
+{
+ ///
+ /// Appends a copy of the specified string followed by the default line terminator to the end of the StringBuilder object.
+ ///
+ /// The StringBuilder instance to append to.
+ /// A composite format string.
+ /// An object array that contains zero or more objects to format.
+ public static StringBuilder AppendLine(this StringBuilder sb, string format, params object[] args)
+ {
+ sb.AppendFormat(format, args);
+ sb.AppendLine();
+ return sb;
+ }
+
+ ///
+ /// Appends a copy of the specified string if is met.
+ ///
+ /// The StringBuilder instance to append to.
+ /// The string to append.
+ /// The condition delegate to evaluate. If condition is null, String.IsNullOrWhiteSpace method will be used.
+ public static StringBuilder AppendIf(this StringBuilder sb, string text, Func condition = null)
+ {
+ var c = condition ?? (s => !string.IsNullOrEmpty(s));
+
+ if (c(text))
+ sb.Append(text);
+
+ return sb;
+ }
+
+ ///
+ /// Appends a copy of the specified string if is met.
+ ///
+ /// The StringBuilder instance to append to.
+ /// The string to append.
+ /// The condition delegate to evaluate. If condition is null, String.IsNullOrWhiteSpace method will be used.
+ public static StringBuilder AppendIf(this StringBuilder sb, string text, bool condition)
+ {
+ if (condition)
+ sb.Append(text);
+
+ return sb;
+ }
+
+ ///
+ /// Appends a copy of the specified string followed by the default line terminator if is met.
+ ///
+ /// The StringBuilder instance to append to.
+ /// The string to append.
+ /// The condition delegate to evaluate. If condition is null, String.IsNullOrWhiteSpace method will be used.
+ public static StringBuilder AppendLineIf(this StringBuilder sb, string text, Func condition = null)
+ {
+ var c = condition ?? (s => !string.IsNullOrEmpty(s));
+
+ if (c(text))
+ sb.AppendLine(text);
+
+ return sb;
+ }
+
+ ///
+ /// Appends a copy of the specified string followed by the default line terminator if is met.
+ ///
+ /// The StringBuilder instance to append to.
+ /// The condition delegate to evaluate. If condition is null, String.IsNullOrWhiteSpace method will be used.
+ public static StringBuilder AppendLineIf(this StringBuilder sb, Func condition)
+ {
+ if (condition())
+ sb.AppendLine();
+
+ return sb;
+ }
+
+ ///
+ /// Concatenates and appends the members of a collection, using the specified separator between each member.
+ ///
+ /// The type of the members of values.
+ /// A reference to this instance after the append operation has completed.
+ /// The string to use as a separator. separator is included in the concatenated and appended strings only if values has more than one element.
+ /// A collection that contains the objects to concatenate and append to the current instance of the string builder.
+ /// A reference to this instance after the append operation has completed.
+ public static StringBuilder AppendJoin(this StringBuilder sb, string separator, IEnumerable values)
+ {
+ if (sb is null)
+ throw new ArgumentNullException(nameof(sb));
+ if (values is null)
+ throw new ArgumentNullException(nameof(values));
+
+ separator ??= string.Empty;
+
+ var wroteValue = false;
+
+ foreach (var value in values)
+ {
+ if (wroteValue)
+ sb.Append(separator);
+
+ sb.Append(value);
+ wroteValue = true;
+ }
+
+ return sb;
+ }
+
+}
diff --git a/src/FluentCommand/Extensions/StringExtensions.cs b/src/FluentCommand/Extensions/StringExtensions.cs
index 2b705298..5c4ce408 100644
--- a/src/FluentCommand/Extensions/StringExtensions.cs
+++ b/src/FluentCommand/Extensions/StringExtensions.cs
@@ -1,7 +1,10 @@
using System;
using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
using System.Text;
+#nullable enable
+
namespace FluentCommand.Extensions;
///
@@ -16,7 +19,7 @@ public static class StringExtensions
///
/// true if is null or empty; otherwise, false.
///
- public static bool IsNullOrEmpty(this string item)
+ public static bool IsNullOrEmpty([NotNullWhen(false)] this string? item)
{
return string.IsNullOrEmpty(item);
}
@@ -28,7 +31,7 @@ public static bool IsNullOrEmpty(this string item)
///
/// true if is null or empty; otherwise, false.
///
- public static bool IsNullOrWhiteSpace(this string item)
+ public static bool IsNullOrWhiteSpace([NotNullWhen(false)] this string? item)
{
if (item == null)
return true;
@@ -47,112 +50,19 @@ public static bool IsNullOrWhiteSpace(this string item)
///
/// true if the specified is not ; otherwise, false.
///
- public static bool HasValue(this string value)
+ public static bool HasValue([NotNullWhen(true)] this string? value)
{
return !string.IsNullOrEmpty(value);
}
///
- /// Uses the string as a format
+ /// Replaces the format item in a specified string with the string representation of a corresponding object in a specified array.
///
- /// A String reference
- /// Object parameters that should be formatted
- /// Formatted string
- public static string FormatWith(this string format, params object[] args)
+ /// A composite format string
+ /// An object array that contains zero or more objects to format
+ /// A copy of format in which the format items have been replaced by the string representation of the corresponding objects in args
+ public static string FormatWith(this string format, params object?[] args)
{
- if (format == null)
- throw new ArgumentNullException("format");
-
return string.Format(format, args);
}
-
- ///
- /// Appends a copy of the specified string followed by the default line terminator to the end of the StringBuilder object.
- ///
- /// The StringBuilder instance to append to.
- /// A composite format string.
- /// An object array that contains zero or more objects to format.
- public static StringBuilder AppendLine(this StringBuilder sb, string format, params object[] args)
- {
- sb.AppendFormat(format, args);
- sb.AppendLine();
- return sb;
- }
-
- ///
- /// Appends a copy of the specified string if is met.
- ///
- /// The StringBuilder instance to append to.
- /// The string to append.
- /// The condition delegate to evaluate. If condition is null, String.IsNullOrWhiteSpace method will be used.
- public static StringBuilder AppendIf(this StringBuilder sb, string text, Func condition = null)
- {
- var c = condition ?? (s => !string.IsNullOrEmpty(s));
-
- if (c(text))
- sb.Append(text);
-
- return sb;
- }
-
- ///
- /// Appends a copy of the specified string if is met.
- ///
- /// The StringBuilder instance to append to.
- /// The string to append.
- /// The condition delegate to evaluate. If condition is null, String.IsNullOrWhiteSpace method will be used.
- public static StringBuilder AppendIf(this StringBuilder sb, string text, bool condition)
- {
- if (condition)
- sb.Append(text);
-
- return sb;
- }
-
- ///
- /// Appends a copy of the specified string followed by the default line terminator if is met.
- ///
- /// The StringBuilder instance to append to.
- /// The string to append.
- /// The condition delegate to evaluate. If condition is null, String.IsNullOrWhiteSpace method will be used.
- public static StringBuilder AppendLineIf(this StringBuilder sb, string text, Func condition = null)
- {
- var c = condition ?? (s => !string.IsNullOrEmpty(s));
-
- if (c(text))
- sb.AppendLine(text);
-
- return sb;
- }
-
- ///
- /// Concatenates and appends the members of a collection, using the specified separator between each member.
- ///
- /// The type of the members of values.
- /// A reference to this instance after the append operation has completed.
- /// The string to use as a separator. separator is included in the concatenated and appended strings only if values has more than one element.
- /// A collection that contains the objects to concatenate and append to the current instance of the string builder.
- /// A reference to this instance after the append operation has completed.
- public static StringBuilder AppendJoin(this StringBuilder sb, string separator, IEnumerable values)
- {
- if (sb is null)
- throw new ArgumentNullException(nameof(sb));
- if (values is null)
- throw new ArgumentNullException(nameof(values));
-
- separator ??= string.Empty;
-
- var wroteValue = false;
-
- foreach (var value in values)
- {
- if (wroteValue)
- sb.Append(separator);
-
- sb.Append(value);
- wroteValue = true;
- }
-
- return sb;
- }
}
diff --git a/src/FluentCommand/FluentCommand.csproj b/src/FluentCommand/FluentCommand.csproj
index 4933a7be..b48f5483 100644
--- a/src/FluentCommand/FluentCommand.csproj
+++ b/src/FluentCommand/FluentCommand.csproj
@@ -7,6 +7,10 @@
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
diff --git a/src/FluentCommand/Internal/IsExternalInit.cs b/src/FluentCommand/Internal/IsExternalInit.cs
deleted file mode 100644
index fee341d3..00000000
--- a/src/FluentCommand/Internal/IsExternalInit.cs
+++ /dev/null
@@ -1,8 +0,0 @@
-#if NETSTANDARD2_0
-using System.ComponentModel;
-
-namespace System.Runtime.CompilerServices;
-
-[EditorBrowsable(EditorBrowsableState.Never)]
-sealed class IsExternalInit { }
-#endif