Repository navigation
9.35.0
Full upgrade guide: https://weasel.jasperfx.net/release-9-35
Two independent fixes, plus CI hygiene.
SQL Server: generated scripts run under sqlcmd, and run twice
#593 — PRs #620, #624, thanks to @jovball
A rendered migration script (db-patch, db-dump, WriteMigrationFileAsync, ToDatabaseScript) now runs as one file under sqlcmd or SSMS, and runs a second time against the same database without failing.
- stored procedures emit
CREATE OR ALTER PROCEDUREbetweenGOlines, because T-SQL requires a procedure definition to be the first statement of its batch - existence guards on index, foreign key, table type and sequence creation, plus
DROP INDEX IF EXISTS - generated script files head with
SET QUOTED_IDENTIFIER ON;, so nosqlcmdflags are needed - a procedure body containing a line whose entire content is
GOis refused at render time — neither sqlcmd nor Weasel's splitter parses string literals, so such a line would split the batch inside the definition
DROP INDEX IF EXISTS and CREATE OR ALTER make SQL Server 2016 SP1 the effective floor.
⚠️ Breaking change, SQL Server only
Rendered stored procedure DDL now carries GO lines. A consumer that executes that text through its own SqlCommand must split it first with the new SqlServerBatchSplitter.Split, or switch to CreateAsync. Everything Weasel executes itself already splits.
EF Core: batched queries return what EF Core returns
#621 — PRs #622, #625, reported and fixed by @ayuksekkaya
BatchedQuery.Query<T>() and QuerySingle<T>() built entities by reflecting over the entity type's scalar properties. Anything that was not flat came back incomplete and nothing reported an error: owned types, owned JSON columns, complex properties and complex collections left null or empty, Included navigations empty, a collection Include returning one parent per child row, and nothing tracked. Saving one of those entities wrote the empty members to the database.
EF Core now runs every batched query and materializes every result, so a batched query returns exactly what the same query returns on its own — tracking, identity resolution, owned/complex/JSON members, Includes and projections.
Batching into a single round trip requires the new BatchedQueryInterceptor:
services.AddDbContext<MyDbContext>(opts =>
{
opts.UseNpgsql(connectionString);
opts.UseWeaselBatchedQueries();
});Without it — and where a batch cannot faithfully stand in for separate execution — every queued query runs on its own round trip with the same results. Correctness does not depend on registering anything; only the round trip count does.
Wolverine users: Wolverine batches query plans automatically as soon as a handler has two of them against the same DbContext, so this defect could appear in a working handler when an unrelated second plan was added. Wolverine registers the interceptor from the release that takes this version of Weasel — JasperFx/wolverine#4626.
CI
#611 — PR #623. The seven CI workflows have concurrency groups, so a re-pushed branch stops stacking 18 jobs behind the ones it supersedes.
New public API
SqlServerBatchSplitter.Split(string)— sqlcmd'sGOsemanticsMigrator.SplitIntoBatches(string)—public virtual, returns the whole string by default; every provider but SQL Server keeps thatIndexDefinition.WriteCreateStatement(Table, TextWriter)— the guarded emission methodBatchQueryExtensions.UseWeaselBatchedQueries(...)andBatchedQueryInterceptor
Verification
Every PR was 18/18 green, and master was packed locally and run against both downstream consumers before this release: Wolverine.SqlServerTests 483/0, Wolverine.EfCoreTests 233/0, Polecat.Tests 2809/0, Weasel.SqlServer.Tests 642/0, Weasel.EntityFrameworkCore.Tests 130/0.