1

我正在 F# 中构建一个 Web API 来测试一些东西。我来自 C# 背景,我已经组织了我在那里做的事情。

你可以在这里找到回购:https ://github.com/MrGodlike6/WebApiTest

我在 WebApiTest.WebApi 中引用了 WebApiTest.Repositories.SqlServer 项目,但由于某种原因,Visual Studio 说它找不到 WebApiTest.Repositories.SqlServer 命名空间。

问题是解决方案编译得很好,我可以运行应用程序,只是我没有智能感知来自 SqlServer 项目的任何东西(例如,在 CompositionRoot 模块中)。

我已经尝试了很多东西,从不同的数据库到为数据库项目制作一个 .NET Framework 4.7.2 项目。到目前为止,没有任何效果。尝试了 Nuget 和 Paket,没有任何区别。尝试过 VS 2019。在 VS 2022 中,它给出了一些不相关的编译错误。

我使用 JetBrains 的 dotPeek 来查看生成的 .dll,并且命名空间和模块按预期存在。不知道是什么原因造成的。

您还可以指出我使用的项目/文件夹结构是否适用于 F#?也欢迎任何其他建议。

编辑:SQL 部分基于https://github.com/isaacabraham/get-programming-fsharp/tree/master/src/code-listings/lesson-35。这里一切正常,尽管 SQL 代码没有放在单独的项目中。

我已经评论了 SqlEnumProvider 并且我不再在组合根中遇到问题。我会仔细看看这个提供者,看看我能不能想出一些东西。

EDIT2:在 GitHub 上创建了一个问题:https ://github.com/fsprojects/FSharp.Data.SqlClient/issues/410

4

2 回答 2

1

谢谢布赖恩的剧本。

正如文档所说,
“枚举类型(或枚举类型)是由一组基础整数数字类型的命名常量定义的值类型。”
我将OperationId列数据类型更改为 int indbo.Operationdbo.AccountTransaction填充了表 dbo.Operation,因为SqlEnumProvider在编译期间抱怨缺少数据。


CREATE TABLE [dbo].[Operation] (
    [Description] NVARCHAR (100) NULL,
    [OperationId] INT            NOT NULL
);

CREATE TABLE [dbo].[AccountTransaction] (
    [AccountId]   UNIQUEIDENTIFIER NOT NULL,
    [Timestamp]   DATETIME         NOT NULL,
    [OperationId] INT              NOT NULL,
    [Amount]      MONEY            NOT NULL
);

insert dbo.Operation (Description, OperationId) values ('Deposit', 1), ('Withdraw', 2)

现在我可以编译解决方案了。

于 2021-09-17T10:29:14.060 回答
1

我已经复制了你所看到的。该问题似乎是由 FSharp.Data 类型提供程序中的设计时错误引起的。特别是,SqlEnumProvider似乎是来源。当我DbOperations从 AccountRepository.fs 中删除类型时(使用纯字符串而不是枚举值),我能够WebApiTest.Repositories.SqlServer在 CompositionRoot.fs 中获取 Intellisense。

这是我笨拙的解决方法:

[<AutoOpen>]
module private DB =
    let [<Literal>] Conn = @"Data Source=.;Database=BankAccountDb;Integrated Security=True;Connect Timeout=60"
    type AccountsDb = SqlProgrammabilityProvider<Conn>
    type GetAccountId = SqlCommandProvider<"SELECT TOP 1 AccountId FROM dbo.Account WHERE Owner = @owner", Conn, SingleRow = true>
    type FindTransactions = SqlCommandProvider<"SELECT Timestamp, OperationId, Amount FROM dbo.AccountTransaction WHERE AccountId = @accountId", Conn>
    type FindTransactionsByOwner = SqlCommandProvider<"SELECT a.AccountId, at.Timestamp, at.OperationId, at.Amount FROM dbo.Account a LEFT JOIN dbo.AccountTransaction at on a.AccountId = at.AccountId WHERE Owner = @owner", Conn>
    // type DbOperations = SqlEnumProvider<"SELECT Description, OperationId FROM dbo.Operation", Conn>

let toBankOperation operationId =
    match operationId with
        | "Deposit" -> Deposit
        | "Withdraw" -> Withdraw
        | _ -> failwith "Unknown operation!"

let fromBankOperation bankOperation =
    match bankOperation with
        | Deposit -> "Deposit"
        | Withdraw -> "Withdraw"

我在 GitHub 上搜索了一个现有问题,但没有找到,因此您可能想自己打开一个新问题。

如果其他人想尝试这个,这是我用来编译的虚拟数据库模式:

USE [BankAccountDb]
GO
/****** Object:  Table [dbo].[Account]    Script Date: 9/16/2021 11:40:48 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Account](
    [Owner] [nchar](10) NOT NULL,
    [AccountId] [uniqueidentifier] NOT NULL
) ON [PRIMARY]
GO
/****** Object:  Table [dbo].[AccountTransaction]    Script Date: 9/16/2021 11:40:48 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[AccountTransaction](
    [AccountId] [uniqueidentifier] NOT NULL,
    [Timestamp] [datetime] NOT NULL,
    [OperationId] [nchar](10) NOT NULL,
    [Amount] [money] NOT NULL
) ON [PRIMARY]
GO
/****** Object:  Table [dbo].[Operation]    Script Date: 9/16/2021 11:40:48 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Operation](
    [Description] [nvarchar](100) NULL,
    [OperationId] [nvarchar](100) NULL
) ON [PRIMARY]
GO
于 2021-09-17T03:38:47.417 回答