如何在 EF Core 中跳过一些迁移?

5

我在EF上下文中进行了一些更改,并添加了新的迁移。

dotnet ef migrations add changed98112601

然后我运行以下命令

dotnet ef database update

我有以下输出。看起来想要应用初始迁移。诗歌表在数据库中,因为它是通过应用初始迁移创建的。我该如何防止这种情况发生?当我想要更新时,该如何跳过初始迁移?
Build started...
Build succeeded.
Applying migration '20191225133128_Initial'.
Failed executing DbCommand (159ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
CREATE TABLE [Poems] (
    [Id] int NOT NULL IDENTITY,
    [Number] int NOT NULL,
    [Meaning] nvarchar(max) NULL,
    CONSTRAINT [PK_Poems] PRIMARY KEY ([Id])
);
Microsoft.Data.SqlClient.SqlException (0x80131904): There is already an object named 'Poems' in the database.
   at Microsoft.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction) in E:\agent1\_work\34\s\src\Microsoft.Data.SqlClient\netcore\src\Microsoft\Data\SqlClient\SqlConnection.cs:line 1591
   at Microsoft.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction) in E:\agent1\_work\34\s\src\Microsoft.Data.SqlClient\netcore\src\Microsoft\Data\SqlClient\SqlInternalConnection.cs:line 618
   at Microsoft.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose) in E:\agent1\_work\34\s\src\Microsoft.Data.SqlClient\netcore\src\Microsoft\Data\SqlClient\TdsParser.cs:line 1169
   at Microsoft.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady) in E:\agent1\_work\34\s\src\Microsoft.Data.SqlClient\netcore\src\Microsoft\Data\SqlClient\TdsParser.cs:line 1719
   at Microsoft.Data.SqlClient.SqlCommand.RunExecuteNonQueryTds(String methodName, Boolean isAsync, Int32 timeout, Boolean asyncWrite) in E:\agent1\_work\34\s\src\Microsoft.Data.SqlClient\netcore\src\Microsoft\Data\SqlClient\SqlCommand.cs:line 2857
   at Microsoft.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource`1 completion, Boolean sendToPipe, Int32 timeout, Boolean& usedCache, Boolean asyncWrite, Boolean inRetry, String methodName) in E:\agent1\_work\34\s\src\Microsoft.Data.SqlClient\netcore\src\Microsoft\Data\SqlClient\SqlCommand.cs:line 1395
   at Microsoft.Data.SqlClient.SqlCommand.ExecuteNonQuery() in E:\agent1\_work\34\s\src\Microsoft.Data.SqlClient\netcore\src\Microsoft\Data\SqlClient\SqlCommand.cs:line 974
   at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteNonQuery(RelationalCommandParameterObject parameterObject)
   at Microsoft.EntityFrameworkCore.Migrations.MigrationCommand.ExecuteNonQuery(IRelationalConnection connection, IReadOnlyDictionary`2 parameterValues)
   at Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationCommandExecutor.ExecuteNonQuery(IEnumerable`1 migrationCommands, IRelationalConnection connection)
   at Microsoft.EntityFrameworkCore.Migrations.Internal.Migrator.Migrate(String targetMigration)
   at Microsoft.EntityFrameworkCore.Design.Internal.MigrationsOperations.UpdateDatabase(String targetMigration, String contextType)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.UpdateDatabaseImpl(String targetMigration, String contextType)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.UpdateDatabase.<>c__DisplayClass0_0.<.ctor>b__0()
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action)
ClientConnectionId:b1027e70-d231-407a-87a0-5b53d06d2782
Error Number:2714,State:6,Class:16
There is already an object named 'Poems' in the database.

1
看起来你正在更新数据库,而数据库中已经存在一个对象Poems。 - jdweng
是的,Poems表在数据库中。因为它是通过应用初始迁移创建的。 - mohsen
诗歌表是否也是 DotNet EF 迁移的一部分?您能否手动将该迁移添加到 __EFMigrationsHistory 表中? - nickfinity
你尝试过这个吗?https://dev59.com/t3A65IYBdhLWcg3w2iep#6143116 - Tony Ngo
你可以通过更改 Migrations/ 文件夹下的迁移文件中生成的代码来绕过它:在 Up() 方法中删除 CreateTable(name:'Poems',...) 的相关代码。注意:如果您想这样做,请在将来手动更改数据库时同步更改。 - itminus
1个回答

1

我知道这个问题是两年前提出的,所以我猜mohsen不再需要它了,但是也许对其他人有用。

在我的情况下,我必须检查当执行迁移脚本时表是否已经存在,因为第一个迁移脚本没有被执行,因此不在__EFMigrationsHistory表中。第一个迁移脚本中的表在数据库中存在(可能手动创建)。我想保持迁移的完整性,所以当从头创建数据库时,会像通常一样执行迁移,如果表已经存在,则跳过第一个迁移脚本。

更新到您的情况:

public class DbInitializer
{
    private const string CreateMigrationsTable = @"
                    IF NOT EXISTS(SELECT 1 FROM [INFORMATION_SCHEMA].[TABLES]
                    WHERE TABLE_NAME = '__EFMigrationsHistory')
                    CREATE TABLE [dbo].[__EFMigrationsHistory](
                        [MigrationId] [nvarchar](150) NOT NULL,
                        [ProductVersion] [nvarchar](32) NOT NULL,
                     CONSTRAINT [PK___EFMigrationsHistory] PRIMARY KEY CLUSTERED 
                    (
                        [MigrationId] ASC
                    )WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
                    ) ON [PRIMARY]
                ";
                
    private const string InsertInitialMigration = @"
                    IF EXISTS(SELECT 1 FROM [INFORMATION_SCHEMA].[TABLES]
                    WHERE TABLE_NAME = 'Poems')
                    INSERT INTO [dbo].[__EFMigrationsHistory] (MigrationId, ProductVersion)
                    VALUES ('20191225133128_Initial', '5.0.8')
                ";
    private const string InsertSecondMigration = @"
                    IF EXISTS(SELECT 1 FROM [INFORMATION_SCHEMA].[TABLES]
                    WHERE TABLE_NAME = 'Poems')
                    INSERT INTO [dbo].[__EFMigrationsHistory] (MigrationId, ProductVersion)
                    VALUES ('20220420132739_Second', '5.0.8')
                ";

    public static void Initialize(DbContext context)
    {
        var pendingMigrations = context.Database.GetPendingMigrations().ToList();

        if (pendingMigrations.Any())
        {                
            if (pendingMigrations.Contains("20191225133128_Initial"))
            {
                // If the tabel doesn't exists, it needs to be created
                if (context.Database.EnsureCreated())
                {                                                
                    context.Database.ExecuteSqlRaw(CreateMigrationsTable);

                    // If it is created all migrations need to be added in the migrations table
                    context.Database.ExecuteSqlRaw(InsertInitialMigration);
                    context.Database.ExecuteSqlRaw(InsertSecondMigration);
                }
                else
                {
                    context.Database.ExecuteSqlRaw(CreateMigrationsTable);
                    context.Database.ExecuteSqlRaw(InsertInitialMigration);
                }
            }

            // If the table was already there, a call to Migrate will add the second migration
            context.Database.Migrate();                
        }            
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接