4

I have to created a database through Entity Framework 5 with the following model:

public class Post
{
        public int PostId { get; set; }
        [MaxLength(200)]
        public string Title { get; set; }
        public string Content { get; set; }

        public int BlogId { get; set; }
        public Blog Blog { get; set; }
}

Then I have added new property in Post

public string Abstract { get; set; }

then I have run

Add-Migration AddPostAbstract

which created the following class in my Migrations folder, after that I have modified this file by adding one more SQL statement

//201308300714477_AddPostAbstract.cs
public override void Up()
{
                AddColumn("dbo.Posts", "Abstract", c => c.String());
                Sql("UPDATE dbo.Posts SET Abstract = LEFT(Content, 100) WHERE Abstract IS NULL");
}

public override void Down()
{
    DropColumn("dbo.Posts", "Abstract");
}

After that I have executed this command

Update-Database –Verbose

which updated my database and also returned this SQL query:

ALTER TABLE [dbo].[Posts] ADD [Abstract] [nvarchar](max)
UPDATE dbo.Posts SET Abstract = LEFT(Content, 100) WHERE Abstract IS NULL

Now I have deleted Abstract column from table and tried to execute the above query manually in SQL at that time it show me following error.

Msg 207, Level 16, State 1, Line 2
Invalid column name 'Abstract'.

My question is why this query is not executed in SQL even this query is generated through migration?

Or is there any way to run such multiple query through migration generated script.

4

1 回答 1

12

输出仅显示语句摘要-Verbose。如果您在 SQL Server Management Studio 中手动运行命令,则需要GO在两个语句之间添加:

ALTER TABLE [dbo].[Posts] ADD [Abstract] [nvarchar](max)
GO
UPDATE dbo.Posts SET Abstract = LEFT(Content, 100) WHERE Abstract IS NULL

快速解决方法是执行以下操作:

  • 更新数据库脚本
  • 然后使用 Sql Server management Studio 在生成的脚本中进行如下搜索和替换:
    • 找到什么:(^{:b*}{{INSERT|UPDATE|SELECT|DELETE}.+}这会找到任何 CRUD 语句
    • 替换为:(\1GO\n\1\2\n保留缩进,并GO在任何 CRUD 语句之前添加)
    • 查找选项:使用正则表达式

但是,请注意,-Verbose它不会为您提供所需的输出,您需要来自 的输出-Script,否则您将丢失__MigrationHistory历史表的插入数据,这可能导致您的应用程序在运行时抛出错误(有关详细信息,请参见下文) .

细节

您在下面关于MSDN Code First Migrations 页面上的信息的评论很有趣。该页面实际声明(在“获取 SQL 脚本”部分下)

运行 Update-Database 命令,但这次指定 –Script 标志

如果你这样做,你会看到类似的东西:

ALTER TABLE [dbo].[Posts] ADD [Abstract] [nvarchar](max)
UPDATE dbo.Posts SET Abstract = LEFT(Content, 100) WHERE Abstract IS NULL
INSERT INTO [__MigrationHistory] ([MigrationId], [Model], [ProductVersion]) VALUES ( ...

INSERT很重要 - 这就是您的应用程序中的 EF 如何知道它正在使用最新的数据库版本(因此将运行而不是向您显示错误)。但是,它仍然缺少 GO 命令。因此,SQL Server 尝试将 3 行编译为单个批处理并失败。

添加GO您需要的语句后,您仍然可以在单个事务中运行它,方法是将其包围:

BEGIN TRANSACTION;
BEGIN TRY
   --Your migration code, with GO statements
END TRY
BEGIN CATCH
  SELECT 
    ERROR_NUMBER() AS ErrorNumber
    ,ERROR_SEVERITY() AS ErrorSeverity
    ,ERROR_STATE() AS ErrorState
    ,ERROR_PROCEDURE() AS ErrorProcedure
    ,ERROR_LINE() AS ErrorLine
    ,ERROR_MESSAGE() AS ErrorMessage;

  IF @@TRANCOUNT > 0
    ROLLBACK TRANSACTION;
END CATCH;

IF @@TRANCOUNT > 0
  COMMIT TRANSACTION;
GO

如果您因为生成大型脚本而感到沮丧,那么GO在任何行的末尾ALTER TABLE加上 SSMS 中的 replace 都是微不足道的,这就像这个答案顶部的那个

于 2013-08-30T08:37:44.267 回答