F# SqlCommandProvider 将 eval 延迟到运行时

F# SqlCommandProvider defer eval until runtime

我正在尝试使用 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 中很好)

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.

简短的回答是"No, this cannot be done"

更详尽的答案是"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"

仅从学术兴趣的角度来看,在 运行 时间在数据库中创建额外的列和约束不是问题(尽管这是一种非常不寻常的做法)并且不需要涉及动态 SQL 用于此目的。可以通过将普通 ADO 与类型提供程序并排使用来轻松实现:

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

但实际问题是这个新创建的列在 FSharp.Data.SqlClient 类型提供程序上下文中没有任何用处,因为它不 在编译时还存在于数据库模式中,无论如何都可以被类型提供者使用。

换句话说,FSharp.Data.SqlClient 类型提供程序在 运行 时不执行任何操作,它的工作已经在编译时完成。