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