{"record":{"id":"ae215f25e9478a28","repo":"dotnet/efcore","slug":"the-current-migration-sql-generator-sqlgenerator","errorCode":null,"errorMessage":"The current migration SQL generator '{sqlGeneratorType}' is unable to generate SQL for operations of type '{operationType}'.","messagePattern":"The current migration SQL generator '(.+?)' is unable to generate SQL for operations of type '(.+?)'\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/EFCore.Relational/Migrations/MigrationsSqlGenerator.cs","lineNumber":156,"sourceCode":"    /// </summary>\n    /// <remarks>\n    ///     This method uses a double-dispatch mechanism to call one of the 'Generate' methods that are\n    ///     specific to a certain subtype of <see cref=\"MigrationOperation\" />. Typically database providers\n    ///     will override these specific methods rather than this method. However, providers can override\n    ///     this methods to handle provider-specific operations.\n    /// </remarks>\n    /// <param name=\"operation\">The operation.</param>\n    /// <param name=\"model\">The target model which may be <see langword=\"null\" /> if the operations exist without a model.</param>\n    /// <param name=\"builder\">The command builder to use to build the commands.</param>\n    protected virtual void Generate(\n        MigrationOperation operation,\n        IModel? model,\n        MigrationCommandListBuilder builder)\n    {\n        var operationType = operation.GetType();\n        if (!GenerateActions.TryGetValue(operationType, out var generateAction))\n        {\n            throw new InvalidOperationException(RelationalStrings.UnknownOperation(GetType().ShortDisplayName(), operationType));\n        }\n\n        generateAction(this, operation, model, builder);\n    }\n\n    /// <summary>\n    ///     Builds commands for the given <see cref=\"AddColumnOperation\" /> by making calls on the given\n    ///     <see cref=\"MigrationCommandListBuilder\" />.\n    /// </summary>\n    /// <param name=\"operation\">The operation.</param>\n    /// <param name=\"model\">The target model which may be <see langword=\"null\" /> if the operations exist without a model.</param>\n    /// <param name=\"builder\">The command builder to use to build the commands.</param>\n    /// <param name=\"terminate\">Indicates whether or not to terminate the command after generating SQL for the operation.</param>\n    protected virtual void Generate(\n        AddColumnOperation operation,\n        IModel? model,\n        MigrationCommandListBuilder builder,\n        bool terminate = true)","sourceCodeStart":138,"sourceCodeEnd":174,"githubUrl":"https://github.com/dotnet/efcore/blob/3a2006ef569de08368d59db5e1468aa8f407e4f8/src/EFCore.Relational/Migrations/MigrationsSqlGenerator.cs#L138-L174","documentation":"MigrationsSqlGenerator.Generate(MigrationOperation, ...) dispatches by operation type via a prebuilt GenerateActions table keyed on the runtime operation type. If no entry exists for operation.GetType() (i.e. no Generate overload was registered for that type), it throws UnknownOperation. This usually means a custom MigrationOperation subclass was emitted that neither the base nor the provider generator knows how to render.","triggerScenarios":"A custom MigrationOperation subclass is added to a migration's operations but the provider's MigrationsSqlGenerator has no matching Generate overload; an operation from a newer EF version is fed to an older/unextended provider; a plugin/extension registers an operation without also extending the SQL generator.","commonSituations":"Custom operation authored for one provider (e.g. SQLite) then run against another (e.g. SQL Server) whose generator was not extended; EF Core upgrade introduced a new operation type that the provider package version predates.","solutions":["Subclass the provider's MigrationsSqlGenerator and add a Generate(YourCustomOperation, IModel, MigrationCommandListBuilder) overload, then register it via options.Use[Provider](b => b.MigrationsAssembly(...).ReplaceService<IMigrationsSqlGenerator, YourGenerator>()).","If using a stock operation type, upgrade the database provider package to a version that implements its Generate method.","Avoid emitting the unsupported operation; replace it with one the provider already supports."],"exampleFix":"// before — custom operation throws at SQL generation\npublic class CreateViewOperation : MigrationOperation { /* ... */ }\n\n// after — teach the generator to handle it\npublic class MySqlGenerator : SqlServerMigrationsSqlGenerator\n{\n    public MySqlGenerator(MigrationsSqlGeneratorDependencies deps)\n        : base(deps) { }\n\n    protected override void Generate(\n        CreateViewOperation op, IModel? model, MigrationCommandListBuilder builder)\n    {\n        builder.AppendLine(\"CREATE VIEW \")\n               .Append(Dependencies.SqlGenerationHelper.DelimitIdentifier(op.Name))\n               .AppendLine(\" AS \").AppendLines(op.Body)\n               .EndCommand();\n    }\n}\n\n// register\noptions.UseSqlServer(conn,\n    sql => sql.ReplaceService<IMigrationsSqlGenerator, MySqlGenerator>());","handlingStrategy":"type-guard","validationCode":"// Before generating SQL, confirm the generator can handle each operation type\nvar gen = db.GetService<IMigrationsSqlGenerator>();\nvar handled = db.GetService<Type>() // placeholder — see typeGuard for runtime check\n    is not null;","typeGuard":"// Check that a Generate method exists for the custom operation type\nstatic bool GeneratorSupports(IMigrationsSqlGenerator gen, Type opType)\n{\n    return gen.GetType().GetMethods(BindingFlags.Instance |\n            BindingFlags.NonPublic | BindingFlags.Public)\n        .Any(m => m.Name == \"Generate\"\n               && m.GetParameters() is { Length: 3 } p\n               && p[0].ParameterType.IsAssignableFrom(opType));\n}","tryCatchPattern":null,"preventionTips":["When authoring a custom MigrationOperation, also extend the provider's MigrationsSqlGenerator.","Pin provider package versions so operation/generator capabilities stay in sync.","Add a test that runs each migration's operations through the generator."],"tags":["migrations","sql-generation","provider","extensibility"],"backgroundTag":null,"analyzedSha":"3a2006ef569de08368d59db5e1468aa8f407e4f8","analyzedAt":"2026-08-11T23:42:04.146Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}