I have worked with the FSharp.Data.TypeProvider a number of times but this is the first time I have encountered this bug. I am able to connect to the SQL db without any issues and also run a query but when I try use any Seq. function (such as |> Seq.toArray), I get a timeout expired error.
type dbSchema = SqlDataConnection<DBString, Views = false, Functions = false, StoredProcedures = false>
let db = dbSchema.GetDataContext()
which returns:
type dbSchema =
class
static member GetDataContext : unit -> edbSchema.ServiceTypes.SimpleDataContextTypes.dbTableOutput
+ 1 overload
nested type ServiceTypes
end
then I run a simple query:
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))
which returns:
val query1: seq<DateTime * Nullable<int> * float>
now if I attempt to run something simple such as:
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
I would appreciate any help.
Thanks
I found this:
When you use a query expression, you must remember that the query is subject to lazy evaluation. Therefore, the database is still open for reading during any chained evaluations, such as in the lambda expression blocks after each query expression. Any database operation that explicitly or implicitly uses a transaction must occur after the read operations have completed.
Is there anyway to execute a query and not be subject to lazy evaluation?
I think there may be a way to do it using full data context and executionquery but than you lose most of the benefits of the type provider
Besides forcing the query to a list, you can specify the timeout in the Connection String, for example Connection Timeout = 60
. There are some other things you can try with the datacontext, for example:
db.DataContext.ObjectTrackingEnabled <- false
db.DataContext.CommandTimeout <- 90
However in many cases these type of timeout issues are better solved on the DB side, which you mention you cannot do. Most of my timeout issues were solved by adding indexes. So you might need to performance profile the query.
I might be mistaken, but sounds like the connection is already closed when obtaining the head of the sequence...
If you would change your code to
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
would there be any difference? Maybe transforming the sequence to a List will help...
User contributions licensed under CC BY-SA 3.0