How to flatten the nested try-catch block in F# for the following code? I am using EF Core with F#. The nested is required because I need to Rollback the transaction if there are errors in saving or committing the transaction!

let createTenant (ctx: AppContext) (tenant: Db.Tenant) (firstUser: Db.User) =
    async {
            let! db = ctx.Aquire()
            use! transaction = db.Database.BeginTransactionAsync(IsolationLevel.Serializable) |> Async.AwaitTask

            db.Tenant.Add tenant |> ignore
            db.User.Add firstUser |> ignore

            let! result =
                async {
                        let! _ = db.SaveChangesAsync() |> Async.AwaitTask
                        do! transaction.CommitAsync() |> Async.AwaitTask
                        return Ok tenant.Id
                    | _ ->
                        do! transaction.RollbackAsync() |> Async.AwaitTask
                        return Error "internal error"


            return result

        | _ -> return Error "internal error"

On a side note, is this the clean/idiomatic way to handle exceptions in F#? Is there a better way to do this?

  • \$\begingroup\$ The current question title of your question is too generic to be helpful. Please edit to the site standard, which is for the title to simply state the task accomplished by the code. Please see How do I ask a good question?. \$\endgroup\$
    – BCdotWEB
    Sep 27, 2020 at 18:36
  • \$\begingroup\$ You don't need the inner try/catch. If SaveChangesAsync() errors then the transaction will be rolled back anyway and you jump into the outer try/catch. \$\endgroup\$ Sep 29, 2020 at 6:38
  • \$\begingroup\$ @GertArnold I am new to EF Core. Does it automatically rollback the transaction if there are errors in SaveChangesAsync() or CommitAsync() method? \$\endgroup\$ Sep 29, 2020 at 7:34
  • 1
    \$\begingroup\$ Yep. It's all or nothing with these methods. \$\endgroup\$ Sep 29, 2020 at 7:38
  • 1
    \$\begingroup\$ Not related to question, but since you're working mostly with TPL and Task class, it would be better to use Ply or TaskBuilder to avoid usage of Async.AwaitTask which might be slow and gives better interop experience when your library is called from other languages \$\endgroup\$
    – JL0PD
    Mar 12, 2021 at 5:49


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Browse other questions tagged or ask your own question.