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
Тип провайдера не выполняет никаких действий во время выполнения, его работа уже выполнена во время компиляции.