我必须通过Entity Framework 5使用以下模型创建数据库:
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; }
}
然后我在Post
public string Abstract { get; set; }
然后我跑了
Add-Migration AddPostAbstract
在我的Migrations
文件夹中创建了以下类,之后我通过添加一个SQL语句修改了这个文件
//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");
}
之后我执行了这个命令
Update-Database –Verbose
更新了我的数据库并返回了这个SQL查询:
ALTER TABLE [dbo].[Posts] ADD [Abstract] [nvarchar](max)
UPDATE dbo.Posts SET Abstract = LEFT(Content, 100) WHERE Abstract IS NULL
现在我已经从表中删除了Abstract
列,并尝试在SQL中手动执行上述查询,此时它会向我显示以下错误。
Msg 207,Level 16,State 1,Line 2
列名称无效'摘要'。
我的问题是为什么在SQL中不执行此查询,即使此查询是通过迁移生成的?
或者有没有办法通过迁移生成的脚本运行这样的多个查询。
答案 0 :(得分: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
快速解决方法是执行以下操作:
^{:b*}{{INSERT|UPDATE|SELECT|DELETE}.+}
(这可以找到任何CRUD语句)\1GO\n\1\2\n
(保留缩进,并在任何CRUD语句之前添加GO
)但是,请注意-Verbose
没有为您提供所需的输出,您需要-Script
的输出,否则您将缺少__MigrationHistory
历史记录表的插入数据这可能会导致应用程序在运行时抛出错误(详见下文)。
<强>详情
以下关于MSDN Code First Migrations page信息的评论很有意思。该页面实际指出(在“获取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将如何知道它使用最新的db版本(因此将运行而不是向您显示错误)。但是,仍然缺少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中的替换是微不足道的,这类似于顶部的那个这个答案