1
votes

I am trying some async ops in f# but w/o much luck. I am trying to grab records from the db and perform operations on each record in Parallel.

let IsA1 companyId = 
    query {   for comp in db.Company do
                join cc in db.CC on (comp.CompanyId = int(cc.CompanyId))
                join pp in db.PP on (cc.PartId = pp.PartId)
                join tl in db.TL on (pp.CompanyId = tl.CompanyId)
                where (comp.CompanyId = companyId)
                select (comp.CompanyId > 0)
          }
          |> Seq.length |> fun len -> len > 0

let IsA2 companyId = 
    query {   for t in db.Title do
                join pp in db.PP on (t.Tid = pp.Tid)
                join comp in db.Company on (pp.CompanyId = comp.CompanyId)
                where (comp.CompanyId = companyId)
                select (comp.CompanyId > 0)
          }
          |> Seq.length |> fun len -> len > 0

let GetAffiliations id = 
    async {
        if (IsA1 id) then return "AffilBBB"
        elif (IsA2 id) then return "AffilCCD"
        else return Unknown
    }

let ProcessCompany (company:dbSchema.ServiceTypes.Company) =
    async {
            let grp = GetAffiliations company.CompanyId
            let result = { Id=company.CompanyId; Name=company.Name; Affiliations=grp; ContactType="ok"; }
            return result
    }

let GetCompanyNames =
    let companies = db.Company |> Seq.distinctBy(fun d -> d.CompanyId)
    companies
    |> Seq.map(fun co -> ProcessCompany co)
    |> Async.Parallel
    |> Async.RunSynchronously

When I run the above code, I get error:

System.ArgumentException: An item with the same key has already been added.

The error is occurring as a result of another function call inside async { }:

let grp = GetAffiliations company.CompanyId

I am sure its a newbie issue, but I am not sure what the issue is. I even tried making the call inside of the async{ } another async call and used let! grp = (GetAffiliations company.CompanyId) but that does not resolve.

1
do I get this right: the error is inside GetAffiliations? If so you have to look/post it - the code you did show looks ok - but of course it's almost impossible to tell because obviously we cannot run it - so just in case can you post the complete exception (with stacktrace please)?Random Dev
I get the error no matter what method I call inside of async (when that method also contacts the db) -- I just gave that as example, I actually call 2 methods in the async { } and either gives same error.schmoopy
Sorry, you are fast - i was updating the question with the other method call..schmoopy
Here is the stacktrace: System.ArgumentException: An item with the same key has already been added. at Microsoft.FSharp.Control.AsyncBuilderImpl.commit[a](Result1 res) at Microsoft.FSharp.Control.CancellationTokenOps.RunSynchronously[a](CancellationToken token, FSharpAsync1 computation, FSharpOption1 timeout) at Microsoft.FSharp.Control.FSharpAsync.RunSynchronously[T](FSharpAsync1 computation, FSharpOption1 timeout, FSharpOption1 cancellationToken) at <StartupCode$FSI_0008>.$FSI_0008.main@() in C:\Script.fsx:line 111schmoopy
I suspect this is because you are using the same 'db' context. Try using 2 different instances of the context for each of the queries.hocho

1 Answers

1
votes

Because the two concurrent queries are sharing the same context, when the second result is added to the same context, you get an error saying that the context already has an item with the same key.

Using distinct instances of the 'db' context for each of the queries, should solve your issue.