Implement backup and restore functionality; add IBackupService and BackupService; refactor services to use DbContextFactory
This commit is contained in:
@@ -9,13 +9,15 @@ namespace Duempelkas.Infrastructure.Services;
|
||||
|
||||
public class EntryService : IEntryService
|
||||
{
|
||||
private readonly FinanceDbContext _db;
|
||||
private readonly IDbContextFactory<FinanceDbContext> _dbFactory;
|
||||
|
||||
public EntryService(FinanceDbContext db) => _db = db;
|
||||
public EntryService(IDbContextFactory<FinanceDbContext> dbFactory) => _dbFactory = dbFactory;
|
||||
|
||||
public async Task<List<EntryDto>> GetEntriesAsync(int accountId, bool currentYearOnly)
|
||||
{
|
||||
var query = _db.Entries.Where(e => e.AccountId == accountId);
|
||||
await using var db = await _dbFactory.CreateDbContextAsync();
|
||||
|
||||
var query = db.Entries.Where(e => e.AccountId == accountId);
|
||||
|
||||
if (currentYearOnly)
|
||||
query = query.Where(e => e.Date.Year == DateTime.Now.Year);
|
||||
@@ -27,7 +29,7 @@ public class EntryService : IEntryService
|
||||
|
||||
var entryIds = entries.Select(e => e.Id).ToList();
|
||||
|
||||
var transferLinks = await _db.TransferLinks
|
||||
var transferLinks = await db.TransferLinks
|
||||
.Include(tl => tl.SourceEntry).ThenInclude(e => e.Account)
|
||||
.Include(tl => tl.TargetEntry).ThenInclude(e => e.Account)
|
||||
.Where(tl => entryIds.Contains(tl.SourceEntryId) || entryIds.Contains(tl.TargetEntryId))
|
||||
@@ -59,7 +61,9 @@ public class EntryService : IEntryService
|
||||
|
||||
public async Task<EntryDto> CreateEntryAsync(int accountId, EntryType type, DateTime date, string title, decimal amount)
|
||||
{
|
||||
var displayId = await GenerateDisplayIdAsync(accountId, date.Year);
|
||||
await using var db = await _dbFactory.CreateDbContextAsync();
|
||||
|
||||
var displayId = await GenerateDisplayIdAsync(db, accountId, date.Year);
|
||||
|
||||
var entry = new Entry
|
||||
{
|
||||
@@ -70,8 +74,8 @@ public class EntryService : IEntryService
|
||||
Title = title,
|
||||
Amount = amount
|
||||
};
|
||||
_db.Entries.Add(entry);
|
||||
await _db.SaveChangesAsync();
|
||||
db.Entries.Add(entry);
|
||||
await db.SaveChangesAsync();
|
||||
|
||||
return new EntryDto(entry.Id, entry.AccountId, entry.DisplayId, entry.Type, entry.Date, entry.Title, entry.Amount, false, false, null, null, null);
|
||||
}
|
||||
@@ -81,9 +85,10 @@ public class EntryService : IEntryService
|
||||
if (sourceAccountId == targetAccountId)
|
||||
throw new InvalidOperationException("Umbuchung innerhalb desselben Kontos ist nicht möglich.");
|
||||
|
||||
await using var transaction = await _db.Database.BeginTransactionAsync();
|
||||
await using var db = await _dbFactory.CreateDbContextAsync();
|
||||
await using var transaction = await db.Database.BeginTransactionAsync();
|
||||
|
||||
var sourceDisplayId = await GenerateDisplayIdAsync(sourceAccountId, date.Year);
|
||||
var sourceDisplayId = await GenerateDisplayIdAsync(db, sourceAccountId, date.Year);
|
||||
|
||||
var sourceEntry = new Entry
|
||||
{
|
||||
@@ -95,10 +100,10 @@ public class EntryService : IEntryService
|
||||
Amount = amount
|
||||
};
|
||||
|
||||
_db.Entries.Add(sourceEntry);
|
||||
await _db.SaveChangesAsync();
|
||||
db.Entries.Add(sourceEntry);
|
||||
await db.SaveChangesAsync();
|
||||
|
||||
var targetDisplayId = await GenerateDisplayIdAsync(targetAccountId, date.Year);
|
||||
var targetDisplayId = await GenerateDisplayIdAsync(db, targetAccountId, date.Year);
|
||||
|
||||
var targetEntry = new Entry
|
||||
{
|
||||
@@ -110,8 +115,8 @@ public class EntryService : IEntryService
|
||||
Amount = amount
|
||||
};
|
||||
|
||||
_db.Entries.Add(targetEntry);
|
||||
await _db.SaveChangesAsync();
|
||||
db.Entries.Add(targetEntry);
|
||||
await db.SaveChangesAsync();
|
||||
|
||||
var link = new TransferLink
|
||||
{
|
||||
@@ -119,62 +124,68 @@ public class EntryService : IEntryService
|
||||
TargetEntryId = targetEntry.Id,
|
||||
Note = $"Umbuchung: {title}"
|
||||
};
|
||||
_db.TransferLinks.Add(link);
|
||||
await _db.SaveChangesAsync();
|
||||
db.TransferLinks.Add(link);
|
||||
await db.SaveChangesAsync();
|
||||
|
||||
sourceEntry.TransferLinkId = link.Id;
|
||||
targetEntry.TransferLinkId = link.Id;
|
||||
await _db.SaveChangesAsync();
|
||||
await db.SaveChangesAsync();
|
||||
|
||||
await transaction.CommitAsync();
|
||||
}
|
||||
|
||||
public async Task DeleteEntryAsync(int entryId)
|
||||
{
|
||||
var entry = await _db.Entries.FindAsync(entryId)
|
||||
await using var db = await _dbFactory.CreateDbContextAsync();
|
||||
|
||||
var entry = await db.Entries.FindAsync(entryId)
|
||||
?? throw new InvalidOperationException($"Eintrag {entryId} nicht gefunden.");
|
||||
|
||||
entry.IsDeleted = true;
|
||||
|
||||
var link = await _db.TransferLinks
|
||||
var link = await db.TransferLinks
|
||||
.FirstOrDefaultAsync(tl => tl.SourceEntryId == entryId || tl.TargetEntryId == entryId);
|
||||
|
||||
if (link != null)
|
||||
{
|
||||
var otherEntryId = link.SourceEntryId == entryId ? link.TargetEntryId : link.SourceEntryId;
|
||||
var otherEntry = await _db.Entries.FindAsync(otherEntryId);
|
||||
var otherEntry = await db.Entries.FindAsync(otherEntryId);
|
||||
if (otherEntry != null) otherEntry.IsDeleted = true;
|
||||
}
|
||||
|
||||
await _db.SaveChangesAsync();
|
||||
await db.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public async Task RestoreEntryAsync(int entryId)
|
||||
{
|
||||
var entry = await _db.Entries.FindAsync(entryId)
|
||||
await using var db = await _dbFactory.CreateDbContextAsync();
|
||||
|
||||
var entry = await db.Entries.FindAsync(entryId)
|
||||
?? throw new InvalidOperationException($"Eintrag {entryId} nicht gefunden.");
|
||||
|
||||
entry.IsDeleted = false;
|
||||
|
||||
var link = await _db.TransferLinks
|
||||
var link = await db.TransferLinks
|
||||
.FirstOrDefaultAsync(tl => tl.SourceEntryId == entryId || tl.TargetEntryId == entryId);
|
||||
|
||||
if (link != null)
|
||||
{
|
||||
var otherEntryId = link.SourceEntryId == entryId ? link.TargetEntryId : link.SourceEntryId;
|
||||
var otherEntry = await _db.Entries.FindAsync(otherEntryId);
|
||||
var otherEntry = await db.Entries.FindAsync(otherEntryId);
|
||||
if (otherEntry != null) otherEntry.IsDeleted = false;
|
||||
}
|
||||
|
||||
await _db.SaveChangesAsync();
|
||||
await db.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public async Task UpdateEntryAsync(int entryId, DateTime date, string title, decimal amount)
|
||||
{
|
||||
var entry = await _db.Entries.FindAsync(entryId)
|
||||
await using var db = await _dbFactory.CreateDbContextAsync();
|
||||
|
||||
var entry = await db.Entries.FindAsync(entryId)
|
||||
?? throw new InvalidOperationException($"Eintrag {entryId} nicht gefunden.");
|
||||
|
||||
var link = await _db.TransferLinks
|
||||
var link = await db.TransferLinks
|
||||
.FirstOrDefaultAsync(tl => tl.SourceEntryId == entryId || tl.TargetEntryId == entryId);
|
||||
|
||||
entry.Date = date;
|
||||
@@ -184,7 +195,7 @@ public class EntryService : IEntryService
|
||||
if (link != null)
|
||||
{
|
||||
var otherEntryId = link.SourceEntryId == entryId ? link.TargetEntryId : link.SourceEntryId;
|
||||
var otherEntry = await _db.Entries.FindAsync(otherEntryId);
|
||||
var otherEntry = await db.Entries.FindAsync(otherEntryId);
|
||||
if (otherEntry != null)
|
||||
{
|
||||
otherEntry.Date = date;
|
||||
@@ -193,20 +204,22 @@ public class EntryService : IEntryService
|
||||
}
|
||||
}
|
||||
|
||||
await _db.SaveChangesAsync();
|
||||
await db.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public async Task UpdateTransferAsync(int entryId, int newLinkedAccountId, DateTime date, string title, decimal amount)
|
||||
{
|
||||
var entry = await _db.Entries.FindAsync(entryId)
|
||||
await using var db = await _dbFactory.CreateDbContextAsync();
|
||||
|
||||
var entry = await db.Entries.FindAsync(entryId)
|
||||
?? throw new InvalidOperationException($"Eintrag {entryId} nicht gefunden.");
|
||||
|
||||
var link = await _db.TransferLinks
|
||||
var link = await db.TransferLinks
|
||||
.FirstOrDefaultAsync(tl => tl.SourceEntryId == entryId || tl.TargetEntryId == entryId)
|
||||
?? throw new InvalidOperationException($"Kein Transfer-Link für Eintrag {entryId} gefunden.");
|
||||
|
||||
var otherEntryId = link.SourceEntryId == entryId ? link.TargetEntryId : link.SourceEntryId;
|
||||
var otherEntry = await _db.Entries.FindAsync(otherEntryId)
|
||||
var otherEntry = await db.Entries.FindAsync(otherEntryId)
|
||||
?? throw new InvalidOperationException($"Gegeneintrag {otherEntryId} nicht gefunden.");
|
||||
|
||||
// Update date, title, amount on both sides
|
||||
@@ -221,16 +234,16 @@ public class EntryService : IEntryService
|
||||
if (otherEntry.AccountId != newLinkedAccountId)
|
||||
{
|
||||
otherEntry.AccountId = newLinkedAccountId;
|
||||
otherEntry.DisplayId = await GenerateDisplayIdAsync(newLinkedAccountId, date.Year);
|
||||
otherEntry.DisplayId = await GenerateDisplayIdAsync(db, newLinkedAccountId, date.Year);
|
||||
}
|
||||
|
||||
await _db.SaveChangesAsync();
|
||||
await db.SaveChangesAsync();
|
||||
}
|
||||
|
||||
private async Task<string> GenerateDisplayIdAsync(int accountId, int year)
|
||||
private static async Task<string> GenerateDisplayIdAsync(FinanceDbContext db, int accountId, int year)
|
||||
{
|
||||
var prefix = $"{year}-";
|
||||
var maxDisplayId = await _db.Entries
|
||||
var maxDisplayId = await db.Entries
|
||||
.Where(e => e.DisplayId.StartsWith(prefix))
|
||||
.Select(e => e.DisplayId)
|
||||
.MaxAsync(id => (string?)id);
|
||||
|
||||
Reference in New Issue
Block a user