简体   繁体   English

F#-FSharp.Data.SqlClient-获取身份值后更新行

[英]F# - FSharp.Data.SqlClient - update row after getting identity value

Let's say that I have the following: 假设我有以下几点:

SQL SQL

Create database called Clm , then run this script: 创建名为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# 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 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 db.config

<connectionStrings>
    <add name="Clm" connectionString="Data Source=localhost;Initial Catalog=Clm;Integrated Security=SSPI" />
</connectionStrings>

I need to get SQL identity value from table ModelData . 我需要从表ModelData获取SQL身份值。 It is used somewhere in the code. 它在代码中的某处使用。 So, I have the following function to add a new row with some default values and then get identity value back. 因此,我具有以下功能,以使用一些默认值添加新行,然后返回标识值。

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 ()

And the I use it to get new identity value of modelId from the database. 我使用它从数据库中获取modelId新标识值。

let modelId = getNewModelDataId conn

The after about 0.5 – 1.5 hours of execution time I need to update some data, eg 在大约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

where the string "Some new data..." represents some fairly large string. 字符串"Some new data..."表示一些相当大的字符串。 This only happens once per modelId . 每个modelId仅发生一次。 The code above does work . 上面的代码可以正常工作 But it looks soooo ugly, epsecially the part t1.Rows |> Seq.find ... ☹ I guess that I am missing something about FSharp.Data.SqlClient type providers. 但是它看起来非常丑陋,尤其是t1.Rows |> Seq.find ...我想我缺少有关FSharp.Data.SqlClient类型提供程序的信息。 I'd appreciate any advice. 我将不胜感激任何建议。

To begin with the most obvious blunder: FSharp.Data.SqlClient type provider via its SqlCommandProvider supports any DML data modification statements, including UPDATE . 首先介绍最明显的错误: FSharp.Data.SqlClient类型提供程序通过其SqlCommandProvider支持任何DML数据修改语句,包括UPDATE So, instead of all that jazz with pulling the model to the client side, modifying, and pushing back to the server, the same can be achieved by 因此,除了将模型拉到客户端,修改并推回服务器之外,所有这些爵士乐都可以通过以下方式实现:

...
use cmd = SqlCommandProvider<
              "UPDATE [dbo].[ModelData] SET [modelData]=@ModelData WHERE [modelId]=@ModelId",
               conn>(conn)
cmd.Execute(ModelData="Some new data...", ModelId=modelId) |> ignore
...

The less obvious problem relates to the use of identity field . 不太明显的问题与identity field的使用有关。 It sounds like it does not have any special role beyond uniquely identifying every new model. 听起来,除了唯一地标识每个新模型之外,它没有任何特殊作用。 So, instead of the tinkering with creating a fake record, then pulling its id from the server, then updating the record having this id with real values, why not just: 因此,与其修补虚假记录,而不是从服务器中提取其id ,然后使用真实值更新具有该id的记录,不如:

  • introduce an additional column modelUid of type uniqueidentifier 引入额外的列modelUid类型为uniqueidentifier
  • add a nonclustered index on it, if this matters 如果这很重要,请在其上添加非聚集索引
  • begin creating of every new model by generating a fresh GUID with System.Guid.NewGuid() 通过使用System.Guid.NewGuid()生成新的GUID开始创建每个新模型
  • use this GUID value whatever you want, then when you ready to persist your model do it with SQL DML INSERT using the same GUID for modelUid field 随便使用此GUID值,然后在准备持久保存模型时,使用SQL DML INSERT对它使用相同的GUID作为modelUid字段即可

Notice, that with such approach you also use just SqlCommandProvider type of FSharp.Data.SqlClient type provider, so the things stay simple. 注意,通过这种方法,您还只使用了FSharp.Data.SqlClient类型提供程序的SqlCommandProvider类型,因此事情保持简单。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM