Working with multiple connections - jacentino/DbFun GitHub Wiki

Working with connections is quite comfortable, since their creation and disposal is encapsulated in the DbCall.Run method. But it has some downsides. Since we don't open and close them explicitly, we haven't control over it. We can encounter usage scenarions not covered by this mechanism. E.g. when copying data from one database to another, we are forced to open and close at least one of them many times:

dbsession {
    let! archivedPostIds = Blogging.getArchivedPostIds()
    for ids in archivedPostIds |> List.chunkBySize batchSize do
        let! batch = Blogging.getPostsToBeArchived(ids) 
        Archiving.saveBatch(batch) |> Archiving.run |> Async.start
        do! Blogging.removeArchivedPosts(ids)
} |> Main.run

DbFun provides two kinds of multiple connection support.

Parallel computations

It's possible to run many data access routines simultaneously:

DbCall.Parallel 
    [ for batch in payments |> List.chunkBySize batchSize do
          do! Payments.SavePayments batch
    ] |> run

The DbCall.Parallel function creates one connection per sequence item (connections are not thread-safe) and runs them in parrallel.

Multiple databases

This scenario requires more complex configuration. We have to specify database discriminator:

type Database = 
    | Main
    | Archive

Then we define connection creation function differently:

let createConnection = function 
    | Main    -> new SqlConnection(<main-db-connection-string>)
    | Archive -> new SqlConnection(<archive-db-connection-string>)

The run function doesn't change. It just uses new variant of createConnection:

let run dbCall = DbCall.Run(createConnection, dbCall)

We also use another variant of QueryBuilder allowing to utilize discriminator.

Modules accessing different databases use different values of the discriminator:

module Blogging =
    let query = QueryBuilder<Database>(Main, createConnection)

    let getArchivedPostIds = query.Sql<unit, List<int>>(...)
    let getPostsToBeArchived = query.Sql<List<int>, List<Post>>(...)
    let removeArchivedPosts = query.Sql<List<int>, unit>(...)
module Archiving =
    let query = QueryBuilder<Database>(Archive, createConnection)

    let saveBatch = query.Sql<List<Post>, unit>(...)

The run function provides proper connections for subsequent data access functions:

dbsession {
    let! archivedPostIds = Blogging.getArchivedPostIds()
    for ids in archivedPostIds |> List.chunkBySize batchSize do
        let! batch = Blogging.getPostsToBeArchived(ids) 
        do! Archiving.saveBatch(batch) 
        do! Blogging.removeArchivedPosts(ids)
} |> run
⚠️ **GitHub.com Fallback** ⚠️