F# SqlCommandProvider отложить eval до времени выполнения

Я пытаюсь использовать SqlCommandProvider (часть FSharp.Data.SqlClient), чтобы создать столбец, если он не существует, а затем установить ограничение (самоссылка). Проблема в том, что он не будет компилироваться, потому что обнаружит, что столбец как часть ограничения еще не существует. Я попытался обернуть его в другой блок IF, но безрезультатно.

[<Literal>]
let CreateParentColumn = "
    IF COL_LENGTH('Company', 'ParentId') IS NULL
    BEGIN
        ALTER TABLE Company
        ADD ParentId INT

        ALTER TABLE Company
        ADD CONSTRAINT FK_ParentIdCompanyId FOREIGN KEY (ParentId)
        REFERENCES Company(CompanyId);
    END
"

type CreateParentIdColumn  = SqlCommandProvider<CreateParentColumn, connectionString>

Я бы предпочел не использовать динамический SQL. Мне было интересно, есть ли способ отложить оценку, чтобы она работала правильно (обратите внимание, что сам запрос прекрасно работает в SQL Management Studio)

Ошибка 1 Поставщик типа "FSharp.Data.SqlCommandProvider" сообщил об ошибке: внешний ключ "FK_ParentIdCustomerId" ссылается на недопустимый столбец "ParentId" в ссылочной таблице "Компания". Не удалось создать ограничение. Смотрите предыдущие ошибки.

1 ответ

Решение

Краткий ответ: "Нет, этого нельзя сделать".

Более сложный ответ: "Это невозможно сделать по фундаментальной причине: функции схемы базы данных времени выполнения должны присутствовать уже во время компиляции, чтобы в любом случае использоваться FSharp.Data.SqlClient провайдер типа ".

С точки зрения академического интереса, это не проблема (хотя и довольно необычная практика) создания дополнительного столбца и ограничения в базе данных во время выполнения, и для этой цели нет необходимости использовать динамический SQL. Это может быть легко достигнуто с помощью простого ADO рядом с поставщиком типов:

use cmd = new System.Data.SqlClient.SqlCommand(CreateParentColumn, connectionString)
cmd.ExecuteNonQuery() |> ignore

Однако реальная проблема заключается в том, что этот недавно созданный столбец не может быть использован в FSharp.Data.SqlClient контекст поставщика типа, так как он еще не существует в схеме базы данных во время компиляции, чтобы в любом случае использоваться поставщиком типа.

Перефразируя, FSharp.Data.SqlClient Тип провайдера не выполняет никаких действий во время выполнения, его работа уже выполнена во время компиляции.

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