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.runDbFun provides two kinds of multiple connection support.
It's possible to run many data access routines simultaneously:
DbCall.Parallel
[ for batch in payments |> List.chunkBySize batchSize do
do! Payments.SavePayments batch
] |> runThe DbCall.Parallel function creates one connection per sequence item (connections are not thread-safe) and runs them in parrallel.
This scenario requires more complex configuration. We have to specify database discriminator:
type Database =
| Main
| ArchiveThen 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