Throw ObjectNotFoundException from FindRequired; add run-console wrappers

- DbBase.FindRequired / Client.FindByNameRequired now throw the
  domain-specific ObjectNotFoundException (NHibernate lineage; Rails
  equivalent: ActiveRecord::RecordNotFound) on a lookup miss; the
  no-context case stays InvalidOperationException (configuration error)
- Console demo catches the new type; tests (18)/(21) assert it,
  (19)/(23) keep InvalidOperationException with rationale comments
- scripts/run-console.sh delegates to dotnet.sh; run-console.ps1 is
  the Windows/PowerShell counterpart (mise-first, repo-root cd)

Yak: objectnotfoundexception-run-console-wrappers-3p8b
This commit is contained in:
2026-09-14 22:39:21 +01:00
parent 4b6e6f5a00
commit ec9586c316
8 changed files with 104 additions and 17 deletions
+8 -4
View File
@@ -86,8 +86,9 @@ public class DbBase
/// <summary>
/// Throwing variant of <see cref="Find{T}(System.Predicate{T},DbContext?)"/>. Finds the first entity
/// whose runtime type matches <typeparamref name="T"/> and satisfies
/// <paramref name="predicate"/>. Throws <see cref="InvalidOperationException"/>
/// when no match is found or when no <see cref="Context"/> singleton is configured.
/// <paramref name="predicate"/>. Throws <see cref="ObjectNotFoundException"/>
/// when no match is found, and <see cref="InvalidOperationException"/> when no
/// <see cref="Context"/> singleton is configured (a configuration error, not a lookup miss).
///
/// The exception message includes <paramref name="predicateToString"/> so
/// callers can debug which lookup failed.
@@ -98,8 +99,11 @@ public class DbBase
/// <param name="predicateToString">A human-readable description of the predicate, used in the
/// exception message when the search fails.</param>
/// <returns>The first matching entity.</returns>
/// <exception cref="ObjectNotFoundException">
/// Thrown when no entity matches <paramref name="predicate"/>.
/// </exception>
/// <exception cref="InvalidOperationException">
/// Thrown when no entity matches <paramref name="predicate"/> or when no context is available.
/// Thrown when no context is available (neither passed explicitly nor set as the singleton).
/// </exception>
public static T FindRequired<T>(Predicate<T> predicate, DbContext? db, string predicateToString)
where T : DbBase
@@ -117,7 +121,7 @@ public class DbBase
if (e is T candidate && predicate(candidate))
return candidate;
throw new InvalidOperationException(
throw new ObjectNotFoundException(
$"FindRequired<{typeof(T).Name}>({predicateToString}) — " +
$"no matching {typeof(T).Name} found in context.");
}