Sqlcmd завершается с ошибкой из-за неправильного синтаксиса рядом с ';' после обновления до .NET 8

Мы обновили .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);
            }
        }
    }
}

Эти операторы SQL по сути идентичны, и нет никаких причин, по которым они могут потерпеть неудачу.

DavidG 05.09.2024 14:34

@DavidG обновлен. Это пусто BEGIN END;

nop 05.09.2024 14:41

Итак, вы на самом деле утверждаете, что EF теперь генерирует IF, внутри которого ничего не сказано IF?

Thom A 05.09.2024 14:43

@ThomA, да. В файлах миграции ничего не изменилось. Были обновлены только версии .NET и EF Core с 6 по 8.

nop 05.09.2024 14:50

На самом деле я не уверен, как EF вообще мог это сгенерировать, поскольку в пустой миграции даже не было бы этого блока. Что на самом деле делает миграция 20210814000018_AddSPHedgeReport?

DavidG 05.09.2024 14:58

Содержит ли созданная миграция что-нибудь?

phuzi 05.09.2024 14:58

@DavidG, я тоже не уверен. Я только что поделился кодом миграции

nop 05.09.2024 15:01

@phuzi, да. Я только что поделился кодом миграции.

nop 05.09.2024 15:01

Использует ли какая-либо из предыдущих миграций помощник сценария?

phuzi 05.09.2024 15:08

Привет, нет, измените свой ScriptHelper по этой ссылке и сообщите нам результат.

Jason Pan 05.09.2024 15:09

@phuzi, все буквально то же самое. Я только что использовал WinMerge для сравнения обеих веток .net 6 и .net 8.

nop 05.09.2024 15:12

@phuzi, я только что это сделал, но, похоже, ничего не изменилось. Обратите внимание, что я только обновил класс ScriptHelper и ничего не изменил в миграции, после чего я создал новый сценарий миграции, который запустил непосредственно в SSMS, поскольку он показывает, какие строки кода вызывают проблемы.

nop 05.09.2024 15:23

Можете ли вы точно проверить, почему строка SQL извлекается методом RunScripts?

DavidG 05.09.2024 15:41

@JasonPan Если строка sql была пустой, то migrationBuilder.Sql все равно выдаст исключение.

DavidG 05.09.2024 15:50

@DavidG, это вызвано ScriptHelper, потому что, когда я закомментировал migrationBuilder.RunScripts("20210813"), он исчез. Вот содержимое «..._20210813.sql»: astebin.com/e20HUJFz . Не все миграции, в которых используется класс ScriptHelper, генерируют пустой BEGIN-END, что означает, что, вероятно, это что-то в файле .sql, на которое ссылается вызов метода RunScripts.

nop 05.09.2024 16:00

Я имел в виду то, что находится в реальной переменной sql, возможно, ваш метод RunScripts вытаскивает что-то странное, вам следует это отладить.

DavidG 05.09.2024 16:05

Еще один момент, который следует проверить: какую версию EF вы используете и актуальна ли она?

DavidG 05.09.2024 16:10

@nop Попробуйте это обновление еще раз.Спасибо за терпение.

Jason Pan 05.09.2024 16:11

@JasonPan Этот код бессмысленен и потенциально может нарушить выполняемый SQL, поскольку он требует наличия BEGIN и END. Проблема не в том, что исполняемый SQL содержит пустой блок BEGIN/END, а в том, что EF его генерирует.

DavidG 05.09.2024 16:13

@JasonPan, кажется, у меня это только что получилось. Сейчас тестирую пайплайны, но локально всё заработало. astebin.com/0QQWZrBm -> Я только что добавил .Trim()

nop 05.09.2024 16:49

@JasonPan, это сработало. Окончательно! Не могли бы вы отправить pastebin.com/0QQWZrBm в качестве ответа, поскольку именно вы предложили изменение. Просто нужен был Trim()

nop 05.09.2024 17:14

Привет, нет, готово. Спасибо за вашу доброту, хорошего вам дня.

Jason Pan 05.09.2024 19:01

Вам также большое спасибо и хорошего дня/вечера!

nop 05.09.2024 19:36
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
23
69
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Использование метода 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);
            }
        }
    }
}

Другие вопросы по теме