Dzoukr / Dapper.FSharp

Lightweight F# extension for StackOverflow Dapper with support for MSSQL, MySQL, PostgreSQL, and SQLite
MIT License
365 stars 35 forks source link

SelectAsync returns a Task which cannot be wrapped in async block #60

Closed DianaLaa closed 2 years ago

DianaLaa commented 2 years ago

This does not work:

namespace API.DAL.Authorization

open API.DAL
open Dapper.FSharp
open Dapper.FSharp.MSSQL
open Microsoft.Data.SqlClient
open System.Data

type public IAuthorizationRepository =
    abstract member ListModules : slug:string -> Async<string list>

type public AuthorizationRepository(connectionString: ConnectionString) =
    interface IAuthorizationRepository with
        member this.ListModules(slug: string) = 
            use connection: IDbConnection = new SqlConnection(connectionString.ConnectionString)
            let moduleTable = table<string>
            async {
                select {
                    for p in moduleTable do
                    selectAll
                } |> connection.SelectAsync<string>
                // ??? Compile error: Type constraint mismatch. The type Async<unit> is not compatible with type Async<string list>
            }

How to use Dapper.FSharp with async?

JordanMarr commented 2 years ago

Use the new task block instead of async (or else convert the task to an async). Also you will need to return!, or await the results with let! and then return them.

You should review this: https://docs.microsoft.com/en-us/dotnet/fsharp/tutorials/async

Also, you should be calling connection.SelectAsync<MyModuleType>, where MyModuleType is the type you created to represent that table.

namespace API.DAL.Authorization

open API.DAL
open Dapper.FSharp
open Dapper.FSharp.MSSQL
open Microsoft.Data.SqlClient
open System.Data

type public IAuthorizationRepository =
    abstract member ListModules : slug:string -> Async<string list>

type public AuthorizationRepository(connectionString: ConnectionString) =
    interface IAuthorizationRepository with
        member this.ListModules(slug: string) = 
            use connection: IDbConnection = new SqlConnection(connectionString.ConnectionString)
            let moduleTable = table<string>
            task {
                let! modules =
                  select {
                      for p in moduleTable do
                      selectAll
                  } |> connection.SelectAsync<MyModuleType>

                return 
                  modules 
                  |> Seq.map (fun m -> m.Name)
            }
DianaLaa commented 2 years ago

I don't think that's configured correctly either... I'm getting TaskCanceledException on connection.SelectAsync. I'm sure I'm doing something wrong..

DianaLaa commented 2 years ago

Ah, found it. The use connection statement should be inside the task.

JordanMarr commented 2 years ago

Good catch!