f# - F# - FSharp.Data.SqlClient - 获取标识值后更新行
问题描述
假设我有以下内容:
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>
应用程序配置
<?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>
我需要从表中获取 SQL 标识值ModelData
。它在代码中的某处使用。所以,我有以下函数来添加一个带有一些默认值的新行,然后取回标识值。
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
类型提供程序的一些东西。我会很感激任何建议。
解决方案
首先是最明显的错误: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()
- 随心所欲地使用此 GUID 值,然后当您准备好持久化模型时,使用 SQL DML对字段
INSERT
使用相同的 GUIDmodelUid
请注意,通过这种方法,您也只使用类型提供程序SqlCommandProvider
的FSharp.Data.SqlClient
类型,因此事情保持简单。
推荐阅读
- python - K-Arms Bandit Epsilon-贪婪策略
- c++ - 如何在 Visual Studio C++ 中将西里尔文(俄语)字符输出到控制台?
- sql - SAS - 由于 Select 中的 case 语句,Group By 无法工作
- apache-beam - 如何在 Apache Beam 中实现类似于 Spark 的累加器的变量
- python - Python 3 + Click:当从另一个命令调用一个命令时,CLI 参数会被破坏
- sql - 不能混合聚合值和非聚合值
- swift - iOS - 使用 linphone 4.4.0 不会增加呼叫会议持续时间
- javascript - TypeError:AWS.Location 不是构造函数
- django - 其中哪个是 django 中最昂贵的查询?
- api - 来自多个不同 REST 调用的数据的有序分页