AccountingNext/Schaad.Accounting.Db/RepositoryCache.cs
Claudio Schaad 1c7ba7f416 PR D: per-scope repository cache
Add a Scoped RepositoryCache that memoizes deserialized XML lists,
keyed by absolute file path. Each XML file is loaded at most once per
SignalR circuit; Save invalidates the corresponding entry so
subsequent reads reload from disk.

BaseRepository gains a LoadList<T>(fileName) helper; each of the seven
repositories now defines Get*List() as a one-liner over that helper
and takes RepositoryCache via the constructor.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-07-02 20:52:24 +02:00

38 lines
1.2 KiB
C#

using System;
using System.Collections.Generic;
namespace Schaad.Accounting.Repositories
{
/// <summary>
/// Per-scope cache of deserialized XML lists, keyed by absolute file path.
///
/// Registered as Scoped so it lives for the SignalR circuit; each XML file is
/// then loaded at most once per circuit. Writes go through <see cref="BaseRepository.Save"/>,
/// which invalidates the corresponding entry so the next read reloads from disk.
///
/// Not thread-safe — callers within a single Blazor Server circuit run serialized on the
/// circuit's synchronization context, so no locking is needed.
/// </summary>
public class RepositoryCache
{
private readonly Dictionary<string, object> entries =
new(StringComparer.OrdinalIgnoreCase);
public List<T> GetOrLoad<T>(string cacheKey, Func<List<T>> loader)
{
if (entries.TryGetValue(cacheKey, out var cached))
{
return (List<T>)cached;
}
var list = loader();
entries[cacheKey] = list;
return list;
}
public void Invalidate(string cacheKey)
{
entries.Remove(cacheKey);
}
}
}