镜像站点 · 本页由第三方 GitHub 只读镜像提供,非 GitHub 官方站点,不接受任何登录或凭据输入。前往 github.com
Skip to content

Scaffold foreign keys whose column type differs from the principal key - #39633

Open
ajcvickers wants to merge 1 commit into
dotnet:mainfrom
ajcvickers:fix-19793-scaffold-fk-type-mismatch
Open

ajcvickers wants to merge 1 commit into
dotnet:mainfrom
ajcvickers:fix-19793-scaffold-fk-type-mismatch

Conversation

@ajcvickers

Copy link
Copy Markdown
Contributor

Fixes #19793

Reverse engineering threw InvalidOperationException when a foreign key column and the principal key column it references scaffolded to different CLR types, for example a bigint column referencing an int key, or NUMBER(12,0) referencing NUMBER on Oracle. This aborted scaffolding of the whole database, because EF can't map an entity type whose foreign key and principal key properties have different CLR types.

Behavior

Where it is safe, the dependent column is now scaffolded with the CLR type of the principal column and keeps its own store type through HasColumnType, so EF uses a value converter:

public int ParentId { get; set; }   // was long, but the principal key is int

entity.Property(e => e.ParentId).HasColumnType("bigint");

It is safe when all of these hold:

  • The column references principals of a single CLR type, and is not itself referenced by another foreign key.
  • The principal columns are a key or unique index of the principal table.
  • The principal CLR type can't overflow the column. The converter EF uses for this doesn't check for overflow, so integral columns only change to a type with a smaller or equal range. decimal and integral types can be mixed, which covers the Oracle NUMBER case. Any other mix (string, Guid, binary, float, bool) is left alone.
  • The column is not a row version and has no default value.
  • The type mapping source can map the principal CLR type to the column's store type.

The columns of a foreign key are changed together or not at all. The check uses the column's own store type, not the CLR type hint that SQLite derives from the data in a column, so a SQLite INTEGER column hinted as int can still reference an INTEGER key.

In every other case the foreign key is skipped with a new warning, and scaffolding continues, instead of failing:

Could not scaffold the foreign key 'FK_Child_Parent'. The types of the foreign key properties {'ParentId' : short} do not match the types of the principal key properties {'Id' : long}, and the foreign key columns could not be safely changed to use the principal key types.

This follows what was agreed in the issue: at least don't abort scaffolding, and add the converter in scaffolding when it is low cost.

Behavior change to note

Databases that previously failed to scaffold now succeed. Foreign key columns in them can have a different CLR type from the column's default for its store type, with an explicit HasColumnType, and some foreign keys are skipped with the new warning. Databases that scaffolded before produce the same output.

Not handled

  • A foreign key column with a default value (for example SQLite DEFAULT 0) is not retyped, so its foreign key is skipped with the warning.
  • A column that is itself the target of another foreign key (for example a shared primary key chain with mismatched types) is not retyped.

Tests

  • New tests in RelationalScaffoldingModelFactoryTest cover wider and narrower dependent types, decimal against integral, non-numeric mismatches, default values, row versions, columns without a store type, self-referencing and composite foreign keys (including a cascade across foreign keys that share columns), primary key, unique index and unique constraint columns, principals that are not keys, repeated Create calls, and the SQLite ClrType hint on either end.
  • A new CSharpDbContextGeneratorTest generates code from a scaffolded model with a mismatched foreign key, compiles it, and checks the compiled model.
  • I checked that the tests fail when the principal key check, the re-check loop for shared columns, or the store-type based safety check is removed.
  • test.cmd passes locally (28 test projects), with SQL Server tests run against a local container.

🤖 Generated with Claude Code

@ajcvickers
ajcvickers requested a review from a team as a code owner November 13, 2026 15:19
Copilot AI balanced review requested due to automatic review settings November 13, 2026 15:19

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota. Try requesting a review at a lower effort level.

Fixes dotnet#19793

Reverse engineering threw InvalidOperationException when a foreign key
column and the principal key column it references scaffolded to
different CLR types, for example a bigint column referencing an int key,
or NUMBER(12,0) referencing NUMBER. This aborted scaffolding of the
whole database, because EF can't map an entity type whose foreign key
and principal key properties have different CLR types.

Now, where it is safe, the dependent column is scaffolded with the CLR
type of the principal column and keeps its own store type through
HasColumnType, so EF uses a value converter. It is safe when:
 - the column references principals of a single CLR type, and is not
   itself referenced by another foreign key;
 - the principal columns are a key or unique index of the principal;
 - the principal CLR type can't overflow the column (integral types only
   change to a type with a smaller or equal range, decimal and integral
   types can be mixed, and any other mix of types is left alone);
 - the column is not a row version and has no default value; and
 - the type mapping source can map the principal CLR type to the store
   type.

All the columns of a foreign key are changed together or not at all.

In every other case the foreign key is skipped with a new warning
instead of failing scaffolding.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@ajcvickers
ajcvickers force-pushed the fix-19793-scaffold-fk-type-mismatch branch from 22cca54 to 8fff764 Compare November 14, 2026 11:53
Copilot AI balanced review requested due to automatic review settings November 14, 2026 11:53

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota. Try requesting a review at a lower effort level.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

RevEng: InvalidOperationException scaffolding primary/foreign key columns with different precisions

2 participants