11using Npgsql . EntityFrameworkCore . PostgreSQL . Metadata . Conventions ;
2+ using Npgsql . EntityFrameworkCore . PostgreSQL . Metadata . Internal ;
23
34namespace Npgsql . EntityFrameworkCore . PostgreSQL . Migrations . Internal ;
45
@@ -101,14 +102,40 @@ protected override IReadOnlyList<MigrationCommand> GetCreateCommands()
101102 {
102103 // TODO: This is all a hack around https://github.com/dotnet/efcore/issues/34991: we have provider-specific conventions which add
103104 // enums and extensions to the model, and the default EF logic causes them to be created at this point, when the history table is
104- // being created.
105+ // being created. This causes problems when:
106+ // (a) we create an enum here when creating the history table, and then try to create it again when the actual migration
107+ // runs (#3324), and
108+ // (b) we shouldn't be creating extensions at this early point either, and doing so can cause issues (e.g. #3496).
109+ //
110+ // So we filter out any extension/enum migration operations.
111+ // Note that the approach in EF is to remove specific conventions (e.g. DbSetFindingConvention), but we don't want to hardcode
112+ // specific conventions here; for example, the NetTopologySuite plugin has its NpgsqlNetTopologySuiteExtensionAddingConvention
113+ // which adds PostGIS. So we just filter out the annotations on the operations themselves.
105114 var model = EnsureModel ( ) ;
106115
107116 var operations = Dependencies . ModelDiffer . GetDifferences ( null , model . GetRelationalModel ( ) ) ;
108- var commandList = Dependencies . MigrationsSqlGenerator . Generate ( operations , model ) ;
109- return commandList ;
117+
118+ foreach ( var operation in operations )
119+ {
120+ if ( operation is not AlterDatabaseOperation alterDatabaseOperation )
121+ {
122+ continue ;
123+ }
124+
125+ foreach ( var annotation in alterDatabaseOperation . GetAnnotations ( ) )
126+ {
127+ if ( annotation . Name . StartsWith ( NpgsqlAnnotationNames . PostgresExtensionPrefix , StringComparison . Ordinal )
128+ || annotation . Name . StartsWith ( NpgsqlAnnotationNames . EnumPrefix , StringComparison . Ordinal ) )
129+ {
130+ alterDatabaseOperation . RemoveAnnotation ( annotation . Name ) ;
131+ }
132+ }
133+ }
134+
135+ return Dependencies . MigrationsSqlGenerator . Generate ( operations , model ) ;
110136 }
111137
138+ // Copied as-is from EF's HistoryRepository, since it's private (see https://github.com/dotnet/efcore/issues/34991)
112139 private IModel EnsureModel ( )
113140 {
114141 if ( _model == null )
@@ -117,16 +144,13 @@ private IModel EnsureModel()
117144
118145 conventionSet . Remove ( typeof ( DbSetFindingConvention ) ) ;
119146 conventionSet . Remove ( typeof ( RelationalDbFunctionAttributeConvention ) ) ;
120- // TODO: this whole method exists only so we can remove this convention (https://github.com/dotnet/efcore/issues/34991)
121- conventionSet . Remove ( typeof ( NpgsqlPostgresModelFinalizingConvention ) ) ;
122147
123148 var modelBuilder = new ModelBuilder ( conventionSet ) ;
124- modelBuilder . Entity < HistoryRow > (
125- x =>
126- {
127- ConfigureTable ( x ) ;
128- x . ToTable ( TableName , TableSchema ) ;
129- } ) ;
149+ modelBuilder . Entity < HistoryRow > ( x =>
150+ {
151+ ConfigureTable ( x ) ;
152+ x . ToTable ( TableName , TableSchema ) ;
153+ } ) ;
130154
131155 _model = Dependencies . ModelRuntimeInitializer . Initialize (
132156 ( IModel ) modelBuilder . Model , designTime : true , validationLogger : null ) ;
0 commit comments