diff --git a/I18N Commander/Processor/SectionProcessor.cs b/I18N Commander/Processor/SectionProcessor.cs
index 7dd6799..7b291b7 100644
--- a/I18N Commander/Processor/SectionProcessor.cs
+++ b/I18N Commander/Processor/SectionProcessor.cs
@@ -1,6 +1,7 @@
using DataModel.Database;
using DataModel.Database.Common;
using Microsoft.EntityFrameworkCore;
+using Microsoft.Extensions.DependencyInjection;
namespace Processor;
@@ -9,16 +10,24 @@ public static class SectionProcessor
///
/// Load one layer of the tree by using the specified depth:
///
- public static IAsyncEnumerable LoadLayer(DataContext db, int depth)
+ public static async Task> LoadLayer(int depth)
{
- return db.Sections.Where(n => n.Depth == depth).OrderBy(n => n.Id).AsAsyncEnumerable();
+ await using var db = ProcessorMeta.ServiceProvider.GetRequiredService();
+ var sections = await db.Sections.Where(n => n.Depth == depth).OrderBy(n => n.Id).ToListAsync();
+
+ // Ensure, that the database loaded the section's parent:
+ foreach (var section in sections)
+ await db.Entry(section).Reference(n => n.Parent).LoadAsync();
+
+ return sections;
}
///
/// Determine how deep the tree is.
///
- public static async ValueTask GetDepth(DataContext db)
+ public static async ValueTask GetDepth()
{
+ await using var db = ProcessorMeta.ServiceProvider.GetRequiredService();
if(!await db.Sections.AnyAsync())
{
return 0;
@@ -30,8 +39,10 @@ public static class SectionProcessor
///
/// Compute the new sections key and its depth, then store the section in the database.
///
- public static async Task> AddSection(DataContext db, string text, string? parentKey)
+ public static async Task> AddSection(string text, string? parentKey)
{
+ await using var db = ProcessorMeta.ServiceProvider.GetRequiredService();
+
// Remove any whitespaces from the section name, regardless of how many e.g. spaces the user typed:
var key = string.Join('_', text.Split(' ', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries)).ToUpperInvariant();
@@ -97,24 +108,32 @@ public static class SectionProcessor
}
}
- public static async Task RemoveSection(DataContext db, string selectedKey)
+ public static async Task RemoveSection(string selectedKey)
+ {
+ await using var db = ProcessorMeta.ServiceProvider.GetRequiredService();
+ await SectionProcessor.RemoveOneSectionAndItsChildren(db, selectedKey);
+ await db.SaveChangesAsync();
+ }
+
+ private static async Task RemoveOneSectionAndItsChildren(DataContext db, string selectedKey)
{
// Remove the section from the database:
var section2Delete = await db.Sections.FirstOrDefaultAsync(n => n.DataKey == selectedKey);
if (section2Delete is null)
throw new ArgumentException($"The section with key {selectedKey} does not exist in the database.");
-
+
// Next, remove all children of the section, and the children's children, etc.:
var children = await db.Sections.Where(n => n.Parent == section2Delete).ToListAsync();
foreach (var child in children)
- await RemoveSection(db, child.DataKey);
+ await SectionProcessor.RemoveOneSectionAndItsChildren(db, child.DataKey);
db.Sections.Remove(section2Delete);
- await db.SaveChangesAsync();
}
-
- public static async Task NumberChildren(DataContext db, string selectedKey)
+
+ public static async Task NumberChildren(string selectedKey)
{
+ await using var db = ProcessorMeta.ServiceProvider.GetRequiredService();
+
// Read the section from the database:
var section = await db.Sections.FirstOrDefaultAsync(n => n.DataKey == selectedKey);
if (section is null)
@@ -123,8 +142,10 @@ public static class SectionProcessor
return await db.Sections.CountAsync(n => n.Parent == section);
}
- public static async Task> RenameSection(DataContext db, string selectedNodeKey, string alteredName)
+ public static async Task> RenameSection(string selectedNodeKey, string alteredName)
{
+ await using var db = ProcessorMeta.ServiceProvider.GetRequiredService();
+
// Read the section from the database:
var section = await db.Sections.FirstOrDefaultAsync(n => n.DataKey == selectedNodeKey);
if (section is null)
@@ -158,10 +179,18 @@ public static class SectionProcessor
}
}
- public static Section GetSection(DataContext db, string sectionKey) => db.Sections.First(n => n.DataKey == sectionKey);
-
- public static async Task GetSectionPath(DataContext db, string sectionKey)
+ public static async Task GetSection(string sectionKey)
{
+ await using var db = ProcessorMeta.ServiceProvider.GetRequiredService();
+ var section = await db.Sections.FirstAsync(n => n.DataKey == sectionKey);
+ await db.Entry(section).Reference(n => n.Parent).LoadAsync();
+
+ return section;
+ }
+
+ public static async Task GetSectionPath(string sectionKey)
+ {
+ await using var db = ProcessorMeta.ServiceProvider.GetRequiredService();
var section = await db.Sections.FirstAsync(n => n.DataKey == sectionKey);
// Ensure, that the database loaded the section's parent:
diff --git a/I18N Commander/Processor/TextElementProcessor.cs b/I18N Commander/Processor/TextElementProcessor.cs
index 1d31532..82a4718 100644
--- a/I18N Commander/Processor/TextElementProcessor.cs
+++ b/I18N Commander/Processor/TextElementProcessor.cs
@@ -1,18 +1,22 @@
using DataModel.Database;
using DataModel.Database.Common;
using Microsoft.EntityFrameworkCore;
+using Microsoft.Extensions.DependencyInjection;
namespace Processor;
public static class TextElementProcessor
{
- public static Task> GetTextElements(DataContext db, Section section)
+ public static async Task> GetTextElements(Section section)
{
- return Task.FromResult(db.TextElements.Where(n => n.Section == section).AsAsyncEnumerable());
+ await using var db = ProcessorMeta.ServiceProvider.GetRequiredService();
+ return await db.TextElements.Where(n => n.Section == section).ToListAsync();
}
- public static async Task> AddTextElement(DataContext db, string? currentSectionKey, string elementName)
+ public static async Task> AddTextElement(string? currentSectionKey, string elementName)
{
+ await using var db = ProcessorMeta.ServiceProvider.GetRequiredService();
+
if(string.IsNullOrWhiteSpace(currentSectionKey))
throw new ArgumentOutOfRangeException(nameof(currentSectionKey));
diff --git a/I18N Commander/UI WinForms/Components/SectionTree.cs b/I18N Commander/UI WinForms/Components/SectionTree.cs
index 41fc3c3..308a38c 100644
--- a/I18N Commander/UI WinForms/Components/SectionTree.cs
+++ b/I18N Commander/UI WinForms/Components/SectionTree.cs
@@ -1,6 +1,4 @@
-using DataModel.Database.Common;
-using Microsoft.Extensions.DependencyInjection;
-using Processor;
+using Processor;
using UI_WinForms.Dialogs;
using UI_WinForms.Resources;
@@ -8,8 +6,6 @@ namespace UI_WinForms.Components;
public partial class SectionTree : UserControl
{
- private readonly DataContext db;
-
public SectionTree()
{
this.InitializeComponent();
@@ -18,12 +14,6 @@ public partial class SectionTree : UserControl
if(Program.SERVICE_PROVIDER is null)
return;
- // Get the DI context from the main form:
- this.db = Program.SERVICE_PROVIDER.GetService()!;
-
- // Dispose of the context when the control is disposed:
- this.Disposed += (_, _) => this.db.Dispose();
-
// Create an image list from a resource:
var imgList = new ImageList();
imgList.ImageSize = new Size(45, 45);
@@ -46,7 +36,7 @@ public partial class SectionTree : UserControl
var treeNodes = new Dictionary();
// Get the max. depth of the tree:
- var maxDepth = await SectionProcessor.GetDepth(this.db);
+ var maxDepth = await SectionProcessor.GetDepth();
// Store nodes, where we cannot find the parents:
var missingParents = new List();
@@ -54,7 +44,7 @@ public partial class SectionTree : UserControl
// Populate the tree view out of the database, layer by layer:
for (var i = 0; i <= maxDepth; i++)
{
- await foreach (var section in SectionProcessor.LoadLayer(this.db, i))
+ foreach (var section in await SectionProcessor.LoadLayer(i))
{
// Create the tree node:
var node = new TreeNode
@@ -139,7 +129,7 @@ public partial class SectionTree : UserControl
var selectedNode = this.treeView.SelectedNode;
// Add the new section to the database:
- var addedSection = await SectionProcessor.AddSection(this.db, result.Text, addRootNode ? null : selectedNode?.Name);
+ var addedSection = await SectionProcessor.AddSection(result.Text, addRootNode ? null : selectedNode?.Name);
addedSection.ProcessError();
if(!addedSection.Successful)
@@ -173,7 +163,7 @@ public partial class SectionTree : UserControl
// Get the number of children:
// (notice, that the node's name is its key)
- var numberChildren = await SectionProcessor.NumberChildren(this.db, selectedNode.Name);
+ var numberChildren = await SectionProcessor.NumberChildren(selectedNode.Name);
// Ask the user, if he really wants to remove the section:
if(MessageBox.Show(numberChildren > 0 ? $"Are you sure, you want to remove the section '{selectedNode.Text}', its {numberChildren} children and so on?" : $"Are you sure, you want to remove the section '{selectedNode.Text}'?", "Remove section", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) == DialogResult.No)
@@ -181,7 +171,7 @@ public partial class SectionTree : UserControl
// Remove the section from the database:
// (notice, that the node's name is its key)
- await SectionProcessor.RemoveSection(this.db, selectedNode.Name);
+ await SectionProcessor.RemoveSection(selectedNode.Name);
// Remove all nodes from the tree control:
this.treeView.Nodes.Clear();
@@ -190,7 +180,7 @@ public partial class SectionTree : UserControl
this.LoadNodes(this, EventArgs.Empty);
}
- private void treeView_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
+ private async void treeView_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
{
if(this.DesignMode)
return;
@@ -205,7 +195,7 @@ public partial class SectionTree : UserControl
if (selectedNode is not null)
{
// Get the section from the database:
- var section = SectionProcessor.GetSection(this.db, selectedNode.Name);
+ var section = await SectionProcessor.GetSection(selectedNode.Name);
AppEvents.SectionChanged(section);
}
}
@@ -235,7 +225,7 @@ public partial class SectionTree : UserControl
return;
// Rename the section:
- var alteredSection = await SectionProcessor.RenameSection(this.db, selectedNode.Name, result.Text);
+ var alteredSection = await SectionProcessor.RenameSection(selectedNode.Name, result.Text);
alteredSection.ProcessError();
if(!alteredSection.Successful)
diff --git a/I18N Commander/UI WinForms/Components/TextElements.cs b/I18N Commander/UI WinForms/Components/TextElements.cs
index 24ad44f..081fb1f 100644
--- a/I18N Commander/UI WinForms/Components/TextElements.cs
+++ b/I18N Commander/UI WinForms/Components/TextElements.cs
@@ -1,6 +1,4 @@
using DataModel.Database;
-using DataModel.Database.Common;
-using Microsoft.Extensions.DependencyInjection;
using Processor;
using UI_WinForms.Dialogs;
@@ -8,8 +6,6 @@ namespace UI_WinForms.Components;
public partial class TextElements : UserControl
{
- private readonly DataContext db;
-
private Section? currentSection;
public TextElements()
@@ -20,12 +16,6 @@ public partial class TextElements : UserControl
if(Program.SERVICE_PROVIDER is null)
return;
- // Get the DI context from the main form:
- this.db = Program.SERVICE_PROVIDER.GetService()!;
-
- // Dispose of the context when the control is disposed:
- this.Disposed += (_, _) => this.db.Dispose();
-
// When the section is changed, update this component:
AppEvents.WhenSectionChanged += async (sender, section) =>
{
@@ -36,7 +26,7 @@ public partial class TextElements : UserControl
if (this.currentSection is null)
return;
- this.labelSectionPath.Text = await SectionProcessor.GetSectionPath(this.db, this.currentSection.DataKey);
+ this.labelSectionPath.Text = await SectionProcessor.GetSectionPath(this.currentSection.DataKey);
this.LoadTextElements();
};
}
@@ -48,11 +38,11 @@ public partial class TextElements : UserControl
return;
// Load the text elements:
- var textElements = await TextElementProcessor.GetTextElements(this.db, this.currentSection);
+ var textElements = await TextElementProcessor.GetTextElements(this.currentSection);
// Update the list:
this.listTextElements.Items.Clear();
- await foreach (var textElement in textElements)
+ foreach (var textElement in textElements)
{
var item = new ListViewItem(textElement.Name)
{
@@ -79,7 +69,7 @@ public partial class TextElements : UserControl
return;
// Add the text element to the database into the current section:
- var newTextElement = await TextElementProcessor.AddTextElement(this.db, this.currentSection?.DataKey, result.Text);
+ var newTextElement = await TextElementProcessor.AddTextElement(this.currentSection?.DataKey, result.Text);
newTextElement.ProcessError();
if(!newTextElement.Successful)
diff --git a/I18N Commander/UI WinForms/Program.cs b/I18N Commander/UI WinForms/Program.cs
index a26755f..e871b6e 100644
--- a/I18N Commander/UI WinForms/Program.cs
+++ b/I18N Commander/UI WinForms/Program.cs
@@ -2,6 +2,7 @@ using DataModel;
using DataModel.Database.Common;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
+using Processor;
namespace UI_WinForms;
@@ -34,9 +35,6 @@ internal static class Program
//
builder.ConfigureServices((hostContext, serviceCollection) =>
{
- // The main form:
- serviceCollection.AddSingleton();
-
// The database:
serviceCollection.AddDatabase(loader.DataFile, true);
});
@@ -50,15 +48,15 @@ internal static class Program
// Get a service provider:
SERVICE_PROVIDER = scope.ServiceProvider;
+ // Set the service provider to the processor:
+ ProcessorMeta.ServiceProvider = SERVICE_PROVIDER;
+
// Apply database migrations:
using (var database = SERVICE_PROVIDER.GetRequiredService())
Setup.PerformDataMigration(database).Wait();
- // Create the main window:
- var mainWindow = SERVICE_PROVIDER.GetService();
-
// Start the app:
- Application.Run(mainWindow);
+ Application.Run(new Main());
}
}
}
\ No newline at end of file