我有以下F#代码
open FSharp.Data.Sql
open FSharp.Data.Sql.Runtime
open System.IO
[<Literal>]
let private schemaConn = @"Driver={Microsoft dBASE Driver (*.dbf)};DriverID=277;Dbq=C:\Citect\User\NPM;"
type private schema = SqlDataProvider<Common.DatabaseProviderTypes.ODBC, schemaConn>
let private connStringFormat = Printf.StringFormat<string->string>(@"Driver={Microsoft dBASE Driver (*.dbf)};DriverID=277;Dbq=%s;")
type internal Project = {
name : string
path : string
dcx : schema.dataContext
}
[<Literal>]
let private cUserPath = @"C:\Citect\User"
let private findPath projectName =
Directory.GetDirectories(cUserPath, projectName, SearchOption.AllDirectories)
|> Array.find (fun d -> d.Contains("web") |> not)
let internal connect projectName =
let path' = findPath projectName
let connString = sprintf connStringFormat path'
let dcx' = schema.GetDataContext(connString)
{ name = projectName; path = path'; dcx = dcx' }
let internal updVariable (project : Project) variable =
let dcx = project.dcx
let q = query {
for v in dcx.Dbo.Variable do
where (v.Addr = "%MW217.0")
select v
exactlyOne
}
q.Addr <- "QQQ"
dcx.SubmitUpdates() //error
let internal prj = connect "NPMUG_SCC35"
updVariable prj ()
连接和查询按预期工作,但是当我尝试更新数据源时,我收到来自odbc驱动程序的以下错误:
消息 - &gt;错误[HY092] [Microsoft] [ODBC dBase驱动程序]无效 属性/选项标识符来源 - &gt; ODBCJT32.DLL
有没有办法让它工作或者我是否需要放弃类型提供者并回归OleDb?
更新
禁用事务使事情变得更好,现在错误是由于我必须使用的dbf文件中缺少主键。
唯一改变的代码是获取数据上下文
let dcx = schema.GetDataContext( { Timeout = TimeSpan.MaxValue; IsolationLevel = Transactions.IsolationLevel.DontCreateTransaction } : FSharp.Data.Sql.Transactions.TransactionOptions)
新错误是:
System.Exception:错误 - 您无法更新没有的实体 有一个主键。 (dbo.variable)at FSharp.Data.Sql.Providers.OdbcProvider.createUpdateCommand(的IDbConnection con,StringBuilder sb,SqlEntity实体,FSharpList`1 changedColumns)
at。$ Providers.Odbc.FSharp-Data-Sql-Common-ISqlProvider-ProcessUpdates @ 648-4.Invoke(SqlEntity) 吃 Microsoft.FSharp.Collections.SeqModule.Iterate [T](FSharpFunc
2 action, IEnumerable
1 source)at at FSharp.Data.Sql.Providers.OdbcProvider.FSharp-DATA-SQL的共ISqlProvider-ProcessUpdates(的IDbConnection con,ConcurrentDictionary2 entities, TransactionOptions transactionOptions, FSharpOption
1超时)at 。$ @ SqlRuntime.DataContext.f 1-69(SqlDataContext __,IDbConnection con,Unit unitVar0)at FSharp.Data.Sql.Runtime.SqlDataContext.FSharp-Data-Sql-Common-ISqlDataContext-SubmitPendingChanges()
有关如何处理此探测器的任何想法吗?
答案 0 :(得分:1)
我发现了一种棘手/肮脏的方式,我将其分类为一种解决方法,而不是真正的解决方案,但它适用于我的情况;所以我将使用它,除非/直到其他人建议一个结论性的。
为了让类型提供者工作,我需要做两件事,而不是在通常的工作流程中:
这里是工作代码
[<Literal>]
let private schemaConn = @"Driver={Microsoft dBASE Driver (*.dbf)};DriverID=277;Dbq=C:\Citect\User\NPM;READONLY=FALSE"
type private schema = SqlDataProvider<Common.DatabaseProviderTypes.ODBC, schemaConn>
let private connStringFormat = Printf.StringFormat<string->string>(@"Driver={Microsoft dBASE Driver (*.dbf)};DriverID=277;Dbq=%s;READONLY=FALSE")
type internal Project = {
name : string
path : string
dcx : schema.dataContext
}
[<Literal>]
let private cUserPath = @"C:\Citect\User"
let private findPath projectName =
Directory.GetDirectories(cUserPath, projectName, SearchOption.AllDirectories)
|> Array.find (fun d -> d.Contains("web") |> not)
let private createPK (cn : IDbConnection) =
let cm = cn.CreateCommand()
cm.CommandText <- "ALTER TABLE Variable ADD PRIMARY KEY (Name)"
try
cn.Open()
cm.ExecuteNonQuery() |> ignore
finally cn.Close()
let internal connect projectName =
let path' = findPath projectName
let connString = sprintf connStringFormat path'
let transOptions = { Timeout = TimeSpan.FromSeconds(3.0); IsolationLevel = Transactions.IsolationLevel.DontCreateTransaction }
let dcx' = schema.GetDataContext(connectionString = connString, transactionOptions = transOptions)
dcx'.CreateConnection() |> createPK
{ name = projectName; path = path'; dcx = dcx' }
let internal updVariable (project : Project) variable =
let dcx = project.dcx
let q = query {
for v in dcx.Dbo.Variable do
where (v.Addr = "%MW217.0")
select v
exactlyOne
}
q.Addr <- "QQQ"
dcx.SubmitUpdates()
let internal prj = connect "NPMUG_SCC35"
updVariable prj ()