Add DbBase.Find<T> static generic finder (yak: Console app for Before (ActiveRecord-style) > ○ Add DbBase.Find<T> static generic)

This commit is contained in:
2026-09-14 20:45:12 +01:00
parent 92b9e3f784
commit c21c6416cf
2 changed files with 33 additions and 11 deletions
+3 -11
View File
@@ -31,19 +31,11 @@ public class Client : DbBase
/// ///
/// This mirrors how an ActiveRecord-style ORM might surface a static /// This mirrors how an ActiveRecord-style ORM might surface a static
/// finder on the domain class itself — it rides the <c>DbContext</c> leak /// finder on the domain class itself — it rides the <c>DbContext</c> leak
/// from the entity's back-reference. /// from the entity's back-reference. Delegates to
/// <see cref="DbBase.Find{T}"/> for the common traversal logic.
/// </summary> /// </summary>
public static Client? FindByName(string name, DbContext? db) public static Client? FindByName(string name, DbContext? db)
{ => DbBase.Find<Client>(c => c.Name == name, db);
if (db is null)
return null;
foreach (var e in db.Tracked)
if (e is Client c && c.Name == name)
return c;
return null;
}
} }
/// <summary> /// <summary>
+30
View File
@@ -26,4 +26,34 @@ public class DbBase
/// (including the WebApp, and the tests) can only read it. /// (including the WebApp, and the tests) can only read it.
/// </summary> /// </summary>
public DbContext? DbContext { get; internal set; } public DbContext? DbContext { get; internal set; }
/// <summary>
/// Generic ActiveRecord-style finder: walks the <paramref name="db"/
/// />'s tracked entities, looks for the first whose runtime type matches
/// <typeparamref name="T"/> and satisfies <paramref name="predicate"/>
///.
///
/// This static generic rides the <c>DbContext</c> leak just like
/// <see cref="Client.FindByName"/>, but works for any <see cref="DbBase"
/// /> subtype without each entity needing its own hand-written finder.
/// </summary>
/// <typeparam name="T">Entity type to find (must derive from <see cref="DbBase"/>).
/// </typeparam>
/// <param name="predicate">Filter applied to candidates of type <typeparamref name="T"/>.
/// </param>
/// <param name="db">The context whose tracked entities to search.
/// </param>
/// <returns>The first matching entity, or <c>null</c> when no match.
/// </returns>
public static T? Find<T>(Predicate<T> predicate, DbContext? db) where T : DbBase
{
if (db is null)
return default;
foreach (var e in db.Tracked)
if (e is T candidate && predicate(candidate))
return candidate;
return default;
}
} }