efcore.pg icon indicating copy to clipboard operation
efcore.pg copied to clipboard

replacing IMigrationsSqlGenerator with custom implementation

Open epitka opened this issue 2 years ago • 5 comments

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?

epitka avatar Dec 22 '23 09:12 epitka

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.

roji avatar Dec 22 '23 18:12 roji

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

epitka avatar Jan 02 '24 14:01 epitka

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?

roji avatar Jan 02 '24 15:01 roji

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>();

epitka avatar Jan 02 '24 16:01 epitka

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.

roji avatar Jan 03 '24 07:01 roji