diff --git a/I18N Commander/DataModel/Database/Common/DataContext.cs b/I18N Commander/DataModel/Database/Common/DataContext.cs
index 3cfa6dd..0f46a50 100644
--- a/I18N Commander/DataModel/Database/Common/DataContext.cs
+++ b/I18N Commander/DataModel/Database/Common/DataContext.cs
@@ -1,4 +1,5 @@
-using System.Text.Json;
+using System.Linq.Expressions;
+using System.Text.Json;
using System.Text.Json.Serialization;
using Microsoft.EntityFrameworkCore;
@@ -151,6 +152,7 @@ public sealed class DataContext : DbContext, IDataContext
/// When false, exclude sensitive data from export.
public async Task ExportAsync(string path, bool includeSensitiveData = false)
{
+ Console.WriteLine("Exporting database to JSON file...");
var jsonSettings = new JsonSerializerOptions
{
WriteIndented = true,
@@ -176,19 +178,32 @@ public sealed class DataContext : DbContext, IDataContext
}
}
+ // Use a local reference to the database to use it in the lambda expression trees below:
+ // (we cannot use "this" in a lambda expression tree; yields an exception at runtime)
+ var db = this;
+
await using var fileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None);
await JsonSerializer.SerializeAsync(fileStream,
new JsonData
{
+ // Settings don't have references to other entities; we can just use them here:
Settings = includeSensitiveData ?
// Include all settings, including sensitive data:
this.Settings.OrderBy(n => n.UniqueId).Select(n => n.ToJsonSetting()).ToList() :
// Exclude sensitive data:
FilterSensitiveSettings(this.Settings.OrderBy(n => n.UniqueId).Select(n => n.ToJsonSetting()).AsEnumerable()).ToList(),
- Sections = this.Sections.OrderBy(n => n.UniqueId).Select(n => n.ToJsonSection()).ToList(),
+
+ // Warning: the parents cannot pre-loaded, thus, we must load them now inside the lambda expression tree:
+ Sections = this.Sections.OrderBy(n => n.UniqueId).Select(n => n.ToJsonSection(db)).ToList(),
+
+ // All text elements references are pre-loaded, so we can use them here:
TextElements = this.TextElements.OrderBy(n => n.UniqueId).Select(n => n.ToJsonTextElement()).ToList(),
+
+ // All translation references are pre-loaded, so we can use them here:
Translations = this.Translations.OrderBy(n => n.UniqueId).Select(n => n.ToJsonTranslation()).ToList(),
}, jsonSettings);
+
+ Console.WriteLine("Export complete.");
}
///
@@ -211,6 +226,8 @@ public sealed class DataContext : DbContext, IDataContext
await this.TextElements.AnyAsync() ||
await this.Translations.AnyAsync())
throw new InvalidOperationException("The database is not empty. In order to import data, the database must be empty.");
+
+ Console.WriteLine("Start importing data from JSON file...");
// Start a transaction:
await using var transaction = await this.Database.BeginTransactionAsync();
@@ -244,6 +261,8 @@ public sealed class DataContext : DbContext, IDataContext
{
// Convert the next element:
var nextSection = Section.FromJsonSection(section);
+
+ // Notice: the parent id is not yet resolved.
// Store the element:
allSections.Add(nextSection.UniqueId, new (section.ParentUniqueId.UniqueId, nextSection));
@@ -252,8 +271,28 @@ public sealed class DataContext : DbContext, IDataContext
// Now, resolve the parent-child relationships for the sections:
foreach (var (uniqueId, (parentId, section)) in allSections)
- section.Parent = parentId == Guid.Empty ? null : allSections[parentId].Entity;
-
+ {
+ if(parentId == Guid.Empty)
+ {
+ if(section.Depth != 0)
+ Console.WriteLine(@$"Section {uniqueId} ""{section.Name}"" has no parent.");
+ else
+ Console.WriteLine(@$"Section {uniqueId} ""{section.Name}"" is a root section, thus, has no parent.");
+
+ section.Parent = null;
+ continue;
+ }
+
+ if(allSections.TryGetValue(parentId, out var parent))
+ section.Parent = parent.Entity;
+ else
+ {
+ Console.WriteLine(@$"Parent of section {uniqueId} ""{section.Name}"" was not found.");
+ section.Parent = null;
+ continue;
+ }
+ }
+
// -------------------------
// Import the text elements:
// -------------------------
@@ -330,7 +369,15 @@ public sealed class DataContext : DbContext, IDataContext
// Commit the transaction:
await transaction.CommitAsync();
+
+ Console.WriteLine("Finished importing data from JSON file.");
}
#endregion
+
+ #region Tools
+
+ internal Task LoadElementsAsync(TEntry entry, Expression> selector) where TEntry : class where TProp : class => this.Entry(entry).Reference(selector).LoadAsync();
+
+ #endregion
}
\ No newline at end of file
diff --git a/I18N Commander/DataModel/Database/Section.cs b/I18N Commander/DataModel/Database/Section.cs
index 0bd9cb0..a990898 100644
--- a/I18N Commander/DataModel/Database/Section.cs
+++ b/I18N Commander/DataModel/Database/Section.cs
@@ -22,16 +22,23 @@ public sealed class Section
internal DataContext.JsonUniqueId JsonUniqueId => new(this.DataKey, this.UniqueId, "Sec");
- internal DataContext.JsonSection ToJsonSection() => new()
+ internal DataContext.JsonSection ToJsonSection(DataContext db)
{
- UniqueId = this.JsonUniqueId,
- Name = this.Name,
- DataKey = this.DataKey,
- Depth = this.Depth,
- ParentUniqueId = this.Parent?.JsonUniqueId ?? new DataContext.JsonUniqueId("null", Guid.Empty, "Sec"),
- TextElements = this.TextElements.Select(n => n.JsonUniqueId).ToList()
- };
-
+ db.LoadElementsAsync(this, n => n.Parent).GetAwaiter().GetResult();
+ if(this.Depth > 0 && this.Parent == null)
+ Console.WriteLine($"Found section with depth > 0 and parent is null ==> {this.JsonUniqueId}");
+
+ return new()
+ {
+ UniqueId = this.JsonUniqueId,
+ Name = this.Name,
+ DataKey = this.DataKey,
+ Depth = this.Depth,
+ ParentUniqueId = this.Parent?.JsonUniqueId ?? new DataContext.JsonUniqueId("null", Guid.Empty, "Sec"),
+ TextElements = this.TextElements.Select(n => n.JsonUniqueId).ToList()
+ };
+ }
+
internal static Section FromJsonSection(DataContext.JsonSection jsonSection) => new()
{
UniqueId = jsonSection.UniqueId.UniqueId,
diff --git a/I18N Commander/DataModel/MigrationScripts/202211AddUniqueIds.cs b/I18N Commander/DataModel/MigrationScripts/202211AddUniqueIds.cs
index aa85699..76bcc90 100644
--- a/I18N Commander/DataModel/MigrationScripts/202211AddUniqueIds.cs
+++ b/I18N Commander/DataModel/MigrationScripts/202211AddUniqueIds.cs
@@ -7,16 +7,28 @@ public static class Script202211AddUniqueIds
public static async Task PostMigrationAsync(DataContext db)
{
await foreach (var setting in db.Settings)
- setting.UniqueId = Guid.NewGuid();
-
+ {
+ if(setting.UniqueId == Guid.Empty)
+ setting.UniqueId = Guid.NewGuid();
+ }
+
await foreach(var section in db.Sections)
- section.UniqueId = Guid.NewGuid();
-
+ {
+ if(section.UniqueId == Guid.Empty)
+ section.UniqueId = Guid.NewGuid();
+ }
+
await foreach (var textElement in db.TextElements)
- textElement.UniqueId = Guid.NewGuid();
-
+ {
+ if(textElement.UniqueId == Guid.Empty)
+ textElement.UniqueId = Guid.NewGuid();
+ }
+
await foreach (var translation in db.Translations)
- translation.UniqueId = Guid.NewGuid();
+ {
+ if(translation.UniqueId == Guid.Empty)
+ translation.UniqueId = Guid.NewGuid();
+ }
await db.SaveChangesAsync();
}
diff --git a/I18N Commander/Processor/DeepL.cs b/I18N Commander/Processor/DeepL.cs
index af3ffe5..d942e9c 100644
--- a/I18N Commander/Processor/DeepL.cs
+++ b/I18N Commander/Processor/DeepL.cs
@@ -54,17 +54,24 @@ public static class DeepL
{
var sourceCultureIndex = await AppSettings.GetDeepLSourceCultureIndex();
var sourceCulture = await AppSettings.GetCultureCode(sourceCultureIndex);
-
+
// In case of the source culture, we cannot specify the region, so we need to remove it:
sourceCulture = sourceCulture.Split('-')[0];
-
+
using var deepl = new Translator(deepLAPIKey);
var translation = await deepl.TranslateTextAsync(text, sourceCulture, targetCulture);
-
+
return translation.Text;
}
- catch (AuthorizationException)
+ catch (AuthorizationException e)
{
+ Console.WriteLine($"DeepL authorization failed: {e.Message}");
+ DEEPL_NOT_AVAILABLE = true;
+ return string.Empty;
+ }
+ catch (DeepLException e)
+ {
+ Console.WriteLine($"DeepL issue: {e.Message}");
DEEPL_NOT_AVAILABLE = true;
return string.Empty;
}
diff --git a/I18N Commander/Processor/Version.cs b/I18N Commander/Processor/Version.cs
index 592ab98..d6dce1e 100644
--- a/I18N Commander/Processor/Version.cs
+++ b/I18N Commander/Processor/Version.cs
@@ -2,5 +2,5 @@
public static class Version
{
- public static string Text => $"v0.8.1 (2023-01-24), .NET {Environment.Version}";
+ public static string Text => $"v0.8.2 (2023-02-11), .NET {Environment.Version}";
}
\ No newline at end of file