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>
38 lines
1.2 KiB
C#
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);
|
|
}
|
|
}
|
|
}
|