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>
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>
Мне нужно получить значение идентификатора 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 ...
Guess Я думаю, что я что-то упускаю из FSharp.Data.SqlClient
Тип провайдеров. Буду признателен за любой совет.
1 ответ
Для начала самая очевидная ошибка: 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
используя тот же GUID дляmodelUid
поле
Обратите внимание, что при таком подходе вы также используете просто SqlCommandProvider
тип FSharp.Data.SqlClient
Тип провайдера, так что все остается просто.