如何修复 Giraffe API 通过 SqlDataProvider 从数据库获取的空对象

How to fix empty objects returned by Giraffe API fetched from DB through SqlDataProvider

我正在尝试通过创建一个带有存储库的 F# 应用程序来学习 F#,以便为将来的 Gym 应用程序获取练习。

我使用 SqlServer 存储数据并使用 Fsharp.Data.Sql 获取数据。这个单元测试工作得很好。

我正在尝试使用 Giraffe 通过 Web api 公开数据,问题是我得到了一个长度正确但里面有空对象的列表。

上下文如下:

module Context

open FSharp.Data.Sql

let [<Literal>] dbVendor = Common.DatabaseProviderTypes.MSSQLSERVER
let [<Literal>] connectionString = "Server=DESKTOP-20JMHNK;Database=GymStrongDB;Trusted_Connection=True;"
let [<Literal>] indivAmount = 1000
let [<Literal>] useOptTypes  = true
let [<Literal>] owner = "public, admin, references"

type sql =
    SqlDataProvider<
        dbVendor,
        connectionString,
        "",
        "",
        indivAmount,
        useOptTypes,
        owner>

let gymStrongContext = sql.GetDataContext()

这是存储库

namespace GymStrong.Repositories

open ...

module ExerciseRepository =
    let ctx = gymStrongContext.Dbo

    let getExercises = 
        ctx.Exercises |> Seq.toList

    let getExercisesHandler : HttpHandler =
        fun (next : HttpFunc) (ctx : HttpContext) ->
            Successful.OK getExercises next ctx

这里是Program.fs

的相关部分
open ...

let webApp =
    choose [
        GET >=> 
            choose [
                route "/" >=> text "Hello World"
                route "/user" >=> mustBeLoggedIn >=> getLoggedInUser
                route "/logout" >=> mustBeLoggedIn >=> logoutHandler
                route "/exercises" >=> mustBeLoggedIn >=> getExercisesHandler
                ]
        POST >=> 
            choose [
                route "/register" >=> registerHandler
                route "/login" >=> loginHandler
            ]
    ]

在单元测试中,这可以正常工作。单元测试是用 C# 编写的。

当我通过 PostMan 使用 API 时,我收到此响应

[{},{}]

长度正确,因为我在数据库中有两个练习,但对象似乎是空的。

这可能对某人有用,所以我会 post。

Giraffe 和 SqlDataProvider 都在做他们应该做的事情。问题是我认为我可以将提供的类型作为 json-响应传递给 API。这是错误的,因为提供的类型不是真正的类型,而是 "erased"(而不是我认为我正在使用的类型 Generated)。

为了解决这个问题,我需要将值映射到 "real" 贫乏的 DTO 对象并将其作为响应传递。现在我需要弄清楚是否可以提供这些基于实体类型的贫血 DTO 对象,并让它们从其他程序集中生成和使用。

附加代码:

在repository/service

    type exerciseDto = { 
        Id : string;
        Name : string;
        Description : string;
        Owner : string;
        Type : int; 
    }

    let getExercises = 
        ctx.Exercises |> Seq.map(fun exercise -> exercise.MapTo<exerciseDto>()) |> Seq.toList

并且在program.cs

let handlerWrapper action : HttpHandler =
    fun (next : HttpFunc) (ctxHttp : HttpContext) ->
        Successful.OK action next ctxHttp

let webApp =
    choose [
        GET >=> 
            choose [
                route "/" >=> text "Hello World"
                route "/user" >=> mustBeLoggedIn >=> getLoggedInUser
                route "/logout" >=> mustBeLoggedIn >=> logoutHandler
                route "/exercises" >=> mustBeLoggedIn >=> handlerWrapper getExercises
                ]
        POST >=> 
            choose [
                route "/register" >=> registerHandler
                route "/login" >=> loginHandler
            ]
    ]

希望这可以帮助任何人在未来节省时间。我至少花了几个小时。