![]() |
VOOZH | about |
This page documents how the Npgsql EF Core provider reverse-engineers existing PostgreSQL databases into Entity Framework Core models. This process, known as scaffolding or database-first development, reads the database schema from PostgreSQL system catalogs and generates corresponding C# entity classes and DbContext configuration code.
For information about forward engineering (creating/modifying databases from EF Core models), see Migrations and Schema Management. For database creation and connection setup, see Database Creation and Connection Management.
Reverse engineering in the Npgsql provider is a two-phase process:
Phase 1 queries the PostgreSQL database using system catalogs to build a DatabaseModel containing all schema information. Phase 2 uses this model to generate C# code with appropriate type mappings and PostgreSQL-specific annotations.
Sources: src/EFCore.PG/Scaffolding/Internal/NpgsqlDatabaseModelFactory.cs18-158
The NpgsqlDatabaseModelFactory class is the entry point for reverse engineering. It implements EF Core's DatabaseModelFactory base class and is responsible for reading PostgreSQL schemas.
The factory provides two overloads at src/EFCore.PG/Scaffolding/Internal/NpgsqlDatabaseModelFactory.cs51-58 and src/EFCore.PG/Scaffolding/Internal/NpgsqlDatabaseModelFactory.cs61-158 that accept either a connection string or an existing DbConnection.
The Create method orchestrates the entire scaffolding process:
| Step | Method | Purpose |
|---|---|---|
| 1 | PopulateGlobalDatabaseInfo() | Reads database-level collation from pg_database src/EFCore.PG/Scaffolding/Internal/NpgsqlDatabaseModelFactory.cs164-182 |
| 2 | GetEnums() | Loads PostgreSQL enum types for filtering src/EFCore.PG/Scaffolding/Internal/NpgsqlDatabaseModelFactory.cs1136-1174 |
| 3 | GetTables() | Scaffolds tables, views, and materialized views from pg_class src/EFCore.PG/Scaffolding/Internal/NpgsqlDatabaseModelFactory.cs187-265 |
| 4 | GetColumns() | Scaffolds columns with PostgreSQL-specific features src/EFCore.PG/Scaffolding/Internal/NpgsqlDatabaseModelFactory.cs270-508 |
| 5 | GetConstraints() | Scaffolds primary keys, foreign keys, unique constraints from pg_constraint src/EFCore.PG/Scaffolding/Internal/NpgsqlDatabaseModelFactory.cs814-1033 |
| 6 | GetIndexes() | Scaffolds indexes with method, operators, and options from pg_index src/EFCore.PG/Scaffolding/Internal/NpgsqlDatabaseModelFactory.cs548-812 |
| 7 | GetSequences() | Scaffolds standalone sequences from pg_sequence src/EFCore.PG/Scaffolding/Internal/NpgsqlDatabaseModelFactory.cs1035-1134 |
| 8 | GetExtensions() | Scaffolds installed PostgreSQL extensions src/EFCore.PG/Scaffolding/Internal/NpgsqlDatabaseModelFactory.cs1176-1192 |
| 9 | GetCollations() | Scaffolds user-defined collations from pg_collation src/EFCore.PG/Scaffolding/Internal/NpgsqlDatabaseModelFactory.cs1194-1258 |
Sources: src/EFCore.PG/Scaffolding/Internal/NpgsqlDatabaseModelFactory.cs66-158
The factory queries PostgreSQL's system catalogs extensively to retrieve schema information.
The GetTables() method queries pg_class with a filter on relkind to distinguish different object types:
| relkind | Object Type | Scaffolded As |
|---|---|---|
| 'r' | Regular table | DatabaseTable |
| 'f' | Foreign table | DatabaseTable |
| 'v' | View | DatabaseView |
| 'm' | Materialized view | DatabaseView |
The query at src/EFCore.PG/Scaffolding/Internal/NpgsqlDatabaseModelFactory.cs196-220 also excludes internal schemas (pg_catalog, information_schema) and tables owned by PostgreSQL extensions.
Sources: src/EFCore.PG/Scaffolding/Internal/NpgsqlDatabaseModelFactory.cs187-265
Column scaffolding must detect PostgreSQL-specific features and map them to EF Core concepts.
The provider detects auto-increment columns in two ways:
Identity columns are detected via the attidentity column:
| attidentity | Strategy | Annotation |
|---|---|---|
| 'a' | GENERATED ALWAYS | NpgsqlValueGenerationStrategy.IdentityAlwaysColumn |
| 'd' | GENERATED BY DEFAULT | NpgsqlValueGenerationStrategy.IdentityByDefaultColumn |
Associated sequence options (start, increment, min/max) are stored in the NpgsqlAnnotationNames.IdentityOptions annotation src/EFCore.PG/Scaffolding/Internal/NpgsqlDatabaseModelFactory.cs412-474
For serial columns, the factory performs pattern matching on the default value expression at src/EFCore.PG/Scaffolding/Internal/NpgsqlDatabaseModelFactory.cs429-446:
If a nextval() pattern is matched on these types, the column is marked with NpgsqlValueGenerationStrategy.SerialColumn.
PostgreSQL 12+ supports generated columns. The attgenerated column indicates:
| attgenerated | Type | EF Core Properties |
|---|---|---|
| 's' | Stored | ComputedColumnSql + IsStored = true |
| 'v' | Virtual | ComputedColumnSql + IsStored = false |
Sources: src/EFCore.PG/Scaffolding/Internal/NpgsqlDatabaseModelFactory.cs393-409
NpgsqlAnnotationCodeGenerator converts model annotations into fluent API method calls in the generated DbContext.
Sources: src/EFCore.PG/Design/Internal/NpgsqlAnnotationCodeGenerator.cs13-447
The code generator has special logic for value generation strategies at src/EFCore.PG/Design/Internal/NpgsqlAnnotationCodeGenerator.cs323-384:
| Strategy | Generated Method |
|---|---|
SerialColumn | .UseSerialColumn() |
IdentityAlwaysColumn | .UseIdentityAlwaysColumn() |
IdentityByDefaultColumn | .UseIdentityByDefaultColumn() |
Convention Handling: Both SerialColumn and IdentityByDefaultColumn are considered by-convention, so they're only generated if explicitly different from the convention src/EFCore.PG/Design/Internal/NpgsqlAnnotationCodeGenerator.cs179-201
The scaffolding process supports filtering via DatabaseModelFactoryOptions.
Schema and Table Filtering: The factory parses table names using a regex at src/EFCore.PG/Scaffolding/Internal/NpgsqlDatabaseModelFactory.cs22-32 to support quoted identifiers and schema-qualified names.
Sources: src/EFCore.PG/Scaffolding/Internal/NpgsqlDatabaseModelFactory.cs94-147 test/EFCore.PG.FunctionalTests/Scaffolding/NpgsqlDatabaseModelFactoryTest.cs351-459
Sources:
Refresh this wiki