fix(datastore): batch insert of command rows fails on Postgres for derived command types - #250
Open
jordanfelle wants to merge 2 commits into
Open
jordanfelle wants to merge 2 commits into
jordanfelle wants to merge 2 commits into
Conversation
Dapper resolves a type handler from the runtime type of a parameter value. The batch insert path of BasicRepository.InsertMany binds parameters by prop.GetValue(model), so a CommandModel.Body holding a derived command (RefreshAuthorCommand, ...) found no handler (one was registered only for the base type Command) and failed with 'The member p0_Body of type ... cannot be used as a parameter value'. Single Insert binds by the declared type and worked. Register the same handler for each concrete command type. Adds a SQLite-backed InsertMany fixture.
jordanfelle
added a commit
to jordanfelle/chaptarr
that referenced
this pull request
Sep 27, 2026
jordanfelle
added a commit
to jordanfelle/chaptarr
that referenced
this pull request
Sep 27, 2026
…egistered The registration discovers command types by reflection over the core assembly and a Command name suffix; a command added elsewhere or named differently would silently fail its batch insert on Postgres again. Fails if any concrete command type in the core assembly lacks the handler.
jordanfelle
added a commit
to jordanfelle/chaptarr
that referenced
this pull request
Sep 27, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #227.
Problem
BasicRepository.InsertMany(batch paths for Postgres and SQLite) adds each value withparameters.Add(name, prop.GetValue(model)), so Dapper resolves the type handler from the value's runtime type.CommandModel.Bodyhas a handler registered for the base typeCommandonly, so any derived command fails withThe member p0_Body of type ...RefreshAuthorCommand cannot be used as a parameter value. SingleInsertbinds by the declared property type and works. The bulk author editor hit this throughCommandQueueManager.PushMany(worked around per command in #210).Fix
Register the same
CommandConverterhandler for every concrete command type (CommandConverter.ConcreteCommandTypes, plusUnknownCommand), so the lookup by runtime type succeeds.CommandModel.Bodyis the only column found whose handler is registered for a base type; the other handlers (OsPath,Guid,QualityModel, dictionaries,List<int>, ...) are keyed on the exact runtime types stored. After this,PushMany(#210) could go back to a singleInsertMany.Verification
New SQLite-backed
BasicRepositoryInsertManyDeclaredTypeFixture: a batch of derived commands is stored and read back as the right type, stores the same value as singleInsert, and null / other handler columns still work. The tests fail without the fix with the exact production error (3,023 core tests pass).Untested on Postgres (none available here): the failing lookup is Dapper's and is independent of the database; the SQLite batch path shares the same parameter-binding code.
every_concrete_command_type_should_have_the_command_handler_registered, a guard that fails if a future command type is not covered by the reflection-based registration (54 concrete types plusUnknownCommandtoday; the same patternTableMappingalready uses forIProviderConfig) (3,024 core tests pass).