我们从 .NET 6 升级到 .NET 8,现在 dotnet-ef 工具会在两者之间生成换行符,这是 sqlcmd 不喜欢的。它是兼容级别 150 的 Azure SQL 数据库。
dotnet ef migrations script --project hidden --startup-project hidden --output AppDbContext.sql --context AppDbContext --verbose --idempotent
sqlcmd -S "hidden" -d "hidden" -U "hidden" -P "hidden" -i "D:\AppDbContext.sql"
Msg 102, Level 15, State 1, Server hidden, Line 11
Incorrect syntax near ';'.
我手动运行了SQL,看起来它不是空的
BEGIN...END
:
IF NOT EXISTS (
SELECT * FROM [Historical].[EFMigration]
WHERE [MigrationId] = N'20210814000018_AddSPHedgeReport'
)
BEGIN
END;
GO
EF6 没有用来生成这个。
using Microsoft.EntityFrameworkCore.Migrations;
namespace hidden
{
public partial class AddSPHedgeReport : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string?>(
name: "FixedProperty",
schema: "Reports",
table: "SectionColumn",
nullable: true);
migrationBuilder.RunScripts("20210813");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "FixedProperty",
schema: "Reports",
table: "SectionColumn");
}
}
}
另一个失败的例子:
#nullable disable
using Microsoft.EntityFrameworkCore.Migrations;
namespace hidden
{
public partial class AuditTables : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.RunScripts("20220920");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
}
}
}
这是
ScriptHelper
的作用:
public static class ScriptHelper
{
public static void RunScripts(this MigrationBuilder migrationBuilder, string version)
{
var assembly = Assembly.GetExecutingAssembly();
var resourceNames = assembly.GetManifestResourceNames().Where(str => str.EndsWith(version + ".sql"));
foreach (var resourceName in resourceNames)
{
using (var stream = assembly.GetManifestResourceStream(resourceName))
using (var reader = new StreamReader(stream))
{
var sql = reader.ReadToEnd();
migrationBuilder.Sql(sql);
}
}
}
}
使用
Trim()
方法可以有效地删除 SQL 脚本中的前导和尾随空格,增强其兼容性并防止执行过程中出现与格式相关的错误。
public static class ScriptHelper
{
public static void RunScripts(this MigrationBuilder migrationBuilder, string version)
{
var assembly = Assembly.GetExecutingAssembly();
var resourceNames = assembly.GetManifestResourceNames().Where(str => str.EndsWith(version + ".sql"));
foreach (var resourceName in resourceNames)
{
using var stream = assembly.GetManifestResourceStream(resourceName);
using var reader = new StreamReader(stream);
//Removes white spaces or characters specified in an array of characters from the beginning and end of a string.
var sql = reader.ReadToEnd().Trim();
if (!string.IsNullOrWhiteSpace(sql))
{
migrationBuilder.Sql(sql);
}
}
}
}