Мы обновили .NET 6 до .NET 8, и теперь инструмент dotnet-ef генерирует символы новой строки между ними, что sqlcmd не нравится. Это база данных SQL Azure с уровнем совместимости 150.
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"
Сообщение 102, Уровень 15, Состояние 1, Сервер скрыт, Строка 11
Неправильный синтаксис рядом с ';'
Я запустил SQL вручную, и кажется, что это не пустое BEGIN...END:
IF NOT EXISTS (
SELECT * FROM [Historical].[EFMigration]
WHERE [MigrationId] = N'20210814000018_AddSPHedgeReport'
)
BEGIN
END;
GO
EF 6 не использовался для создания этого.
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);
}
}
}
}
@DavidG обновлен. Это пусто BEGIN END;
Итак, вы на самом деле утверждаете, что EF теперь генерирует IF, внутри которого ничего не сказано IF?
@ThomA, да. В файлах миграции ничего не изменилось. Были обновлены только версии .NET и EF Core с 6 по 8.
На самом деле я не уверен, как EF вообще мог это сгенерировать, поскольку в пустой миграции даже не было бы этого блока. Что на самом деле делает миграция 20210814000018_AddSPHedgeReport?
Содержит ли созданная миграция что-нибудь?
@DavidG, я тоже не уверен. Я только что поделился кодом миграции
@phuzi, да. Я только что поделился кодом миграции.
Использует ли какая-либо из предыдущих миграций помощник сценария?
Привет, нет, измените свой ScriptHelper по этой ссылке и сообщите нам результат.
@phuzi, все буквально то же самое. Я только что использовал WinMerge для сравнения обеих веток .net 6 и .net 8.
@phuzi, я только что это сделал, но, похоже, ничего не изменилось. Обратите внимание, что я только обновил класс ScriptHelper и ничего не изменил в миграции, после чего я создал новый сценарий миграции, который запустил непосредственно в SSMS, поскольку он показывает, какие строки кода вызывают проблемы.
Можете ли вы точно проверить, почему строка SQL извлекается методом RunScripts?
@JasonPan Если строка sql была пустой, то migrationBuilder.Sql все равно выдаст исключение.
@DavidG, это вызвано ScriptHelper, потому что, когда я закомментировал migrationBuilder.RunScripts("20210813"), он исчез. Вот содержимое «..._20210813.sql»: astebin.com/e20HUJFz . Не все миграции, в которых используется класс ScriptHelper, генерируют пустой BEGIN-END, что означает, что, вероятно, это что-то в файле .sql, на которое ссылается вызов метода RunScripts.
Я имел в виду то, что находится в реальной переменной sql, возможно, ваш метод RunScripts вытаскивает что-то странное, вам следует это отладить.
Еще один момент, который следует проверить: какую версию EF вы используете и актуальна ли она?
@nop Попробуйте это обновление еще раз.Спасибо за терпение.
@JasonPan Этот код бессмысленен и потенциально может нарушить выполняемый SQL, поскольку он требует наличия BEGIN и END. Проблема не в том, что исполняемый SQL содержит пустой блок BEGIN/END, а в том, что EF его генерирует.
@JasonPan, кажется, у меня это только что получилось. Сейчас тестирую пайплайны, но локально всё заработало. astebin.com/0QQWZrBm -> Я только что добавил .Trim()
@JasonPan, это сработало. Окончательно! Не могли бы вы отправить pastebin.com/0QQWZrBm в качестве ответа, поскольку именно вы предложили изменение. Просто нужен был Trim()
Привет, нет, готово. Спасибо за вашу доброту, хорошего вам дня.
Вам также большое спасибо и хорошего дня/вечера!





Использование метода 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);
}
}
}
}
Эти операторы SQL по сути идентичны, и нет никаких причин, по которым они могут потерпеть неудачу.