diff --git a/Frends.MicrosoftSQL.ExecuteQueryToFile/CHANGELOG.md b/Frends.MicrosoftSQL.ExecuteQueryToFile/CHANGELOG.md index 528ac6f..a74161e 100644 --- a/Frends.MicrosoftSQL.ExecuteQueryToFile/CHANGELOG.md +++ b/Frends.MicrosoftSQL.ExecuteQueryToFile/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## [2.2.0] - 2026-01-14 +### Fixed +- Fix unloading assembly + ## [2.1.0] - 2024-12-16 ### Added - Added Microsoft.SqlServer.Types dependency so that SqlGeography and SqlGeometry typed objects can be handled. diff --git a/Frends.MicrosoftSQL.ExecuteQueryToFile/Frends.MicrosoftSQL.ExecuteQueryToFile/Definitions/CsvFileWriter.cs b/Frends.MicrosoftSQL.ExecuteQueryToFile/Frends.MicrosoftSQL.ExecuteQueryToFile/Definitions/CsvFileWriter.cs index 7015525..b8e9c85 100644 --- a/Frends.MicrosoftSQL.ExecuteQueryToFile/Frends.MicrosoftSQL.ExecuteQueryToFile/Definitions/CsvFileWriter.cs +++ b/Frends.MicrosoftSQL.ExecuteQueryToFile/Frends.MicrosoftSQL.ExecuteQueryToFile/Definitions/CsvFileWriter.cs @@ -15,7 +15,7 @@ namespace Frends.MicrosoftSQL.ExecuteQueryToFile.Definitions; -internal class CsvFileWriter +internal class CsvFileWriter : IAsyncDisposable { internal CsvFileWriter(SqlCommand sqlCommand, Input input, CsvOptions options) { @@ -30,31 +30,27 @@ internal CsvFileWriter(SqlCommand sqlCommand, Input input, CsvOptions options) private CsvOptions Options { get; set; } - public async Task SaveQueryToCSV(CancellationToken cancellationToken) + public async ValueTask DisposeAsync() { - var output = 0; - var encoding = GetEncoding(Options.FileEncoding, Options.EnableBom, Options.EncodingInString); - - using (var writer = new StreamWriter(Input.OutputFilePath, false, encoding)) - using (var csvFile = CreateCsvWriter(Options.GetFieldDelimiterAsString(), writer)) - { - writer.NewLine = Options.GetLineBreakAsString(); - - var reader = await SqlCommand.ExecuteReaderAsync(cancellationToken); - output = DataReaderToCsv(reader, csvFile, Options, cancellationToken); + if (SqlCommand != null) await SqlCommand.DisposeAsync(); + } - csvFile.Flush(); - } + public async Task SaveQueryToCsv(CancellationToken cancellationToken) + { + var encoding = GetEncoding(Options.FileEncoding, Options.EnableBom, Options.EncodingInString); + await using var writer = new StreamWriter(Input.OutputFilePath, false, encoding); + await using var csvFile = CreateCsvWriter(Options.GetFieldDelimiterAsString(), writer); + writer.NewLine = Options.GetLineBreakAsString(); + var reader = await SqlCommand.ExecuteReaderAsync(cancellationToken).ConfigureAwait(false); + var output = DataReaderToCsv(reader, csvFile, Options, cancellationToken); + await csvFile.FlushAsync().ConfigureAwait(false); return new Result(output, Input.OutputFilePath, Path.GetFileName(Input.OutputFilePath)); } private static CsvWriter CreateCsvWriter(string delimiter, TextWriter writer) { - var csvOptions = new CsvConfiguration(CultureInfo.InvariantCulture) - { - Delimiter = delimiter, - }; + var csvOptions = new CsvConfiguration(CultureInfo.InvariantCulture) { Delimiter = delimiter, }; return new CsvWriter(writer, csvOptions); } @@ -63,10 +59,11 @@ private static string FormatDbHeader(string header, bool forceSpecialFormatting) { if (!forceSpecialFormatting) return header; - // First part of regex removes all non-alphanumeric ('_' also allowed) chars from the whole string. - // Second part removed any leading numbers or underscoress. + // The first part of regex removes all non-alphanumeric ('_' also allowed) chars from the whole string. + // The second part removed any leading numbers or underscores. var rgx = new Regex("[^a-zA-Z0-9_-]|^[0-9_]+"); header = rgx.Replace(header, string.Empty); + return header.ToLower(); } @@ -76,6 +73,7 @@ private static string FormatDbValue(object value, string dbTypeName, Type dotnet { if (dotnetType == typeof(string)) return "\"\""; if (dotnetType == typeof(DateTime) && options.AddQuotesToDates) return "\"\""; + return string.Empty; } @@ -87,8 +85,10 @@ private static string FormatDbValue(object value, string dbTypeName, Type dotnet str = str.Replace("\r\n", " "); str = str.Replace("\r", " "); str = str.Replace("\n", " "); + if (options.AddQuotesToStrings) return $"\"{str}\""; + return str; } @@ -101,7 +101,9 @@ private static string FormatDbValue(object value, string dbTypeName, Type dotnet "date" => dateTime.ToString(options.DateFormat, CultureInfo.InvariantCulture), _ => dateTime.ToString(options.DateTimeFormat, CultureInfo.InvariantCulture), }; + if (options.AddQuotesToDates) return $"\"{output}\""; + return output; } @@ -126,8 +128,9 @@ private static int DataReaderToCsv( CsvOptions options, CancellationToken cancellationToken) { - // Write header and remember column indexes to include. + // Write a header and remember column indexes to include it. var columnIndexesToInclude = new List(); + for (var i = 0; i < reader.FieldCount; i++) { var columnName = reader.GetName(i); @@ -153,6 +156,7 @@ private static int DataReaderToCsv( if (options.IncludeHeadersInOutput) csvWriter.NextRecord(); int count = 0; + while (reader.Read()) { foreach (var columnIndex in columnIndexesToInclude) @@ -172,7 +176,10 @@ private static int DataReaderToCsv( return count; } - private static Encoding GetEncoding(FileEncoding optionsFileEncoding, bool optionsEnableBom, string optionsEncodingInString) + private static Encoding GetEncoding( + FileEncoding optionsFileEncoding, + bool optionsEnableBom, + string optionsEncodingInString) { return optionsFileEncoding switch { diff --git a/Frends.MicrosoftSQL.ExecuteQueryToFile/Frends.MicrosoftSQL.ExecuteQueryToFile/Enums/FileEncoding.cs b/Frends.MicrosoftSQL.ExecuteQueryToFile/Frends.MicrosoftSQL.ExecuteQueryToFile/Enums/FileEncoding.cs index cdc2840..f0fa0a8 100644 --- a/Frends.MicrosoftSQL.ExecuteQueryToFile/Frends.MicrosoftSQL.ExecuteQueryToFile/Enums/FileEncoding.cs +++ b/Frends.MicrosoftSQL.ExecuteQueryToFile/Frends.MicrosoftSQL.ExecuteQueryToFile/Enums/FileEncoding.cs @@ -1,17 +1,17 @@ -namespace Frends.MicrosoftSQL.ExecuteQueryToFile.Enums; - -#pragma warning disable CS1591 // Self-explanatory - -/// -/// File encoding used to encode the file. -/// -public enum FileEncoding -{ - UTF8, - ANSI, - ASCII, - Unicode, - Other, -} - +namespace Frends.MicrosoftSQL.ExecuteQueryToFile.Enums; + +#pragma warning disable CS1591 // Self-explanatory + +/// +/// File encoding used to encode the file. +/// +public enum FileEncoding +{ + UTF8, + ANSI, + ASCII, + Unicode, + Other, +} + #pragma warning restore CS1591 // Self-explanatory \ No newline at end of file diff --git a/Frends.MicrosoftSQL.ExecuteQueryToFile/Frends.MicrosoftSQL.ExecuteQueryToFile/Enums/ReturnFormat.cs b/Frends.MicrosoftSQL.ExecuteQueryToFile/Frends.MicrosoftSQL.ExecuteQueryToFile/Enums/ReturnFormat.cs index f37af8c..4c47233 100644 --- a/Frends.MicrosoftSQL.ExecuteQueryToFile/Frends.MicrosoftSQL.ExecuteQueryToFile/Enums/ReturnFormat.cs +++ b/Frends.MicrosoftSQL.ExecuteQueryToFile/Frends.MicrosoftSQL.ExecuteQueryToFile/Enums/ReturnFormat.cs @@ -1,13 +1,13 @@ -namespace Frends.MicrosoftSQL.ExecuteQueryToFile.Enums; - -#pragma warning disable CS1591 // Self-explanatory - -/// -/// Enumeration for output format. -/// -public enum ReturnFormat -{ - CSV, -} - +namespace Frends.MicrosoftSQL.ExecuteQueryToFile.Enums; + +#pragma warning disable CS1591 // Self-explanatory + +/// +/// Enumeration for output format. +/// +public enum ReturnFormat +{ + CSV, +} + #pragma warning restore CS1591 // Self-explanatory \ No newline at end of file diff --git a/Frends.MicrosoftSQL.ExecuteQueryToFile/Frends.MicrosoftSQL.ExecuteQueryToFile/Frends.MicrosoftSQL.ExecuteQueryToFile.cs b/Frends.MicrosoftSQL.ExecuteQueryToFile/Frends.MicrosoftSQL.ExecuteQueryToFile/Frends.MicrosoftSQL.ExecuteQueryToFile.cs index 1e5d353..2c51983 100644 --- a/Frends.MicrosoftSQL.ExecuteQueryToFile/Frends.MicrosoftSQL.ExecuteQueryToFile/Frends.MicrosoftSQL.ExecuteQueryToFile.cs +++ b/Frends.MicrosoftSQL.ExecuteQueryToFile/Frends.MicrosoftSQL.ExecuteQueryToFile/Frends.MicrosoftSQL.ExecuteQueryToFile.cs @@ -1,6 +1,4 @@ -namespace Frends.MicrosoftSQL.ExecuteQueryToFile; - -using System; +using System; using System.ComponentModel; using System.Data; using System.Threading; @@ -9,6 +7,8 @@ using Frends.MicrosoftSQL.ExecuteQueryToFile.Enums; using Microsoft.Data.SqlClient; +namespace Frends.MicrosoftSQL.ExecuteQueryToFile; + /// /// Main class of the Task. /// @@ -22,45 +22,49 @@ public static class MicrosoftSQL /// Options parameters. /// Cancellation token given by Frends. /// Object { int EntriesWritten, string Path, string FileName } - public static async Task ExecuteQueryToFile([PropertyTab] Input input, [PropertyTab] Options options, CancellationToken cancellationToken) + public static async Task ExecuteQueryToFile( + [PropertyTab] Input input, + [PropertyTab] Options options, + CancellationToken cancellationToken) { Result result = new(); - using (var sqlConnection = new SqlConnection(input.ConnectionString)) - { - await sqlConnection.OpenAsync(cancellationToken); - using var command = sqlConnection.CreateCommand(); - command.CommandTimeout = options.TimeoutSeconds; - command.CommandText = input.Query; - command.CommandType = CommandType.Text; + await using var sqlConnection = new SqlConnection(input.ConnectionString); + await sqlConnection.OpenAsync(cancellationToken).ConfigureAwait(false); + + await using var command = sqlConnection.CreateCommand(); + command.CommandTimeout = options.TimeoutSeconds; + command.CommandText = input.Query; + command.CommandType = CommandType.Text; - if (input.QueryParameters != null) + if (input.QueryParameters != null) + { + foreach (var parameter in input.QueryParameters) { - foreach (var parameter in input.QueryParameters) - { - if (parameter.Value is null) - parameter.Value = DBNull.Value; + parameter.Value ??= DBNull.Value; - if (parameter.SqlDataType is SqlDataTypes.Auto) - { - command.Parameters.AddWithValue(parameterName: parameter.Name, value: parameter.Value); - } - else - { - var sqlDbType = (SqlDbType)Enum.Parse(typeof(SqlDbType), parameter.SqlDataType.ToString()); - var commandParameter = command.Parameters.Add(parameter.Name, sqlDbType); - commandParameter.Value = parameter.Value; - } + if (parameter.SqlDataType is SqlDataTypes.Auto) + { + command.Parameters.AddWithValue(parameterName: parameter.Name, value: parameter.Value); + } + else + { + var sqlDbType = (SqlDbType)Enum.Parse(typeof(SqlDbType), parameter.SqlDataType.ToString()); + var commandParameter = command.Parameters.Add(parameter.Name, sqlDbType); + commandParameter.Value = parameter.Value; } } + } + + switch (options.ReturnFormat) + { + case ReturnFormat.CSV: + { + await using var csvWriter = new CsvFileWriter(command, input, options.CsvOptions); + result = await csvWriter.SaveQueryToCsv(cancellationToken).ConfigureAwait(false); - switch (options.ReturnFormat) - { - case ReturnFormat.CSV: - var csvWriter = new CsvFileWriter(command, input, options.CsvOptions); - result = await csvWriter.SaveQueryToCSV(cancellationToken); break; - } + } } return result; diff --git a/Frends.MicrosoftSQL.ExecuteQueryToFile/Frends.MicrosoftSQL.ExecuteQueryToFile/Frends.MicrosoftSQL.ExecuteQueryToFile.csproj b/Frends.MicrosoftSQL.ExecuteQueryToFile/Frends.MicrosoftSQL.ExecuteQueryToFile/Frends.MicrosoftSQL.ExecuteQueryToFile.csproj index ec6c0bf..0bd3cc0 100644 --- a/Frends.MicrosoftSQL.ExecuteQueryToFile/Frends.MicrosoftSQL.ExecuteQueryToFile/Frends.MicrosoftSQL.ExecuteQueryToFile.csproj +++ b/Frends.MicrosoftSQL.ExecuteQueryToFile/Frends.MicrosoftSQL.ExecuteQueryToFile/Frends.MicrosoftSQL.ExecuteQueryToFile.csproj @@ -3,7 +3,7 @@ net6.0 Latest - 2.1.0 + 2.2.0 Frends Frends Frends