I'm going to post a partial answer in the hope that someone can work out how to do the next bit.
The following code will compile:
open Microsoft.FSharp.Data.TypeProviders
open System.Data.Entity // this is important -- you cannot see any tables without it
type internal dbSchema =
SqlEntityConnection<
ConnectionString="Server=localhost;Database=testdb;User Id=postgres;Password=password;",
Provider="Npgsql">
[<EntryPoint>]
let main argv =
let context = dbSchema.GetDataContext()
query { for item in context.test_table do
select item }
|> Seq.iter (fun item -> printfn "%A" item)
0
For a table test_table
in database testdb
created via
CREATE TABLE test_table
(
id integer NOT NULL,
value text,
CONSTRAINT "PK_test_x_Id" PRIMARY KEY (id)
)
WITH (
OIDS=FALSE
);
ALTER TABLE test_table
OWNER TO postgres;
To do this you need to do four things:
- GAC Npgsql.dll (
"C:\Program Files (x86)\Microsoft SDKs\Windows\v8.0A\bin\NETFX 4.0 Tools\x64\gacutil.exe" /i [filename]
) - GAC Mono.Security.dll (in the same directory that Npgsql.dll was downloaded to by NuGet
- Add the DbProviderFactory to your .NET 4 64-bit machine.config (
"C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Config\machine.config"
): that is the same thing you have in your app.config, but added to the appropriate section in machine.config, mine has one entry at the moment forMicrosoft SQL Server Compact Data Provider
. Remember to include the correct public key token.
<system.data> <DbProviderFactories> <add name="Npgsql Data Provider" invariant="Npgsql" description="Data Provider for PostgreSQL" type="Npgsql.NpgsqlFactory, Npgsql, Version=2.0.12.0, Culture=neutral, PublicKeyToken=5d8b90d52f46fda7" /> </DbProviderFactories> </system.data>
- Restart visual studio.
Now the SqlEntityConnection
compile at design time and you will be able to see all of the tables that are available. This will also happily compile into an executable.
That answers your question; but now for the weird bit which will mean you are still not happy. When you run this code it will throw an ArgumentException
as soon as dbSchema.GetDataContext()
is called saying:
The supplied connection string should be either a valid provider-specific connection string or a valid connection string accepted by the EntityClient.
The inner exception states
The 'server' keyword is not supported.
with stack-trace
at System.Data.EntityClient.EntityConnectionStringBuilder.set_Item(String keyword, Object value) at System.Data.Common.DbConnectionStringBuilder.set_ConnectionString(String value) at System.Data.EntityClient.EntityConnectionStringBuilder..ctor(String connectionString) at SqlEntityConnection1.dbSchema.GetDataContext()
I've tried frigging the connection string to get it to work, but I think that this must be a bug in how the provider is creating the connection string at run-time vs design-time. Since this code is emitted into a dynamic assembly it isn't obvious how you could look at the code to see what is going on.