diff --git a/MoneyMap/Pages/Upload.cshtml.cs b/MoneyMap/Pages/Upload.cshtml.cs
index 33231d0..1dc8858 100644
--- a/MoneyMap/Pages/Upload.cshtml.cs
+++ b/MoneyMap/Pages/Upload.cshtml.cs
@@ -255,6 +255,11 @@ namespace MoneyMap.Pages
var previewItems = new List();
var addedInThisBatch = new HashSet();
+ // Load all existing transactions into memory for fast duplicate checking
+ var existingTransactions = await _db.Transactions
+ .Select(t => new TransactionKey(t.Date, t.Amount, t.Name, t.Memo, t.AccountId, t.CardId))
+ .ToHashSetAsync();
+
using var reader = new StreamReader(csvStream);
using var csv = new CsvReader(reader, new CsvConfiguration(CultureInfo.InvariantCulture)
{
@@ -279,7 +284,8 @@ namespace MoneyMap.Pages
var transaction = MapToTransaction(row, paymentResolution);
var key = new TransactionKey(transaction);
- bool isDuplicate = addedInThisBatch.Contains(key) || await IsDuplicate(transaction);
+ // Fast in-memory duplicate checking
+ bool isDuplicate = addedInThisBatch.Contains(key) || existingTransactions.Contains(key);
previewItems.Add(new TransactionPreview
{
@@ -415,7 +421,7 @@ namespace MoneyMap.Pages
return PaymentResolutionResult.SuccessAccount(account.Id, account.Last4);
}
- private async Task ResolveAutomaticallyAsync(string? memo, ImportContext context)
+ private Task ResolveAutomaticallyAsync(string? memo, ImportContext context)
{
// Extract last4 from both memo and filename
var last4FromFile = CardIdentifierExtractor.FromFileName(context.FileName);
@@ -425,26 +431,26 @@ namespace MoneyMap.Pages
if (!string.IsNullOrWhiteSpace(last4FromMemo))
{
var result = TryResolveByLast4(last4FromMemo, context);
- if (result != null) return result;
+ if (result != null) return Task.FromResult(result);
}
// PRIORITY 2: Fall back to filename (for account-level CSVs or when memo has no card)
if (!string.IsNullOrWhiteSpace(last4FromFile))
{
var result = TryResolveByLast4(last4FromFile, context);
- if (result != null) return result;
+ if (result != null) return Task.FromResult(result);
}
// Nothing found - error
var searchedLast4 = last4FromMemo ?? last4FromFile;
if (string.IsNullOrWhiteSpace(searchedLast4))
{
- return PaymentResolutionResult.Failure(
- "Couldn't determine card or account from memo or file name. Choose an account manually.");
+ return Task.FromResult(PaymentResolutionResult.Failure(
+ "Couldn't determine card or account from memo or file name. Choose an account manually."));
}
- return PaymentResolutionResult.Failure(
- $"Couldn't find account or card with last4 '{searchedLast4}'. Choose an account manually.");
+ return Task.FromResult(PaymentResolutionResult.Failure(
+ $"Couldn't find account or card with last4 '{searchedLast4}'. Choose an account manually."));
}
private PaymentResolutionResult? TryResolveByLast4(string last4, ImportContext context)