FSharp.Data.TypeProviders SQLDataConnection

9

我曾多次使用FSharp.Data.TypeProvider,但这是我遇到的第一次bug。 我能够连接到SQL数据库而不会出现任何问题,并且还可以运行查询,但是当我尝试使用任何Seq.函数(例如|> Seq.toArray)时,我会收到超时错误。

type dbSchema = SqlDataConnection<DBString, Views = false, Functions = false, StoredProcedures = false>
let db = dbSchema.GetDataContext()

这将返回:

type dbSchema =
  class
    static member GetDataContext : unit -> edbSchema.ServiceTypes.SimpleDataContextTypes.dbTableOutput
     + 1 overload
    nested type ServiceTypes
  end

然后我运行了一个简单的查询:

let query1 = 
  let q = query { for a in db.Products do
                  select (a.Date,a.PId, a.Tax)} 
  q |> Seq.map (fun (a,b,c) -> (a,b,c)) 

这将返回:

val query1: seq<DateTime * Nullable<int> * float>

现在,如果我尝试运行一些简单的东西,比如:
query1 |> Seq.head

I get the following error:

System.Data.SqlClient.SqlException (0x80131904): Timeout expired.  The timeout period elapsed prior to completion of the operation or the server is not responding. ---> System.ComponentModel.Win32Exception (0x80004005): The wait operation timed out
   at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
   at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
   at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
   at System.Data.SqlClient.SqlDataReader.TryCloseInternal(Boolean closeReader)
   at System.Data.SqlClient.SqlDataReader.Close()
   at System.Data.Linq.SqlClient.ObjectReaderCompiler.ObjectReaderSession`1.Dispose()
   at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.Dispose()
   at Microsoft.FSharp.Collections.SeqModule.Head[T](IEnumerable`1 source)
   at <StartupCode$FSI_0007>.$FSI_0007.main@()
ClientConnectionId:6b4036ff-6ef4-4224-ad7a-08f8b4808b1b
Stopped due to error

我会非常感激您的帮助。

谢谢

我找到了这个:

当使用查询表达式时,必须记住查询受惰性评估的影响。因此,在任何链接评估期间(例如在每个查询表达式后的lambda表达式块中),数据库仍然处于读取状态。任何明确或隐含使用事务的数据库操作都必须在读取操作完成后进行。

有没有办法执行查询而不受惰性评估的影响?

我认为可以使用完整的数据上下文和executionquery来实现,但这样做会失去大部分类型提供程序的好处。


我认为这是因为seq是惰性的,而且数据库连接没有正确设置所导致的。 - John Palmer
我不负责数据库,如果是这种情况,有什么解决办法吗?谢谢。 - user1129988
尝试:让query1等于 let q = query { for a in db.Products do select (a.Date,a.PId, a.Tax)} q |> Seq.map (fun (a,b,c) -> (a,b,c)) |> Seq.toList。因此,添加Seq.toList强制查询实际运行。 - halcwb
2个回答

0

除了将查询强制转换为列表,您还可以在连接字符串中指定超时时间,例如Connection Timeout = 60。您可以尝试使用数据上下文的其他一些功能,例如:

db.DataContext.ObjectTrackingEnabled <- false  
db.DataContext.CommandTimeout <- 90

然而,在许多情况下,这些类型的超时问题最好在数据库端解决,你提到你无法做到这一点。我的大多数超时问题都是通过添加索引来解决的。因此,您可能需要对查询进行性能分析。


0

我可能错了,但是听起来在获取序列头时连接已经关闭了...

如果你改变你的代码为

let query1 = 
  let q = query { for a in db.Products do
                  select (a.Date,a.PId, a.Tax)} 
  q |> Seq.map (fun (a,b,c) -> (a,b,c)) |> List.ofSeq

会有什么不同吗?也许将序列转换为列表会有所帮助...


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接