diff --git a/src/Before/Client.cs b/src/Before/Client.cs
index 7beb365..c485dbe 100644
--- a/src/Before/Client.cs
+++ b/src/Before/Client.cs
@@ -31,19 +31,11 @@ public class Client : DbBase
///
/// This mirrors how an ActiveRecord-style ORM might surface a static
/// finder on the domain class itself — it rides the DbContext leak
- /// from the entity's back-reference.
+ /// from the entity's back-reference. Delegates to
+ /// for the common traversal logic.
///
public static Client? FindByName(string name, DbContext? 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;
- }
+ => DbBase.Find(c => c.Name == name, db);
}
///
diff --git a/src/Before/DbBase.cs b/src/Before/DbBase.cs
index d6b97b0..b4120fa 100644
--- a/src/Before/DbBase.cs
+++ b/src/Before/DbBase.cs
@@ -26,4 +26,34 @@ public class DbBase
/// (including the WebApp, and the tests) can only read it.
///
public DbContext? DbContext { get; internal set; }
+
+ ///
+ /// Generic ActiveRecord-style finder: walks the 's tracked entities, looks for the first whose runtime type matches
+ /// and satisfies
+ ///.
+ ///
+ /// This static generic rides the DbContext leak just like
+ /// , but works for any subtype without each entity needing its own hand-written finder.
+ ///
+ /// Entity type to find (must derive from ).
+ ///
+ /// Filter applied to candidates of type .
+ ///
+ /// The context whose tracked entities to search.
+ ///
+ /// The first matching entity, or null when no match.
+ ///
+ public static T? Find(Predicate 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;
+ }
}
\ No newline at end of file