diff --git a/MsSql.ClassGenerator.Cli/Program.cs b/MsSql.ClassGenerator.Cli/Program.cs
index 785fa21..11bc67c 100644
--- a/MsSql.ClassGenerator.Cli/Program.cs
+++ b/MsSql.ClassGenerator.Cli/Program.cs
@@ -1,11 +1,10 @@
-using System.Diagnostics;
-using System.Reflection;
-using MsSql.ClassGenerator.Cli.Model;
+using MsSql.ClassGenerator.Cli.Model;
using MsSql.ClassGenerator.Core.Business;
using MsSql.ClassGenerator.Core.Common;
using MsSql.ClassGenerator.Core.Model;
using Serilog;
-using Serilog.Events;
+using System.Diagnostics;
+using System.Reflection;
namespace MsSql.ClassGenerator.Cli;
@@ -21,6 +20,8 @@ internal static class Program
/// The awaitable task.
private static async Task Main(string[] args)
{
+ await CheckForUpdate();
+
var argResult = args.ExtractArguments(out Arguments arguments);
Helper.InitLog(arguments.LogLevel, true);
@@ -98,4 +99,33 @@ private static void PrintFooterHeader(bool header)
if (header)
Log.Information("Version: {version}", Assembly.GetExecutingAssembly().GetName().Version);
}
+
+ ///
+ /// Checks if an update is available.
+ ///
+ /// The awaitable task.
+ private static async Task CheckForUpdate()
+ {
+ try
+ {
+ await UpdateHelper.LoadReleaseInfoAsync(releaseInfo =>
+ {
+ var updateMessage = $"Update available. New version: {releaseInfo.NewVersion}";
+ const string link = $"Link: {UpdateHelper.GitHupUrl}";
+
+ var maxLength = updateMessage.Length > link.Length ? updateMessage.Length : link.Length;
+
+ var line = "-".PadRight(maxLength + 2, '-'); // Add two for the spacer
+ Console.WriteLine($"+{line}+");
+ Console.WriteLine($"| {updateMessage.PadRight(maxLength, ' ')} |");
+ Console.WriteLine($"| {link.PadRight(maxLength, ' ')} |");
+ Console.WriteLine($"+{line}+");
+ Console.WriteLine();
+ });
+ }
+ catch
+ {
+ // Ignore
+ }
+ }
}
diff --git a/MsSql.ClassGenerator.Core/Business/ClassManager.cs b/MsSql.ClassGenerator.Core/Business/ClassManager.cs
index 84db0d2..98910ef 100644
--- a/MsSql.ClassGenerator.Core/Business/ClassManager.cs
+++ b/MsSql.ClassGenerator.Core/Business/ClassManager.cs
@@ -1,4 +1,6 @@
-using MsSql.ClassGenerator.Core.Common;
+using System.Reflection.Emit;
+using System.Text;
+using MsSql.ClassGenerator.Core.Common;
using MsSql.ClassGenerator.Core.Model;
using Serilog;
@@ -12,7 +14,15 @@ public partial class ClassManager
///
/// Occurs when progress was made.
///
- public event EventHandler? ProgressEvent;
+ public event EventHandler? ProgressEvent;
+
+ ///
+ /// Gets the EF Key code.
+ ///
+ ///
+ /// Note: The code is only generated when the option is set to .
+ ///
+ public EfKeyCodeResult EfKeyCode { get; private set; } = new();
///
/// Generates the classes out of the specified tables according to the specified options.
@@ -23,6 +33,8 @@ public partial class ClassManager
/// Will be thrown when the specified output directory doesn't exist.
public async Task GenerateClassAsync(ClassGeneratorOptions options, List tables)
{
+ EfKeyCode = new EfKeyCodeResult();
+
// Step 0: Check the options.
if (!Directory.Exists(options.Output))
throw new DirectoryNotFoundException($"The specified output ({options.Output}) folder doesn't exist.");
@@ -40,6 +52,10 @@ public async Task GenerateClassAsync(ClassGeneratorOptions options, List
@@ -248,4 +264,70 @@ private static string GetPropertyAttributes(ClassGeneratorOptions options, Colum
return string.Join(Environment.NewLine, attributes.OrderBy(o => o.Key).Select(s => s.Value));
}
+
+ ///
+ /// Generates the EF Key code.
+ ///
+ /// The list with the tables.
+ private void GenerateEfKeyCode(List tables)
+ {
+ // Get all tables which contains more than one key column
+ var tmpTables = tables.Where(w => w.Columns.Count(c => c.IsPrimaryKey) > 1).ToList();
+ if (tmpTables.Count == 0)
+ return;
+
+ var sb = PrepareStringBuilder();
+ var count = 1;
+ foreach (var tableEntry in tmpTables)
+ {
+ // Add the entity
+ sb.AppendLine($"{Tab}modelBuilder.Entity<{tableEntry.ClassName}>().HasKey(k => new")
+ .AppendLine($"{Tab}{{");
+
+ // Get the key columns
+ var columnCount = 1;
+ var columns = tableEntry.Columns.Where(w => w.IsPrimaryKey).ToList();
+ foreach (var columnEntry in columns)
+ {
+ var comma = columnCount++ != columns.Count ? "," : string.Empty;
+
+ sb.AppendLine($"{Tab}{Tab}k.{columnEntry.PropertyName}{comma}");
+ }
+
+ // Add the closing brackets
+ sb.AppendLine($"{Tab}}});");
+
+ if (count++ != tmpTables.Count)
+ sb.AppendLine(); // Spacer
+
+ }
+
+ EfKeyCode = new EfKeyCodeResult
+ {
+ Code = FinalizeStringBuilder(),
+ TableCount = tmpTables.Count
+ };
+
+ return;
+
+ StringBuilder PrepareStringBuilder()
+ {
+ var stringBuilder = new StringBuilder()
+ .AppendLine("/// ")
+ .AppendLine("protected override void OnModelCreating(ModelBuilder modelBuilder)")
+ .AppendLine("{");
+
+ return stringBuilder;
+ }
+
+ // Adds the final code
+ string FinalizeStringBuilder()
+ {
+ sb.AppendLine("}");
+
+ return sb.ToString();
+ }
+ }
+
+
}
\ No newline at end of file
diff --git a/MsSql.ClassGenerator.Core/Business/UpdateHelper.cs b/MsSql.ClassGenerator.Core/Business/UpdateHelper.cs
new file mode 100644
index 0000000..a0db1bc
--- /dev/null
+++ b/MsSql.ClassGenerator.Core/Business/UpdateHelper.cs
@@ -0,0 +1,77 @@
+using MsSql.ClassGenerator.Core.Model;
+using RestSharp;
+using RestSharp.Serializers.NewtonsoftJson;
+using Serilog;
+using System.Reflection;
+
+namespace MsSql.ClassGenerator.Core.Business;
+
+///
+/// Provides the functions for the update.
+///
+public static class UpdateHelper
+{
+ ///
+ /// Contains the URL of the latest release of the app.
+ ///
+ public const string GitHupUrl = "https://github.com/InvaderZim85/MsSql.ClassGenerator/releases/latest";
+
+ ///
+ /// Contains the URL of the latest release for the REST call.
+ ///
+ private const string GitHupApiUrl =
+ "https://api.github.com/repos/InvaderZim85/MsSql.ClassGenerator/releases/latest";
+
+ ///
+ /// Loads the release info of the latest release to determine if there is a new version.
+ ///
+ /// Will be executed when there is a new version.
+ /// The awaitable task.
+ public static async Task LoadReleaseInfoAsync(Action callback)
+ {
+ try
+ {
+ var client = new RestClient(GitHupApiUrl,
+ configureSerialization: s => s.UseNewtonsoftJson());
+
+ client.AddDefaultHeader("accept", "application/vnd.github.v3+json");
+
+ var request = new RestRequest();
+ var response = await client.GetAsync(request);
+
+ // This method also checks if the response is null
+ if (IsNewVersionAvailable(response))
+ callback(response!);
+ }
+ catch (Exception ex)
+ {
+ Log.Warning(ex, "Error while loading the latest release info.");
+ }
+ }
+
+ ///
+ /// Checks if an update is available
+ ///
+ /// The infos of the latest release
+ /// when there is a new version, otherwise
+ private static bool IsNewVersionAvailable(ReleaseInfo? releaseInfo)
+ {
+ if (releaseInfo == null)
+ return false;
+
+ if (!Version.TryParse(releaseInfo.TagName.Replace("v", ""), out var releaseVersion))
+ {
+ Log.Warning("Can't determine version of the latest release. Tag value: {value}", releaseInfo.TagName);
+ return false;
+ }
+
+ var currentVersion = Assembly.GetExecutingAssembly().GetName().Version;
+ if (currentVersion == null)
+ return false;
+
+ releaseInfo.CurrentVersion = currentVersion;
+ releaseInfo.NewVersion = releaseVersion;
+
+ return releaseInfo.UpdateAvailable;
+ }
+}
\ No newline at end of file
diff --git a/MsSql.ClassGenerator.Core/Common/Extensions.cs b/MsSql.ClassGenerator.Core/Common/Extensions.cs
index 1e9be63..dadb166 100644
--- a/MsSql.ClassGenerator.Core/Common/Extensions.cs
+++ b/MsSql.ClassGenerator.Core/Common/Extensions.cs
@@ -118,4 +118,24 @@ public static bool StartsWithNumber(this string value)
{
return !string.IsNullOrWhiteSpace(value) && int.TryParse(value[0].ToString(), out _);
}
+
+ ///
+ /// Converts the value into a readable size
+ ///
+ /// The value
+ /// The divider (optional)
+ /// The converted size
+ public static string ConvertSize(this long value, int divider = 1024)
+ {
+ return value switch
+ {
+ _ when value < divider => $"{value:N0} Bytes",
+ _ when value >= divider && value < Math.Pow(divider, 2) => $"{value / divider:N2} KB",
+ _ when value >= Math.Pow(divider, 2) && value < Math.Pow(divider, 3) =>
+ $"{value / Math.Pow(divider, 2):N2} MB",
+ _ when value >= Math.Pow(divider, 3) && value <= Math.Pow(divider, 4) => $"{value / Math.Pow(divider, 3):N2} GB",
+ _ when value >= Math.Pow(divider, 4) => $"{value / Math.Pow(divider, 4)} TB",
+ _ => value.ToString("N0")
+ };
+ }
}
diff --git a/MsSql.ClassGenerator.Core/Common/Helper.cs b/MsSql.ClassGenerator.Core/Common/Helper.cs
index 9d3456f..2f7f4b8 100644
--- a/MsSql.ClassGenerator.Core/Common/Helper.cs
+++ b/MsSql.ClassGenerator.Core/Common/Helper.cs
@@ -1,6 +1,7 @@
using Newtonsoft.Json;
using Serilog;
using Serilog.Events;
+using System.Diagnostics;
namespace MsSql.ClassGenerator.Core.Common;
@@ -90,4 +91,21 @@ public static List GetModifierList()
"protected internal"
];
}
+
+ ///
+ /// Opens the specified link
+ ///
+ /// The url of the link
+ public static void OpenLink(string url)
+ {
+ try
+ {
+ url = url.Replace("&", "^&");
+ Process.Start(new ProcessStartInfo("cmd", $"/c start {url}") { CreateNoWindow = true });
+ }
+ catch
+ {
+ // Ignore
+ }
+ }
}
diff --git a/MsSql.ClassGenerator.Core/Data/BaseRepo.cs b/MsSql.ClassGenerator.Core/Data/BaseRepo.cs
index db527b5..1cd1572 100644
--- a/MsSql.ClassGenerator.Core/Data/BaseRepo.cs
+++ b/MsSql.ClassGenerator.Core/Data/BaseRepo.cs
@@ -30,7 +30,7 @@ protected SqlConnection GetConnection()
DataSource = server,
IntegratedSecurity = true,
TrustServerCertificate = true,
- ApplicationName = nameof(MsSql.ClassGenerator)
+ ApplicationName = nameof(ClassGenerator)
};
if (!string.IsNullOrWhiteSpace(database))
diff --git a/MsSql.ClassGenerator.Core/Model/Asset.cs b/MsSql.ClassGenerator.Core/Model/Asset.cs
new file mode 100644
index 0000000..8ecd9d3
--- /dev/null
+++ b/MsSql.ClassGenerator.Core/Model/Asset.cs
@@ -0,0 +1,32 @@
+using MsSql.ClassGenerator.Core.Common;
+using Newtonsoft.Json;
+
+namespace MsSql.ClassGenerator.Core.Model;
+
+///
+/// Represents the assets of the last release
+///
+public sealed class Asset
+{
+ ///
+ /// Gets or sets the name of the zip file
+ ///
+ public string Name { get; set; } = string.Empty;
+
+ ///
+ /// Gets or sets the size of the latest release (in bytes)
+ ///
+ public long Size { get; set; }
+
+ ///
+ /// Gets the size of the latest release in a readable format
+ ///
+ [JsonIgnore]
+ public string SizeView => Size.ConvertSize();
+
+ ///
+ /// Gets or sets the url of the release
+ ///
+ [JsonProperty("browser_download_url")]
+ public string DownloadUrl { get; set; } = string.Empty;
+}
\ No newline at end of file
diff --git a/MsSql.ClassGenerator.Core/Model/EfKeyCodeResult.cs b/MsSql.ClassGenerator.Core/Model/EfKeyCodeResult.cs
new file mode 100644
index 0000000..cf795bc
--- /dev/null
+++ b/MsSql.ClassGenerator.Core/Model/EfKeyCodeResult.cs
@@ -0,0 +1,22 @@
+namespace MsSql.ClassGenerator.Core.Model;
+
+///
+/// Provides the key code result.
+///
+public sealed class EfKeyCodeResult
+{
+ ///
+ /// Gets the code.
+ ///
+ public string Code { get; init; } = string.Empty;
+
+ ///
+ /// Gets the amount of tables which contains multiple keys.
+ ///
+ public int TableCount { get; init; }
+
+ ///
+ /// Gets the value which indicates whether the code is empty.
+ ///
+ public bool IsEmpty => string.IsNullOrWhiteSpace(Code);
+}
\ No newline at end of file
diff --git a/MsSql.ClassGenerator.Core/Model/ReleaseInfo.cs b/MsSql.ClassGenerator.Core/Model/ReleaseInfo.cs
new file mode 100644
index 0000000..a57570f
--- /dev/null
+++ b/MsSql.ClassGenerator.Core/Model/ReleaseInfo.cs
@@ -0,0 +1,63 @@
+using Newtonsoft.Json;
+
+namespace MsSql.ClassGenerator.Core.Model;
+
+///
+/// Provides the information of the latest release
+///
+public sealed class ReleaseInfo
+{
+ ///
+ /// Gets or sets the html url of the release
+ ///
+ [JsonProperty("html_url")]
+ public string HtmlUrl { get; set; } = string.Empty;
+
+ ///
+ /// Gets or sets the name of the tag
+ ///
+ [JsonProperty("tag_name")]
+ public string TagName { get; set; } = string.Empty;
+
+ ///
+ /// Gets or sets the name of the release
+ ///
+ public string Name { get; set; } = string.Empty;
+
+ ///
+ /// Gets or sets the publish date of the release
+ ///
+ [JsonProperty("published_at")]
+ public DateTime PublishedAt { get; set; }
+
+ ///
+ /// Gets the published at date as formatted string
+ ///
+ [JsonIgnore]
+ public string PublishedAtView => PublishedAt.ToString("yyyy-MM-dd HH:mm:ss");
+
+ ///
+ /// Gets or sets the body (message) of the release
+ ///
+ public string Body { get; set; } = string.Empty;
+
+ ///
+ /// Gets or sets the with the assets
+ ///
+ public List Assets { get; set; } = [];
+
+ ///
+ /// Gets or sets the number current version
+ ///
+ public Version CurrentVersion { get; set; } = new();
+
+ ///
+ /// Gets or sets the number of the new version
+ ///
+ public Version NewVersion { get; set; } = new();
+
+ ///
+ /// Gets the value which indicates whether a new version is available.
+ ///
+ public bool UpdateAvailable => NewVersion > CurrentVersion;
+}
diff --git a/MsSql.ClassGenerator.Core/MsSql.ClassGenerator.Core.csproj b/MsSql.ClassGenerator.Core/MsSql.ClassGenerator.Core.csproj
index c0cdd14..b883681 100644
--- a/MsSql.ClassGenerator.Core/MsSql.ClassGenerator.Core.csproj
+++ b/MsSql.ClassGenerator.Core/MsSql.ClassGenerator.Core.csproj
@@ -1,11 +1,11 @@
-
+
net9.0-windows
enable
enable
- 25.43.0.756
- 25.43.0.756
- 25.43.0.756
+ 24.43.0.756
+ 24.43.0.756
+ 24.43.0.756
@@ -14,6 +14,8 @@
+
+
diff --git a/MsSql.ClassGenerator/Common/Enums/EntryType.cs b/MsSql.ClassGenerator/Common/Enums/EntryType.cs
new file mode 100644
index 0000000..d482dd6
--- /dev/null
+++ b/MsSql.ClassGenerator/Common/Enums/EntryType.cs
@@ -0,0 +1,17 @@
+namespace MsSql.ClassGenerator.Common.Enums;
+
+///
+/// Provides the different entry types.
+///
+public enum EntryType
+{
+ ///
+ /// Represents a table.
+ ///
+ Table,
+
+ ///
+ /// Represents a column.
+ ///
+ Column
+}
\ No newline at end of file
diff --git a/MsSql.ClassGenerator/Model/TableColumnDto.cs b/MsSql.ClassGenerator/Model/TableColumnDto.cs
index bdcfe0f..cc04601 100644
--- a/MsSql.ClassGenerator/Model/TableColumnDto.cs
+++ b/MsSql.ClassGenerator/Model/TableColumnDto.cs
@@ -1,4 +1,5 @@
using CommunityToolkit.Mvvm.ComponentModel;
+using MsSql.ClassGenerator.Common.Enums;
using MsSql.ClassGenerator.Core.Model;
namespace MsSql.ClassGenerator.Model;
@@ -56,11 +57,21 @@ partial void OnAliasChanged(string value)
[ObservableProperty]
private bool _use = true;
+ ///
+ /// Gets or sets the value which indicates whether the column is part of the key.
+ ///
+ public bool KeyColumn { get; set; }
+
///
/// Gets or sets the original item (table / column)
///
public object? OriginalItem { get; set; }
+ ///
+ /// Gets or sets the type of the entry.
+ ///
+ public EntryType Type { get; }
+
///
/// Gets or sets the list with the columns.
///
@@ -82,18 +93,21 @@ public TableColumnDto(TableEntry table)
Columns = table.Columns.Select(s => new TableColumnDto(s)).ToList();
Use = true;
OriginalItem = table;
+ Type = EntryType.Table;
}
///
/// Creates a new column instance.
///
/// The source column.
- public TableColumnDto(ColumnEntry column)
+ private TableColumnDto(ColumnEntry column)
{
Name = column.Name;
Alias = column.Alias;
Position = column.Order;
Use = true;
OriginalItem = column;
+ Type = EntryType.Column;
+ KeyColumn = column.IsPrimaryKey;
}
}
\ No newline at end of file
diff --git a/MsSql.ClassGenerator/MsSql.ClassGenerator.csproj b/MsSql.ClassGenerator/MsSql.ClassGenerator.csproj
index ea56699..bf39e00 100644
--- a/MsSql.ClassGenerator/MsSql.ClassGenerator.csproj
+++ b/MsSql.ClassGenerator/MsSql.ClassGenerator.csproj
@@ -1,13 +1,13 @@
-
+
WinExe
net9.0-windows
enable
enable
true
- 25.43.0.756
- 25.43.0.756
- 25.43.0.756
+ 24.43.0.756
+ 24.43.0.756
+ 24.43.0.756
x64
icon.ico
@@ -15,10 +15,12 @@
+
+
diff --git a/MsSql.ClassGenerator/Ui/UiHelper.cs b/MsSql.ClassGenerator/Ui/UiHelper.cs
new file mode 100644
index 0000000..fbaf0a0
--- /dev/null
+++ b/MsSql.ClassGenerator/Ui/UiHelper.cs
@@ -0,0 +1,22 @@
+using ICSharpCode.AvalonEdit;
+using System.Windows.Media;
+
+namespace MsSql.ClassGenerator.Ui;
+
+///
+/// Provides several helper methods for the UI.
+///
+internal static class UiHelper
+{
+
+ ///
+ /// Init the avalon editor.
+ ///
+ /// The editor.
+ public static void InitAvalonEditor(this TextEditor editor)
+ {
+ editor.Options.HighlightCurrentLine = true;
+ editor.Options.ConvertTabsToSpaces = true; // We hate tabs...
+ editor.Foreground = new SolidColorBrush(Colors.White);
+ }
+}
\ No newline at end of file
diff --git a/MsSql.ClassGenerator/Ui/View/CodeWindow.xaml b/MsSql.ClassGenerator/Ui/View/CodeWindow.xaml
new file mode 100644
index 0000000..6bfbfe0
--- /dev/null
+++ b/MsSql.ClassGenerator/Ui/View/CodeWindow.xaml
@@ -0,0 +1,60 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/MsSql.ClassGenerator/Ui/View/CodeWindow.xaml.cs b/MsSql.ClassGenerator/Ui/View/CodeWindow.xaml.cs
new file mode 100644
index 0000000..132dc8e
--- /dev/null
+++ b/MsSql.ClassGenerator/Ui/View/CodeWindow.xaml.cs
@@ -0,0 +1,48 @@
+using ICSharpCode.AvalonEdit.Search;
+using MahApps.Metro.Controls;
+using MsSql.ClassGenerator.Ui.ViewModel;
+using System.Windows;
+using MsSql.ClassGenerator.Core.Model;
+
+namespace MsSql.ClassGenerator.Ui.View;
+
+///
+/// Interaction logic for CodeWindow.xaml
+///
+public partial class CodeWindow : MetroWindow
+{
+ ///
+ /// Contains the code which should be shown.
+ ///
+ private readonly EfKeyCodeResult _efKeyCode;
+
+ ///
+ /// Creates a new instance of the .
+ ///
+ /// The ef key code which should be shown.
+ public CodeWindow(EfKeyCodeResult efKeyCode)
+ {
+ InitializeComponent();
+
+ _efKeyCode = efKeyCode;
+ }
+
+ ///
+ /// Occurs when the window was loaded.
+ ///
+ /// The .
+ /// The event arguments.
+ private void CodeWindow_OnLoaded(object sender, RoutedEventArgs e)
+ {
+ // Init the editor
+ CodeEditor.InitAvalonEditor();
+
+ // Add the search option (CTRL + F)
+ SearchPanel.Install(CodeEditor);
+
+ CodeEditor.Text = _efKeyCode.Code;
+
+ if (DataContext is CodeWindowViewModel viewModel)
+ viewModel.InitViewModel(_efKeyCode);
+ }
+}
\ No newline at end of file
diff --git a/MsSql.ClassGenerator/Ui/View/MainWindow.xaml b/MsSql.ClassGenerator/Ui/View/MainWindow.xaml
index dbb3dc6..9775a98 100644
--- a/MsSql.ClassGenerator/Ui/View/MainWindow.xaml
+++ b/MsSql.ClassGenerator/Ui/View/MainWindow.xaml
@@ -23,9 +23,22 @@
+
+
+
+
+
+
-
+
+
@@ -360,6 +373,22 @@
ItemsSource="{Binding Columns}">
+
+
+
+
+
+
+
+
diff --git a/MsSql.ClassGenerator/Ui/View/MainWindow.xaml.cs b/MsSql.ClassGenerator/Ui/View/MainWindow.xaml.cs
index 1ac6776..f45bf02 100644
--- a/MsSql.ClassGenerator/Ui/View/MainWindow.xaml.cs
+++ b/MsSql.ClassGenerator/Ui/View/MainWindow.xaml.cs
@@ -2,6 +2,8 @@
using MsSql.ClassGenerator.Model;
using MsSql.ClassGenerator.Ui.ViewModel;
using System.Windows;
+using Microsoft.VisualStudio.Threading;
+using Serilog;
namespace MsSql.ClassGenerator.Ui.View;
///
@@ -32,7 +34,14 @@ public MainWindow(Arguments arguments)
/// The event arguments.
private void MainWindow_OnLoaded(object sender, RoutedEventArgs e)
{
- if (DataContext is MainWindowViewModel viewModel)
- viewModel.InitViewModel(_arguments);
+ try
+ {
+ if (DataContext is MainWindowViewModel viewModel)
+ viewModel.InitViewModelAsync(_arguments).Forget();
+ }
+ catch (Exception ex)
+ {
+ Log.Error(ex, "Error while initializing the main window.");
+ }
}
}
diff --git a/MsSql.ClassGenerator/Ui/ViewModel/CodeWindowViewModel.cs b/MsSql.ClassGenerator/Ui/ViewModel/CodeWindowViewModel.cs
new file mode 100644
index 0000000..2ceaedd
--- /dev/null
+++ b/MsSql.ClassGenerator/Ui/ViewModel/CodeWindowViewModel.cs
@@ -0,0 +1,48 @@
+using CommunityToolkit.Mvvm.ComponentModel;
+using CommunityToolkit.Mvvm.Input;
+using MsSql.ClassGenerator.Core.Model;
+
+namespace MsSql.ClassGenerator.Ui.ViewModel;
+
+///
+/// Interaction logic for .
+///
+internal sealed partial class CodeWindowViewModel : ViewModelBase
+{
+ ///
+ /// Contains the ef key code.
+ ///
+ private EfKeyCodeResult _efKeyCode = new();
+
+ ///
+ /// Gets or sets the info.
+ ///
+ [ObservableProperty]
+ private string _info = "Info";
+
+ ///
+ /// Init the view model.
+ ///
+ /// The ef key code.
+ public void InitViewModel(EfKeyCodeResult efKeyCode)
+ {
+ _efKeyCode = efKeyCode;
+
+ Info = $"Tables with multiple keys: {efKeyCode.TableCount:N0}";
+ }
+
+ ///
+ /// Occurs when the user hits the copy button.
+ ///
+ ///
+ /// Copies the content of the editor to the clipboard.
+ ///
+ [RelayCommand]
+ private void CopyCode()
+ {
+ if (_efKeyCode.IsEmpty)
+ return;
+
+ CopyToClipboard(_efKeyCode.Code);
+ }
+}
\ No newline at end of file
diff --git a/MsSql.ClassGenerator/Ui/ViewModel/MainWindowViewModel.cs b/MsSql.ClassGenerator/Ui/ViewModel/MainWindowViewModel.cs
index 3c938ec..0e00dce 100644
--- a/MsSql.ClassGenerator/Ui/ViewModel/MainWindowViewModel.cs
+++ b/MsSql.ClassGenerator/Ui/ViewModel/MainWindowViewModel.cs
@@ -1,6 +1,7 @@
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using MahApps.Metro.Controls.Dialogs;
+using Microsoft.VisualStudio.Threading;
using Microsoft.Win32;
using MsSql.ClassGenerator.Business;
using MsSql.ClassGenerator.Common;
@@ -12,6 +13,8 @@
using MsSql.ClassGenerator.Model;
using MsSql.ClassGenerator.Ui.View;
using System.Collections.ObjectModel;
+using System.Reflection;
+using System.Windows;
namespace MsSql.ClassGenerator.Ui.ViewModel;
@@ -31,6 +34,11 @@ internal sealed partial class MainWindowViewModel : ViewModelBase
///
private TableManager? _tableManager;
+ ///
+ /// Contains the generated EF Key Code.
+ ///
+ private EfKeyCodeResult _efKeyCode = new();
+
#endregion
#region Properties
@@ -256,6 +264,36 @@ partial void OnFilterColumnChanged(string value)
[ObservableProperty]
private string _appTitle = AppTitleDefault;
+ ///
+ /// Gets or sets the value which indicates whether the button "Show EF Key Code" should be enabled.
+ ///
+ [ObservableProperty]
+ private bool _buttonShowEfKeyCodeEnabled;
+
+ ///
+ /// Gets or sets the information (connection status).
+ ///
+ [ObservableProperty]
+ private string _info = "Not connected.";
+
+ ///
+ /// Gets or sets the version number.
+ ///
+ [ObservableProperty]
+ private string _versionInfo = "Version";
+
+ ///
+ /// Gets or sets the visibility of the update button.
+ ///
+ [ObservableProperty]
+ private Visibility _buttonUpdateVisibility = Visibility.Hidden;
+
+ ///
+ /// Gets or sets the update info.
+ ///
+ [ObservableProperty]
+ private string _updateInfo = "Update available!";
+
#endregion
#endregion
@@ -264,10 +302,18 @@ partial void OnFilterColumnChanged(string value)
/// Init the view model.
///
/// The provided arguments.
- public async void InitViewModel(Arguments arguments)
+ /// The awaitable task.
+ public async Task InitViewModelAsync(Arguments arguments)
{
try
{
+ // Set the version
+ VersionInfo = $"v{Assembly.GetExecutingAssembly().GetName().Version}";
+
+ // Start the update check
+ CheckUpdate();
+
+ // Load the data
ModifierList = Helper.GetModifierList().ToObservableCollection();
SelectedModifier = ModifierList.FirstOrDefault() ?? "public";
@@ -385,7 +431,7 @@ private async Task ConnectAsync()
if (SelectedServer.AutoConnect)
await SelectAsync();
- SetAppTitle();
+ SetAppInfo();
}
catch (Exception ex)
{
@@ -428,7 +474,7 @@ private async Task SelectAsync()
FilterTables();
- SetAppTitle();
+ SetAppInfo();
IsConnected = true;
}
@@ -602,12 +648,15 @@ private void FilterColumns()
/// The observable collection
private static ObservableCollection FilterValues(List source, string filter)
{
- return string.IsNullOrWhiteSpace(filter)
- ? source.ToObservableCollection()
- : source.Where(w => w.Name.Contains(filter, StringComparison.InvariantCultureIgnoreCase) ||
+ var tmpList = string.IsNullOrWhiteSpace(filter)
+ ? source
+ : [.. source.Where(w => w.Name.Contains(filter, StringComparison.InvariantCultureIgnoreCase) ||
(!string.IsNullOrWhiteSpace(w.Schema) && w.Schema.Contains(filter,
- StringComparison.InvariantCultureIgnoreCase)))
- .ToObservableCollection();
+ StringComparison.InvariantCultureIgnoreCase)))];
+
+ return tmpList.FirstOrDefault()?.Type == EntryType.Table
+ ? tmpList.OrderBy(o => o.Name).ToObservableCollection()
+ : tmpList.OrderBy(o => o.Position).ToObservableCollection();
}
#endregion
@@ -662,6 +711,8 @@ private static void SetSelection(IEnumerable source, SelectionTy
[RelayCommand]
private async Task GenerateClassesAsync()
{
+ ButtonShowEfKeyCodeEnabled = false;
+
if (!ValidateInput(out var errorMessage))
{
await ShowMessageAsync("Generation", errorMessage);
@@ -683,6 +734,9 @@ private async Task GenerateClassesAsync()
// Save the current options
await SaveOptionsAsync(options);
+
+ ButtonShowEfKeyCodeEnabled = !_efKeyCode.IsEmpty;
+ _efKeyCode = classManager.EfKeyCode;
}
catch (Exception ex)
{
@@ -694,6 +748,26 @@ private async Task GenerateClassesAsync()
}
}
+ ///
+ /// Occurs when the user hits the "Show EF Key Code" button.
+ ///
+ ///
+ /// Opens the code window with the generated code.
+ ///
+ [RelayCommand]
+ private void ShowEfKeyCode()
+ {
+ if (_efKeyCode.IsEmpty)
+ return;
+
+ var codeWindow = new CodeWindow(_efKeyCode)
+ {
+ Owner = GetMainWindow()
+ };
+
+ codeWindow.ShowDialog();
+ }
+
///
/// Validates the input.
///
@@ -767,6 +841,21 @@ private static async Task SaveOptionsAsync(ClassGeneratorOptions options)
}
#endregion
+ #region Various
+
+ ///
+ /// Occurs when the user hits the update button (title bar).
+ ///
+ ///
+ /// Opens the GitHub page with the latest version.
+ ///
+ [RelayCommand]
+ private static void OpenGitHubPage()
+ {
+ Helper.OpenLink(UpdateHelper.GitHupUrl);
+ }
+ #endregion
+
#endregion
#region Various
@@ -774,17 +863,18 @@ private static async Task SaveOptionsAsync(ClassGeneratorOptions options)
///
/// Sets the app title.
///
- private void SetAppTitle()
+ private void SetAppInfo()
{
- var tmpName = AppTitleDefault;
+ var info = string.Empty;
if (SelectedServer != null)
- tmpName += $" - Server: '{SelectedServer.Name}'";
+ info += $"Server: '{SelectedServer.Name}'";
if (!string.IsNullOrEmpty(SelectedDatabase))
- tmpName += $" | Database: '{SelectedDatabase}'";
+ info += $" | Database: '{SelectedDatabase}'";
- AppTitle = tmpName;
+ AppTitle = $"{AppTitleDefault} - {info}";
+ Info = $"Connected - {info}";
}
///
@@ -797,5 +887,27 @@ private void Reset()
Columns.Clear();
Tables.Clear();
}
+
+ ///
+ /// Checks if a new version is available
+ ///
+ private void CheckUpdate()
+ {
+ // The "Forget()" method is used to let the async task run without waiting.
+ // More information: https://docs.microsoft.com/en-us/answers/questions/186037/taskrun-without-wait.html
+ // To use "Forget" you need the following nuget package: https://www.nuget.org/packages/Microsoft.VisualStudio.Threading/
+ UpdateHelper.LoadReleaseInfoAsync(SetReleaseInfo).Forget();
+ }
+
+ ///
+ /// Sets the release info and shows the update button
+ ///
+ /// The infos of the latest release
+ private void SetReleaseInfo(ReleaseInfo releaseInfo)
+ {
+ ButtonUpdateVisibility = !string.IsNullOrWhiteSpace(releaseInfo.Name) ? Visibility.Visible : Visibility.Hidden;
+ UpdateInfo = $"Update available! New version: v{releaseInfo.NewVersion}";
+ }
+
#endregion
}