2

I'm building a Web API in F# to test some things out. I come from a C# background and I've structured things how I do there.

You can find the repo here: https://github.com/MrGodlike6/WebApiTest

I've referenced the WebApiTest.Repositories.SqlServer project in WebApiTest.WebApi but for some reason Visual studio says it can't find the WebApiTest.Repositories.SqlServer namespace.

The thing is that the solution compiles fine and I can run the application, it's just that I don't have IntelliSense for anything coming from the SqlServer project (e.g. in the CompositionRoot module).

I've tried a lot of things, from different DBs, to making a .NET Framework 4.7.2 project for the DB project. So far nothing works. Tried both Nuget & Paket and no difference. Tried VS 2019. In VS 2022 it gives some compile error that is unrelated.

I used dotPeek from JetBrains to look at the resulting .dll and the namespace & module are there as expected. Don't know what could be causing this.

Also can you indicate if the project/folder structure that I use is good for F#? Any other suggestions are also welcome.

EDIT: The SQL part is based of https://github.com/isaacabraham/get-programming-fsharp/tree/master/src/code-listings/lesson-35. Here everything works, although the SQL code is not put in a separate project.

I've commented the SqlEnumProvider and I no longer have problems in the composition root. I'll look a little closer at this provider and see if I can come up with something.

EDIT2: Created a issue on GitHub: https://github.com/fsprojects/FSharp.Data.SqlClient/issues/410

asked Sep 16, 2021 at 18:42
3
  • 1
    Do you have SQL to populate the database? I can't compile your solution because the type providers in the WebApiTest.Repositories.SqlServer don't have anything to work on. Commented Sep 16, 2021 at 19:46
  • Ok, so the type of OperationId in the relevant tables in the repo is integer. Can you check if you have correct types in your setup? Commented Sep 17, 2021 at 21:30
  • I tried both the DB created by the scripts in the book's repo (localdb) and creating a new DB in docker that has the same schema and no luck. And the SqlEnumProvider code is the same as in the book repo. Commented Sep 19, 2021 at 11:20

2 Answers 2

1

I've reproduced what you're seeing. The problem appears to be caused by a design-time error in the FSharp.Data type provider. In particular, SqlEnumProvider seems to be the source. When I remove the DbOperations type from AccountRepository.fs (using plain strings instead of enum values), I'm able to get Intellisense for WebApiTest.Repositories.SqlServer in CompositionRoot.fs.

Here's my kludgy workaround:

[<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"

I searched for an existing issue on GitHub, but didn't find one, so you might want to open a new one yourself.

If anyone else wants to try this, here's the dummy database schema I used to get things to compile:

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
answered Sep 17, 2021 at 3:38
1

Thank you Brian for the script.

As the documentation says,
"An enumeration type (or enum type) is a value type defined by a set of named constants of the underlying integral numeric type."
I changed the OperationId column data type to int in dbo.Operation and dbo.AccountTransaction and populated the table dbo.Operation, because the SqlEnumProvider complained about lack of data during the compilation.


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)

Now I can compile the solution.

answered Sep 17, 2021 at 10:29

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.