Thread-Safe Query Expressions F#

408 views Asked by At

I have a set of functions which using FSharp.Data.TypeProviders makes several calls to the database via sql to retrieve data.

The code looks like the following:

let query_one (firstName:string) (lastName:string) =
     query { for a in db.Names do
             where (a.firstname = FirstName && a.secondname = LastName)
             select a } |> Seq.last


let query_two (jobTitle:string)  =
     query { for a in db.Jobs do
             where (a.jobId = jobTitle)
             select a } |> Seq.last

let detailsList = new List<('a*'b)>()

let queries = 
   workerDetails 
   |> Array.Parallel.map (fun (firstn, lastn, jobt) -> 
       let j1 = query_one firstn lastn
       let j2 = query_two jobt
       detailsList.add (j1,j2) )

When I run this I get the following:

A first chance exception of type 'System.ArgumentException' occurred in FSharp.Core.dll

Additional information: An item with the same key has already been added.

To be more exact:

System.ArgumentException: An item with the same key has already been added. at Microsoft.FSharp.Linq.RuntimeHelpers.LeafExpressionConverter.EvaluateQuotation(FSharpExpr e) at Microsoft.FSharp.Linq.QueryModule.EvalNonNestedInner(CanEliminate canElim, FSharpExpr queryProducingSequence) at Microsoft.FSharp.Linq.QueryModule.EvalNonNestedOuter(CanEliminate canElim, FSharpExpr tm) at Microsoft.FSharp.Linq.QueryModule.clo@1737-1.Microsoft-FSharp-Linq-ForwardDeclarations-IQueryMethods-Execute[a,b](FSharpExpr`1 ) ... ... at Microsoft.FSharp.Collections.ArrayModule.Parallel.Map@714-3.Invoke(Int32 obj) at System.Threading.Tasks.Parallel.<>c__DisplayClassf`1.b__c() at System.Threading.Tasks.Task.InnerInvoke() at System.Threading.Tasks.Task.InnerInvokeWithArg(Task childTask) at System.Threading.Tasks.Task.<>c__DisplayClass11.b__10(Object param0)<---

I also tried running it from C# using Parallel.For().. I am probably missing something basic. Is there an easy way to make a function thread-safe? or a query expression?

Thanks for the help!

Possible option to resolve: When I included the call for the database context in the function in resolved the parralel exception. Such as:

let query_one (firstName:string) (lastName:string) =
     let db = temp_schema.GetDataContext()
     query { for a in db.Names do
             where (a.firstname = FirstName && a.secondname = LastName)
             select a } |> Seq.last
0

There are 0 answers