npgsql / efcore.pg

Entity Framework Core provider for PostgreSQL
PostgreSQL License
1.52k stars 223 forks source link

replacing IMigrationsSqlGenerator with custom implementation #3035

Open epitka opened 8 months ago

epitka commented 8 months ago

Hi, I wanted to create a custom implementation of the IMigrationsSqlGenerator. For a test I created just a NoOp one and registered it like this

            optionsBuilder.UseNpgsql(
                connectionString,
                o => o.SetPostgresVersion(
                    BaseEnvironmentConfig.PostgresMajorVersion,
                    BaseEnvironmentConfig.PostgresMinorVersion))
                .ReplaceService<IMigrationsSqlGenerator, NoOpSqlGenerator>();

This however does not seem to have any effect.

Running dotnet ef migrations add mytest creates migrations as if it was not registered at all. In ctor I log it, and NoOpSqlGenerator gets instantiated.

    public class NoOpSqlGenerator : IMigrationsSqlGenerator
    {
        public NoOpSqlGenerator()
        {
            Console.WriteLine("Instantiated NoOpSqlGenerator");
        }
        public IReadOnlyList<MigrationCommand> Generate(
            IReadOnlyList<MigrationOperation> operations,
            IModel model = null,
            MigrationsSqlGenerationOptions options = MigrationsSqlGenerationOptions.Default)
        {
        }
    }

Is it not possible to replace generator?

roji commented 8 months ago

This should definitely work - but you may need to read up on how EF locates the design-time DbContext (in other words, make sure your OnConfiguring actually gets called etc.

epitka commented 8 months ago

It gets called definitively, generator is instantiated, but Generate is never called. I confirmed this by logging out steps.

roji commented 8 months ago

I'm not following... you're saying it gets called, but not some specific code path? Maybe you can submit a minimal code sample to show what's going on?

epitka commented 8 months ago

Sure, here is NoOp one, I would expect Exception to be thrown, but it does not

    public class NoOpSqlGenerator : IMigrationsSqlGenerator
    {
        public NoOpSqlGenerator()
        {
            Console.WriteLine("Instantiated NoOpSqlGenerator");
        }
        public IReadOnlyList<MigrationCommand> Generate(
            IReadOnlyList<MigrationOperation> operations,
            IModel model = null,
            MigrationsSqlGenerationOptions options = MigrationsSqlGenerationOptions.Default)
        {
            throw new NotImplementedException();
        }
    }

and in DbContextFactory

 Console.WriteLine("CreateDBContext called");            
 optionsBuilder.UseNpgsql(
                connectionString,
                o => o.SetPostgresVersion(
                    BaseEnvironmentConfig.PostgresMajorVersion,
                    BaseEnvironmentConfig.PostgresMinorVersion))
                .ReplaceService<IMigrationsSqlGenerator, NoOpSqlGenerator>();
roji commented 8 months ago

Are you maybe expecting IMgrationsSqlGenerator to be used when executing dotnet ef migrations add? If so, that's not the case - no SQL is produced at that step, since migrations only contain operations in a higher-level .NET DSL. Actual SQL is only generated when applying migrations to the database (or generating a migration SQL script with dotnet ef migrations script) - that's when you should see the exception.