2

我正在尝试使用 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' 在引用表 'Company' 中引用了无效列 'ParentId'。无法创建约束。请参阅以前的错误。

4

1 回答 1

2

简短的回答是“不,这不能做”

更详细的答案是“这根本原因无法做到:运行时数据库模式特性应该在编译时已经存在,以便 FSharp.Data.SqlClient 类型提供程序无论如何都可以使用”

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

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

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

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

于 2015-09-10T15:45:07.777 回答