假设我具有以下条件:
SQL
创建名为Clm
的数据库,然后运行以下脚本:
CREATE TABLE dbo.ModelData(
modelId bigint IDENTITY(1,1) NOT NULL,
numberOfAminoAcids int NOT NULL,
maxPeptideLength int NOT NULL,
seed int NOT NULL,
fileStructureVersion nvarchar(50) NOT NULL,
modelData nvarchar(max) NOT NULL,
createdOn datetime NOT NULL,
CONSTRAINT PK_ModelData PRIMARY KEY CLUSTERED
(
modelId ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON PRIMARY
) ON PRIMARY TEXTIMAGE_ON PRIMARY
GO
ALTER TABLE dbo.ModelData ADD CONSTRAINT DF_ModelData_createdOn DEFAULT (getdate()) FOR createdOn
GO
F#
[<Literal>]
let ClmDbName = "Clm"
[<Literal>]
let AppConfigFile = __SOURCE_DIRECTORY__ + "\.\App.config"
[<Literal>]
let ClmConnectionString = "Server=localhost;Database=" + ClmDbName + ";Integrated Security=SSPI"
[<Literal>]
let ClmSqlProviderName = "name=" + ClmDbName
type ClmDB = SqlProgrammabilityProvider<ClmSqlProviderName, ConfigFile = AppConfigFile>
type ModelDataTable = ClmDB.dbo.Tables.ModelData
type ModelDataTableRow = ModelDataTable.Row
type ModelDataTableData =
SqlCommandProvider<"select * from dbo.ModelData where modelId = @modelId", ClmConnectionString, ResultType.DataReader>
App.config
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
</startup>
<connectionStrings configSource="db.config" />
<runtime>
<gcAllowVeryLargeObjects enabled="true" />
</runtime>
</configuration>
db.config
<connectionStrings>
<add name="Clm" connectionString="Data Source=localhost;Initial Catalog=Clm;Integrated Security=SSPI" />
</connectionStrings>
我需要从表ModelData
中获取SQL身份值。它在代码中的某处使用。因此,我具有以下功能,以使用一些默认值添加新行,然后返回标识值。
let getNewModelDataId (conn : SqlConnection) =
let t = new ModelDataTable()
let r =
t.NewRow(
numberOfAminoAcids = 0,
maxPeptideLength = 0,
seed = 0,
fileStructureVersion = "",
modelData = "",
createdOn = DateTime.Now
)
t.Rows.Add r
t.Update(conn) |> ignore
r.modelId
let openConnIfClosed (conn : SqlConnection) =
match conn.State with
| ConnectionState.Closed -> do conn.Open()
| _ -> ignore ()
然后我用它来从数据库中获取modelId
的新标识值。
let modelId = getNewModelDataId conn
大约0.5-1.5小时的执行时间后,我需要更新一些数据,例如
use d = new ModelDataTableData(conn)
let t1 = new ModelDataTable()
d.Execute(modelId = modelId) |> t1.Load
let r1 = t1.Rows |> Seq.find (fun e -> e.modelId = modelId)
r1.modelData <- "Some new data..."
t1.Update(conn) |> ignore
其中字符串"Some new data..."
表示一些相当大的字符串。每个modelId
仅发生一次。
上面的代码可以工作。但这看起来很丑,尤其是t1.Rows |> Seq.find ...
部分。我想我缺少关于FSharp.Data.SqlClient
类型提供程序的东西。我将不胜感激。
答案 0 :(得分:0)
从最明显的错误开始:FSharp.Data.SqlClient
类型提供者通过其SqlCommandProvider
支持任何DML数据修改语句,包括UPDATE
。所以,
...
use cmd = SqlCommandProvider<
"UPDATE [dbo].[ModelData] SET [modelData]=@ModelData WHERE [modelId]=@ModelId",
conn>(conn)
cmd.Execute(ModelData="Some new data...", ModelId=modelId) |> ignore
...
不太明显的问题与identity field
的使用有关。听起来,除了唯一地标识每个新模型之外,它没有任何特殊作用。因此,与其修补虚假记录,不如从服务器中提取其id
,然后使用真实值更新具有此id
的记录,为什么不做:
modelUid
GUID
生成新的System.Guid.NewGuid()
来创建每个新模型INSERT
对modelUid
字段使用相同的GUID 请注意,通过这种方法,您也只使用了SqlCommandProvider
类型的FSharp.Data.SqlClient
类型的提供程序,因此事情变得简单了。