FSharp.Data.TypeProviders SQLDataConnection

8

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

f#
type-providers
f#-interactive
f#-3.0
asked on Stack Overflow Dec 3, 2014 by user1129988 • edited Dec 3, 2014 by user1129988

2 Answers

0

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.

answered on Stack Overflow Jun 11, 2016 by s952163
0

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...

answered on Stack Overflow Jul 19, 2018 by Coderookie

User contributions licensed under CC BY-SA 3.0