QueryWindow: Allow users to export query result to csv file
All checks were successful
Test / Run tests (push) Successful in 1m47s
All checks were successful
Test / Run tests (push) Successful in 1m47s
This commit is contained in:
@@ -15,7 +15,9 @@ namespace Elwig.Helpers.Export {
|
|||||||
protected readonly char Separator;
|
protected readonly char Separator;
|
||||||
protected string? Header;
|
protected string? Header;
|
||||||
|
|
||||||
public Csv(string filename, char separator = ';') : this(filename, separator, Utils.UTF8) { }
|
public Csv(string filename, char separator = ';') :
|
||||||
|
this(filename, separator, Utils.UTF8) {
|
||||||
|
}
|
||||||
|
|
||||||
public Csv(string filename, char separator, Encoding encoding) {
|
public Csv(string filename, char separator, Encoding encoding) {
|
||||||
_writer = new StreamWriter(filename, false, encoding);
|
_writer = new StreamWriter(filename, false, encoding);
|
||||||
@@ -58,4 +60,22 @@ namespace Elwig.Helpers.Export {
|
|||||||
|
|
||||||
public abstract string FormatRow(T row);
|
public abstract string FormatRow(T row);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class CsvSimple : Csv<IEnumerable<object?>> {
|
||||||
|
|
||||||
|
public CsvSimple(string filename, char separator, Encoding encoding) :
|
||||||
|
base(filename, separator, encoding) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public CsvSimple(string filename, char separator = ';') :
|
||||||
|
base(filename, separator) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string FormatRow(IEnumerable<object?> row) {
|
||||||
|
return string.Join(Separator, row.Select(i => {
|
||||||
|
var str = $"{i}";
|
||||||
|
return str.Contains(Separator) || str.Contains('\n') ? $"\"{str.Replace("\"", "\"\"")}\"" : str;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ namespace Elwig.Helpers {
|
|||||||
public static partial class Utils {
|
public static partial class Utils {
|
||||||
|
|
||||||
public static readonly Encoding UTF8 = new UTF8Encoding(false, true);
|
public static readonly Encoding UTF8 = new UTF8Encoding(false, true);
|
||||||
|
public static readonly Encoding UTF8BOM = new UTF8Encoding(true, true);
|
||||||
public static readonly JsonSerializerOptions JsonOpts = new() { Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping };
|
public static readonly JsonSerializerOptions JsonOpts = new() { Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping };
|
||||||
|
|
||||||
public static int CurrentYear => DateTime.Now.Year;
|
public static int CurrentYear => DateTime.Now.Year;
|
||||||
|
|||||||
@@ -5,27 +5,35 @@
|
|||||||
Title="Datenbankabfragen - Elwig" Height="450" Width="800" MinWidth="400" MinHeight="300">
|
Title="Datenbankabfragen - Elwig" Height="450" Width="800" MinWidth="400" MinHeight="300">
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="1*" MinHeight="100"/>
|
|
||||||
<RowDefinition Height="5"/>
|
<RowDefinition Height="5"/>
|
||||||
<RowDefinition Height="3*" MinHeight="100"/>
|
<RowDefinition Height="1*" MinHeight="50"/>
|
||||||
|
<RowDefinition Height="5"/>
|
||||||
|
<RowDefinition Height="1*" MinHeight="50"/>
|
||||||
|
<RowDefinition Height="5"/>
|
||||||
|
<RowDefinition Height="6*" MinHeight="100"/>
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
<TextBox x:Name="QueryInput" Text="SELECT * FROM v_delivery"
|
<TextBox x:Name="QueryInput" Text="SELECT * FROM v_member" Grid.Row="1" Grid.RowSpan="3"
|
||||||
AcceptsReturn="True" VerticalScrollBarVisibility="Visible" TextWrapping="Wrap"
|
AcceptsReturn="True" VerticalScrollBarVisibility="Visible" TextWrapping="Wrap"
|
||||||
HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="10,10,120,5"
|
HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="10,5,120,5"
|
||||||
FontFamily="Cascadia Code Light" FontSize="13">
|
FontFamily="Cascadia Code Light" FontSize="13">
|
||||||
<TextBox.InputBindings>
|
<TextBox.InputBindings>
|
||||||
<KeyBinding Key="Return" Modifiers="Control" Command="{Binding EnterCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:QueryWindow}}}" />
|
<KeyBinding Key="Return" Modifiers="Control" Command="{Binding EnterCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:QueryWindow}}}" />
|
||||||
|
<KeyBinding Key="S" Modifiers="Control" Command="{Binding SaveCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:QueryWindow}}}" />
|
||||||
</TextBox.InputBindings>
|
</TextBox.InputBindings>
|
||||||
</TextBox>
|
</TextBox>
|
||||||
<Button x:Name="QueryButton" Content="Abfragen"
|
<Button x:Name="QueryButton" Content="Abfragen" Grid.Row="1"
|
||||||
HorizontalAlignment="Right" VerticalAlignment="Stretch" Margin="10,10,10,5"
|
HorizontalAlignment="Right" VerticalAlignment="Stretch" Margin="10,5,10,0"
|
||||||
Click="QueryButton_Click" Width="100"
|
Click="QueryButton_Click" Width="100"
|
||||||
FontSize="14"/>
|
FontSize="14"/>
|
||||||
|
<Button x:Name="SaveButton" Content="Speichern" Grid.Row="3"
|
||||||
|
HorizontalAlignment="Right" VerticalAlignment="Stretch" Margin="10,0,10,5"
|
||||||
|
Click="SaveButton_Click" Width="100"
|
||||||
|
FontSize="14"/>
|
||||||
|
|
||||||
<GridSplitter Grid.Row="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
|
<GridSplitter Grid.Row="4" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
|
||||||
|
|
||||||
<DataGrid x:Name="DataList" Grid.Row="2"
|
<DataGrid x:Name="DataList" Grid.Row="5"
|
||||||
AutoGenerateColumns="False" HeadersVisibility="Column" IsReadOnly="True" GridLinesVisibility="None" SelectionMode="Extended"
|
AutoGenerateColumns="False" HeadersVisibility="Column" IsReadOnly="True" GridLinesVisibility="None" SelectionMode="Extended"
|
||||||
CanUserDeleteRows="False" CanUserResizeRows="False" CanUserAddRows="False"
|
CanUserDeleteRows="False" CanUserResizeRows="False" CanUserAddRows="False"
|
||||||
HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="10,5,10,10"/>
|
HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="10,5,10,10"/>
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
using Elwig.Helpers;
|
using Elwig.Helpers;
|
||||||
|
using Elwig.Helpers.Export;
|
||||||
|
using Microsoft.Win32;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Data.Common;
|
using System.Data.Common;
|
||||||
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
@@ -13,7 +16,12 @@ namespace Elwig.Windows {
|
|||||||
|
|
||||||
private ICommand? _enterCommand;
|
private ICommand? _enterCommand;
|
||||||
public ICommand EnterCommand => _enterCommand ??= new ActionCommand(async () => {
|
public ICommand EnterCommand => _enterCommand ??= new ActionCommand(async () => {
|
||||||
await ExecuteQuery();
|
await DisplayQuery();
|
||||||
|
});
|
||||||
|
|
||||||
|
private ICommand? _saveCommand;
|
||||||
|
public ICommand SaveCommand => _saveCommand ??= new ActionCommand(async () => {
|
||||||
|
await SaveQuery();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@@ -22,33 +30,45 @@ namespace Elwig.Windows {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async void QueryButton_Click(object sender, RoutedEventArgs evt) {
|
private async void QueryButton_Click(object sender, RoutedEventArgs evt) {
|
||||||
await ExecuteQuery();
|
await DisplayQuery();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task ExecuteQuery() {
|
private async void SaveButton_Click(object sender, RoutedEventArgs evt) {
|
||||||
|
await SaveQuery();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task DisplayQuery() {
|
||||||
try {
|
try {
|
||||||
await ExecuteQuery(QueryInput.Text);
|
Mouse.OverrideCursor = Cursors.Wait;
|
||||||
|
await DisplayQuery(QueryInput.Text);
|
||||||
|
Mouse.OverrideCursor = null;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
Mouse.OverrideCursor = null;
|
||||||
MessageBox.Show(e.Message, "Fehler beim Ausführen", MessageBoxButton.OK, MessageBoxImage.Error);
|
MessageBox.Show(e.Message, "Fehler beim Ausführen", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task ExecuteQuery(string sqlQuery) {
|
private async Task SaveQuery() {
|
||||||
var rows = new List<object[]>();
|
await SaveQuery(QueryInput.Text);
|
||||||
IList<DbColumn> header;
|
}
|
||||||
|
|
||||||
using (var cnx = await AppDbContext.ConnectAsync()) {
|
private static async Task<(IList<DbColumn>, IEnumerable<object[]>)> ExecuteQuery(string sqlQuery) {
|
||||||
|
var rows = new List<object[]>();
|
||||||
|
using var cnx = await AppDbContext.ConnectAsync();
|
||||||
using var cmd = cnx.CreateCommand();
|
using var cmd = cnx.CreateCommand();
|
||||||
cmd.CommandText = sqlQuery;
|
cmd.CommandText = sqlQuery;
|
||||||
using var reader = await cmd.ExecuteReaderAsync();
|
using var reader = await cmd.ExecuteReaderAsync();
|
||||||
header = await reader.GetColumnSchemaAsync();
|
var header = await reader.GetColumnSchemaAsync();
|
||||||
while (await reader.ReadAsync()) {
|
while (await reader.ReadAsync()) {
|
||||||
var values = new object[reader.FieldCount];
|
var values = new object[reader.FieldCount];
|
||||||
reader.GetValues(values);
|
reader.GetValues(values);
|
||||||
rows.Add(values);
|
rows.Add(values);
|
||||||
}
|
}
|
||||||
|
return (header, rows);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task DisplayQuery(string sqlQuery) {
|
||||||
|
var (header, rows) = await ExecuteQuery(sqlQuery);
|
||||||
var styleRight = new Style();
|
var styleRight = new Style();
|
||||||
styleRight.Setters.Add(new Setter(TextBlock.TextAlignmentProperty, TextAlignment.Right));
|
styleRight.Setters.Add(new Setter(TextBlock.TextAlignmentProperty, TextAlignment.Right));
|
||||||
|
|
||||||
@@ -63,5 +83,27 @@ namespace Elwig.Windows {
|
|||||||
}
|
}
|
||||||
DataList.ItemsSource = rows;
|
DataList.ItemsSource = rows;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static async Task SaveQuery(string sqlQuery) {
|
||||||
|
var d = new SaveFileDialog() {
|
||||||
|
FileName = $"Abfrage.csv",
|
||||||
|
DefaultExt = "csv",
|
||||||
|
Filter = "CSV-Datei (*.csv)|*.csv",
|
||||||
|
Title = $"Datenbank Abfrage speichern unter - Elwig"
|
||||||
|
};
|
||||||
|
if (d.ShowDialog() == true) {
|
||||||
|
Mouse.OverrideCursor = Cursors.Wait;
|
||||||
|
await Task.Run(async () => {
|
||||||
|
try {
|
||||||
|
var (header, rows) = await ExecuteQuery(sqlQuery);
|
||||||
|
using var csv = new CsvSimple(d.FileName, ';', Utils.UTF8BOM);
|
||||||
|
await csv.ExportAsync(rows.Prepend([.. header.Select(h => h.ColumnName)]));
|
||||||
|
} catch (Exception exc) {
|
||||||
|
MessageBox.Show(exc.Message, "Fehler beim Ausführen", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Mouse.OverrideCursor = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user