I am trying to use SqlCommandProvider (part of FSharp.Data.SqlClient) to create a column if it does not exist and then set a constraint (self referencing). The problems is that it will not compile because it detects that the column as part of the constraint does not yet exist. I tried wrapping it in another IF block to no avail.
[<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>
I would greatly prefer not to use dynamic sql. I was wondering if there was a way to defer evaluation so that it would run properly (note, the query itself runs fine in SQL Management Studio)
Error 1 The type provider 'FSharp.Data.SqlCommandProvider' reported an error: Foreign key 'FK_ParentIdCustomerId' references invalid column 'ParentId' in referencing table 'Company'. Could not create constraint. See previous errors.
The brief answer is "No, this cannot be done".
The more elaborate answer is "This cannot be done for the fundamental reason: run time database schema features should be already present at compile time in order to be anyhow utilized by FSharp.Data.SqlClient
type provider".
Just from the academic interest standpoint, it is not a problem (although a quite unusual practice) creating an extra column and a constraint in a database at run time and there is no need to involve dynamic SQL for this purpose. Can be easily achieved by using plain ADO side by side with type provider:
use cmd = new System.Data.SqlClient.SqlCommand(CreateParentColumn, connectionString)
cmd.ExecuteNonQuery() |> ignore
The actual problem though is that this freshly created column cannot be of any use in FSharp.Data.SqlClient
type provider context as it does not
exist yet in database schema at compile time to be anyhow utilized by the type provider.
Rephrasing, FSharp.Data.SqlClient
type provider does not perform any action at run time, its job has been already completed at compile time.