Skip to content

Queries

The harness runs plain SQL. It never makes you reference SqlParameter, NpgsqlParameter or MySqlParameter.

var count = await harness.QueryScalarAsync<int>("SELECT COUNT(*) FROM orders");
var newest = await harness.QueryScalarAsync<DateTimeOffset?>("SELECT MAX(placed_at) FROM orders");

QueryScalarAsync<T> reads the first column of the first row. SQL NULL or no row gives default.

It absorbs the drivers’ differences:

  • COUNT(*) is int on SQL Server and bigint elsewhere, and still converts to int.
  • MySQL returns a CHAR(36) where SQL Server returns a uniqueidentifier, and both convert to Guid.
  • A DateTime converts to DateTimeOffset.
  • Nullable targets such as int? work.

ExecuteAsync runs one statement and returns the number of rows it affected:

var rows = await harness.ExecuteAsync(
"DELETE FROM orders WHERE placed_at < @cutoff",
[new DbParameterValue("@cutoff", DateTime.UtcNow.AddDays(-30))]);

Pass parameters as a list of DbParameterValue. The name is as it appears in the SQL, for example @email. All three drivers also accept the name without the @ prefix.

var count = await harness.QueryScalarAsync<int>(
"SELECT COUNT(*) FROM customers WHERE email = @email",
[new DbParameterValue("@email", "ada@example.test")]);

A null value is sent as SQL NULL.

DbParameterValue lives in the DbTest.Core.Engine namespace.

For a reader, a stored procedure call or driver-specific features, open a connection:

await using var connection = await harness.OpenConnectionAsync();

Each helper opens and closes its own connection. OpenConnectionAsync() returns an open connection that you dispose. CreateConnection() returns one that is not opened yet.

To run several steps on one connection, use ExecuteOnConnectionAsync. The connection is closed afterwards:

await harness.ExecuteOnConnectionAsync(async connection =>
{
// work with the open connection here
});

harness.ListObjectsAsync() lists every table, view and routine as the shape guard sees them: a SchemaObject with a schema name, name, kind and ordered column names.