Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrations: Handle GO statements in SQL Server #6747

Closed
patricknolan opened this issue Oct 10, 2016 · 8 comments
Closed

Migrations: Handle GO statements in SQL Server #6747

patricknolan opened this issue Oct 10, 2016 · 8 comments
Assignees
Labels
closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. good first issue This issue should be relatively straightforward to fix. help wanted This issue involves technologies where we are not experts. Expert help would be appreciated. type-enhancement
Milestone

Comments

@patricknolan
Copy link

patricknolan commented Oct 10, 2016

I need to run a separate sql script just after the migration Up logic is executed.
The following sample works fine, except the script is creating quite a few Stored Procedures etc which requires the use of GO statements.

However, the MigrationBuilder.Sql does not seem to support the GO statement. I haven't tried splitting into multiple script files but I would rather not do this as I would require a lot.

Is this something which will be supported soon. What would be the best workaround for the moment?

private class SomeMigration : Migration
{
    protected override void Up(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.Sql(File.ReadAllText(sqlFile));
    }

    protected override void Down(MigrationBuilder migrationBuilder)
    {
    }
}
@smitpatel
Copy link
Contributor

What is the error you are getting?

@patricknolan
Copy link
Author

The error we are getting is below. I have also included below a sample script. The real script attempts to create about 80 separate stored procedures which is why we need the GO statements.

ERROR:

Incorrect syntax near the keyword 'PROCEDURE'.
Must declare the scalar variable "@id".
Must declare the scalar variable "@id".
A RETURN statement with a return value cannot be used in this context.
Incorrect syntax near 'GO'.

at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action1 wrapCloseInAction) at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose) at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady) at System.Data.SqlClient.SqlCommand.RunExecuteNonQueryTds(String methodName, Boolean async, Int32 timeout, Boolean asyncWrite) at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource1 completion, Boolean sendToPipe, Int32 timeout, Boolean asyncWrite, String methodName)
at System.Data.SqlClient.SqlCommand.ExecuteNonQuery()
at Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommand.Execute(IRelationalConnection connection, String executeMethod, IReadOnlyDictionary2 parameterValues, Boolean openConnection, Boolean closeConnection) at Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommand.ExecuteNonQuery(IRelationalConnection connection, IReadOnlyDictionary2 parameterValues, Boolean manageConnection)
at Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationCommandExecutor.ExecuteNonQuery(IEnumerable`1 migrationCommands, IRelationalConnection connection)
at Microsoft.EntityFrameworkCore.Migrations.Internal.Migrator.Migrate(String targetMigration)
at e5.Repository.Program.Main(String[] args) in D:\temp\e5.Repository\src\e5.Repository\Program.cs:line 18

SAMPLE SCRIPT

GO

CREATE PROCEDURE [dbo].[Enterprise_Delete]
(
    @Id uniqueidentifier
)
AS
BEGIN
    SET NOCOUNT ON
    DECLARE @ErrorNumber    INTEGER     -- the error code.
    DECLARE @ErrorMessage   NVARCHAR(100)   -- error message to return

    DELETE [Enterprise]
    WHERE ([Id] = @Id)

    SELECT @ErrorNumber  = @@ERROR
    IF (@ErrorNumber != 0)
    BEGIN
        SELECT @ErrorMessage = 'DELETE error on Enterprise table.  Id=' + CONVERT(NVARCHAR(36),@Id)
        GOTO ENDERROR
    END

    -- **************
    -- Error Handling
    -- **************
    GOTO ENDOK

    ENDERROR:
        BEGIN
            DECLARE @Source NVARCHAR(500)
            SET @Source = 'SQLServer:' + ' DB_ID=' + CONVERT(NVARCHAR(10),DB_ID()) + ' DB_NAME=' + DB_NAME()
            SET @Source = @Source + ' SProcName=' + OBJECT_NAME(@@PROCID) 
            SET @Source = @Source + ' ErrorNumber=' + CONVERT(NVARCHAR(10),@ErrorNumber) + ' ErrorMessage=' + @ErrorMessage 
            RAISERROR (@Source , 16, 1)
        END

    ENDOK:
        RETURN @ErrorNumber
END

GO

@smitpatel
Copy link
Contributor

@patricknolan - Thanks for additional info. I tried running above script and I indeed hit error that Incorrect syntax near 'GO'.. When using MigrationBuilder.Sql method, EF appends ; & GO statements to SQL provided. If you remove the last GO from above SQL then migrations run successfully. There isn't anything specific migrations is doing apart from above which should prevent using GO in SQL.

@patricknolan
Copy link
Author

Thanks for the response. I removed the last GO and it still fails with the following error. If I remove the first GO aswell it works. However, to create multiple stored procedures I need to include the GO statement.

Any ideas why it is working for you and not me?

Incorrect syntax near the keyword 'PROCEDURE'.
Must declare the scalar variable "@id".
Must declare the scalar variable "@id".
A RETURN statement with a return value cannot be used in this context.

@smitpatel
Copy link
Contributor

smitpatel commented Oct 11, 2016

@patricknolan - I got it running because I had removed starting GO also (seemed unnecessary) and was declaring only 1 procedure.
Following is the content of my Data.sql https://gist.github.com/smitpatel/16f67640c8ae1f3947d85d281e299a5a

Running following piece of code in console app also throws same exception.

var myConnection = new SqlConnection(@"Server=(localdb)\mssqllocaldb;Database=_ModelApp;Trusted_Connection=True;");
myConnection.Open();
var command = new SqlCommand(File.ReadAllText("Data.sql"), myConnection);
command.ExecuteNonQuery();

Exception:

System.Data.SqlClient.SqlException: Incorrect syntax near 'GO'.
Must declare the scalar variable "@Idd".
Must declare the scalar variable "@Idd".
   at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
   at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
   at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
   at System.Data.SqlClient.SqlCommand.RunExecuteNonQueryTds(String methodName, Boolean async, Int32 timeout, Boolean asyncWrite)
   at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource`1 completion, Boolean sendToPipe, Int32 timeout, Boolean asyncWrite, String methodName)
   at System.Data.SqlClient.SqlCommand.ExecuteNonQuery()
   at ModelApp.Program.Main(String[] args)

It seems that underlying SqlClient is not able to handle it. EF just passes content of sql after appending ; GO to sql client.

The same sql works fine if run directly into SqlServer Management Studio.

@patricknolan
Copy link
Author

Do you know if there's an alternative recommended approach? I would have thought running a SQL script post the migration UP routine to create some stored procedures would be a fairly common requirement.

@bricelam
Copy link
Contributor

GO is just tooling sugar for starting a new command. You should be able to work around this be splitting at the GO statements and putting the parts into their own Sql call.

We did this for you in EF6. We should consider adding it to EF Core.

@rowanmiller rowanmiller changed the title MigrationBuilder.Sql does not support GO statement MigrationBuilder.Sql split on GO statement Oct 11, 2016
@rowanmiller rowanmiller added this to the 1.2.0 milestone Oct 11, 2016
@bricelam
Copy link
Contributor

Note to implementer: Here is the code for handling utility statements in EF6.

@bricelam bricelam added the help wanted This issue involves technologies where we are not experts. Expert help would be appreciated. label Feb 27, 2017
@bricelam bricelam added the closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. label Mar 8, 2017
@ajcvickers ajcvickers changed the title MigrationBuilder.Sql split on GO statement Migrations: Handle GO statements in SQL Server May 9, 2017
@bricelam bricelam added good first issue This issue should be relatively straightforward to fix. and removed good first issue This issue should be relatively straightforward to fix. labels May 31, 2019
@ajcvickers ajcvickers modified the milestones: 2.0.0-preview1, 2.0.0 Oct 15, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. good first issue This issue should be relatively straightforward to fix. help wanted This issue involves technologies where we are not experts. Expert help would be appreciated. type-enhancement
Projects
None yet
Development

No branches or pull requests

5 participants