Bugfixes
- Added handling for DeepL exceptions - Added debug logging for im- and exporting - When executing the post script for the unique id migration, ensure that new id are generated, only when no id exists - Fixed section export by loading references to parents
This commit is contained in:
parent
59da2c23a8
commit
4c6f5b59f0
@ -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
|
||||
/// <param name="includeSensitiveData">When false, exclude sensitive data from export.</param>
|
||||
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.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -212,6 +227,8 @@ public sealed class DataContext : DbContext, IDataContext
|
||||
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();
|
||||
|
||||
@ -245,6 +262,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));
|
||||
sectionToTextElements.Add(nextSection.UniqueId, section.TextElements.Select(n => n.UniqueId).ToList());
|
||||
@ -252,7 +271,27 @@ 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, TProp>(TEntry entry, Expression<Func<TEntry, TProp?>> selector) where TEntry : class where TProp : class => this.Entry<TEntry>(entry).Reference(selector).LoadAsync();
|
||||
|
||||
#endregion
|
||||
}
|
@ -22,7 +22,13 @@ 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)
|
||||
{
|
||||
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,
|
||||
@ -31,6 +37,7 @@ public sealed class Section
|
||||
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()
|
||||
{
|
||||
|
@ -7,16 +7,28 @@ public static class Script202211AddUniqueIds
|
||||
public static async Task PostMigrationAsync(DataContext db)
|
||||
{
|
||||
await foreach (var setting in db.Settings)
|
||||
{
|
||||
if(setting.UniqueId == Guid.Empty)
|
||||
setting.UniqueId = Guid.NewGuid();
|
||||
}
|
||||
|
||||
await foreach(var section in db.Sections)
|
||||
{
|
||||
if(section.UniqueId == Guid.Empty)
|
||||
section.UniqueId = Guid.NewGuid();
|
||||
}
|
||||
|
||||
await foreach (var textElement in db.TextElements)
|
||||
{
|
||||
if(textElement.UniqueId == Guid.Empty)
|
||||
textElement.UniqueId = Guid.NewGuid();
|
||||
}
|
||||
|
||||
await foreach (var translation in db.Translations)
|
||||
{
|
||||
if(translation.UniqueId == Guid.Empty)
|
||||
translation.UniqueId = Guid.NewGuid();
|
||||
}
|
||||
|
||||
await db.SaveChangesAsync();
|
||||
}
|
||||
|
@ -63,8 +63,15 @@ public static class DeepL
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -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}";
|
||||
}
|
Loading…
Reference in New Issue
Block a user