Summary: EF Core 10's model validator rejects ProjectVDbContext at first access — MigrateAsync, EnsureCreatedAsync, and any LINQ / raw-SQL query through DbSet all hit the same validator:
The 'RefreshTokenDbInfo' property 'UserDbInfo.RefreshToken' could not be mapped because the database provider does not support this type.
UserDbInfoConfiguration.Configure mapped a navigation-typed property (RefreshTokenDbInfo? RefreshToken) as an EF scalar via builder.Property(e => e.RefreshToken). The reverse fix — builder.Ignore or [NotMapped] — surfaces a follow-on binding error because the only constructor on UserDbInfo takes RefreshTokenDbInfo? refreshToken, and EF's constructor binder cannot bind a navigation parameter to a mapped scalar.
A partial fix landed during Phase 2 at the UserDbInfo ctor level (a 6-arg internal ctor that EF can bind + [NotMapped] on the RefreshToken property) — enough to make the test-side raw-SQL channel viable, but NOT enough to make migration generation work.
Where
Sources/Libraries/ProjectV.DataAccessLayer/Services/Users/UserDbInfoConfiguration.cs — the Configure method.
Sources/Libraries/ProjectV.DataAccessLayer/Services/Users/Models/UserDbInfo.cs — constructor shape + the [NotMapped] partial fix.
Sources/Libraries/ProjectV.DataAccessLayer/Services/Tokens/Models/RefreshTokenDbInfo.cs — WrappedUserId is never assigned by any ctor (always default(UserId)).
Sources/Libraries/ProjectV.DataAccessLayer/Migrations/.gitkeep — placeholder for the future InitialCreate migration once the model is clean.
Sources/WebServices/ProjectV.ProcessingWebService/Program.cs — currently calls EnsureCreatedAsync guarded by CanUseDatabase=false in appsettings.json; the production schema story.
Workaround in place (test-side only)
The Phase 2 DAL integration suite bypasses EF entirely — Sources/Tests/ProjectV.DataAccessLayer.Tests/ForTests/DbCollectionFixture.cs issues raw CREATE TABLE statements through Npgsql.NpgsqlConnection directly; the per-test TRUNCATE flows through the same channel. The dotnet-ef 10.0.8 tooling + ProjectVDbContextDesignTimeFactory : IDesignTimeDbContextFactory<…> are installed and committed so the next attempt at dotnet ef migrations add InitialCreate can run without re-bootstrapping.
Decisions needed before unblocking
- Should
UserDbInfo.RefreshToken be removed entirely (the live token row lives in tokens keyed on RefreshTokenDbInfo.UserId) OR turned into an explicit HasOne()...WithOne() relationship?
- What to do with
RefreshTokenDbInfo.WrappedUserId — currently always default(UserId) because no ctor assigns it.
- Does the production app keep
EnsureCreatedAsync as its schema story, or move to migrations?
Acceptance
Surfaced by
Phase 2 Test Coverage (milestone v0.9.8) — DAL integration slice on ProjectV.DataAccessLayer.Tests. Companion to #339 (token-uniqueness decision) and #340 (tokens.user_name rename, which is blocked on this unblocking).
Summary: EF Core 10's model validator rejects
ProjectVDbContextat first access —MigrateAsync,EnsureCreatedAsync, and any LINQ / raw-SQL query throughDbSetall hit the same validator:UserDbInfoConfiguration.Configuremapped a navigation-typed property (RefreshTokenDbInfo? RefreshToken) as an EF scalar viabuilder.Property(e => e.RefreshToken). The reverse fix —builder.Ignoreor[NotMapped]— surfaces a follow-on binding error because the only constructor onUserDbInfotakesRefreshTokenDbInfo? refreshToken, and EF's constructor binder cannot bind a navigation parameter to a mapped scalar.A partial fix landed during Phase 2 at the
UserDbInfoctor level (a 6-arg internal ctor that EF can bind +[NotMapped]on theRefreshTokenproperty) — enough to make the test-side raw-SQL channel viable, but NOT enough to make migration generation work.Where
Sources/Libraries/ProjectV.DataAccessLayer/Services/Users/UserDbInfoConfiguration.cs— theConfiguremethod.Sources/Libraries/ProjectV.DataAccessLayer/Services/Users/Models/UserDbInfo.cs— constructor shape + the[NotMapped]partial fix.Sources/Libraries/ProjectV.DataAccessLayer/Services/Tokens/Models/RefreshTokenDbInfo.cs—WrappedUserIdis never assigned by any ctor (alwaysdefault(UserId)).Sources/Libraries/ProjectV.DataAccessLayer/Migrations/.gitkeep— placeholder for the futureInitialCreatemigration once the model is clean.Sources/WebServices/ProjectV.ProcessingWebService/Program.cs— currently callsEnsureCreatedAsyncguarded byCanUseDatabase=falseinappsettings.json; the production schema story.Workaround in place (test-side only)
The Phase 2 DAL integration suite bypasses EF entirely —
Sources/Tests/ProjectV.DataAccessLayer.Tests/ForTests/DbCollectionFixture.csissues rawCREATE TABLEstatements throughNpgsql.NpgsqlConnectiondirectly; the per-test TRUNCATE flows through the same channel. Thedotnet-ef 10.0.8tooling +ProjectVDbContextDesignTimeFactory : IDesignTimeDbContextFactory<…>are installed and committed so the next attempt atdotnet ef migrations add InitialCreatecan run without re-bootstrapping.Decisions needed before unblocking
UserDbInfo.RefreshTokenbe removed entirely (the live token row lives intokenskeyed onRefreshTokenDbInfo.UserId) OR turned into an explicitHasOne()...WithOne()relationship?RefreshTokenDbInfo.WrappedUserId— currently alwaysdefault(UserId)because no ctor assigns it.EnsureCreatedAsyncas its schema story, or move to migrations?Acceptance
dotnet ef migrations add InitialCreatesucceeds againstProjectVDbContextand produces anInitialCreatemigration class underSources/Libraries/ProjectV.DataAccessLayer/Migrations/.DbCollectionFixture.ApplySchemaAsyncinProjectV.DataAccessLayer.Testsflips from raw-SQL bootstrap toDatabase.MigrateAsync()(orEnsureCreatedAsync, whichever the production app uses); existing Testcontainers integration tests continue to pass.RefreshTokenDbInfo.WrappedUserIdeither gets assigned in the ctor OR is removed.tokens.user_name→tokens.user_id(refactor(dal): rename tokens.user_name column to tokens.user_id (stores Guid, not name) #340) becomes naturally addressable; the token-uniqueness decision (refactor(dal): clarify token uniqueness — UNIQUE constraint on tokens.user_name + SingleOrDefaultAsync #339) can be applied as a schema constraint in the same migration generation pass.Surfaced by
Phase 2 Test Coverage (milestone v0.9.8) — DAL integration slice on
ProjectV.DataAccessLayer.Tests. Companion to #339 (token-uniqueness decision) and #340 (tokens.user_namerename, which is blocked on this unblocking).