FSharp数据类型提供程序用于PostgreSQL

8
我正在尝试使用FSharp数据提供程序连接Postgresql,但是用npgsql时在第一行就遇到了问题。
当我尝试创建SqlDataConnection时,它会抛出一个错误,消息是连接字符串不正确。
“Microsoft.FSharp.Data.TypeProviders.DesignTime.DataProviders”类型提供程序报告了一个错误:“不支持的关键字:'port:5432;database'”。
现在,我使用Servicestack.Ormlite测试连接字符串和数据。它基本上使用IdbConnection。因此,连接都是正确的。但我不知道为什么类型提供程序不起作用。
以下是代码。
    //type dbSchema = SqlDataConnection<ConnectionString = "Server=localhost;Port=5432; Database=TestDB;User Id=postgres;Password=g00gle*92;" >
[<CLIMutable>]
type Person = 
    { ID : int;
      FirstName : string;
      LastName : string }

[<EntryPoint>]
let main args = 
    let dbFactory = 
        OrmLiteConnectionFactory
            (
             "Server=localhost;Port=5432; Database=TestDB;User Id=postgres;Password=*****;", 
             PostgreSqlDialect.Provider)
    use dbConnection = dbFactory.OpenDbConnection()
    Console.WriteLine dbConnection.State
    let persons = dbConnection.Select<Person>()
    persons.ForEach(fun p -> Console.WriteLine p.FirstName)
    Console.Read() |> ignore
    0

以上代码中,第一条注释行不起作用,而相同设置的下面代码是有效的。这意味着问题仅与类型提供程序有关,而不与连接有关。

我需要做其他任何设置吗?

如果需要其他详细信息,请让我知道。

更新

在kvb的评论后,我尝试了两种方法。以下是带有Web配置的更新代码。

//type dbSchema = SqlEntityConnection<ConnectionStringName = "TestDB", Provider="Npgsql">
    type dbSchema = SqlEntityConnection< ConnectionStringName="TestDB" >

    [<CLIMutable>]
    type Person = 
        { ID : int;
          FirstName : string;
          LastName : string }

    [<EntryPoint>]
    let main args = 
        let dbFactory = 
            OrmLiteConnectionFactory
                (
                 "Server=localhost;Port=5432; Database=TestDB;User Id=postgres;Password=*******;", 
                 PostgreSqlDialect.Provider)
        use dbConnection = dbFactory.OpenDbConnection()
        Console.WriteLine dbConnection.State
        let persons = dbConnection.Select<Person>()
        persons.ForEach(fun p -> Console.WriteLine p.FirstName)
        Console.Read() |> ignore
        0

这里是Web.config

  <system.data>
    <DbProviderFactories>
      <add name="Npgsql Data Provider"
            invariant="Npgsql"
            description="Data Provider for PostgreSQL"
            type="Npgsql.NpgsqlFactory, Npgsql" />
    </DbProviderFactories>
  </system.data>
  <connectionStrings>
    <add name="TestDB"
          connectionString="Server=localhost:5432; Database=TestDB;User Id=postgres;Password=******;"
          providerName="Npgsql" />

  </connectionStrings>

这里是appconfig中的汇编。我认为它不会在GAC中,因为我是通过nuget添加的。

 <dependentAssembly>
    <assemblyIdentity name="Npgsql" publicKeyToken="5d8b90d52f46fda7" culture="neutral" />
    <bindingRedirect oldVersion="0.0.0.0-2.0.12.0" newVersion="2.0.12.0" />
 </dependentAssembly>

上面的两个代码,一个被注释了,而另一个没有被注释,它们都以不同的错误失败了。 第一个出现错误是:

类型提供程序'Microsoft.FSharp.Data.TypeProviders.DesignTime.DataProviders'报告了一个错误:读取模式时出错。错误7001:指定的存储提供程序“Npgsql”在配置中找不到,或者“Npgsql”无效。无法找到请求的.Net Framework数据提供程序。它可能没有被安装。

而第二个则是这个错误:

类型提供程序'Microsoft.FSharp.Data.TypeProviders.DesignTime.DataProviders'报告了一个错误:读取模式时出错。错误7001:该提供程序未返回ProviderManifestToken字符串。与SQL Server建立连接时出现了与网络相关或特定于实例的错误。无法找到服务器或无法访问。请验证实例名称是否正确,并确认SQL Server已配置为允许远程连接。(提供程序:命名管道提供程序,错误:40 - 无法打开到 SQL Server 的连接)找不到网络路径。

我仍然不明白为什么它正在搜索SQL Server。
如果需要更多信息,请告诉我。

3
SqlDataConnection 依赖于 sqlmetal.exe 进行代码生成,据我所知它仅支持 SQL Server。 - kvb
3
你可以尝试使用 SqlEntityConnection,因为实体框架支持多个数据库。我不知道如何进行配置,但你可以参考 https://dev59.com/_XM_5IYBdhLWcg3w02z8 了解有关使用实体框架与 PostgreSQL 的更多信息。 - kvb
1
我认为除了正确设置连接字符串之外,您可能还需要设置 SqlEntityConnection 的可选 Provider 参数。 - kvb
1
SqlEntityConnection<ConnectionStringName="...", Provider="..."> - kvb
@kvb 我已经更新了问题并附上了错误信息。 - kunjee
显示剩余15条评论
2个回答

4

我会提供部分答案,希望有人能够解决下一步的问题。

以下代码将可以编译:

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

对于在数据库testdb中创建的一张名为test_table的表:

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;

要完成这个任务,你需要做四件事情:
  • 将 Npgsql.dll 安装到 GAC ("C:\Program Files (x86)\Microsoft SDKs\Windows\v8.0A\bin\NETFX 4.0 Tools\x64\gacutil.exe" /i [filename])
  • 将 Mono.Security.dll 安装到 GAC(与 Npgsql.dll 下载到的同一目录中)
  • 将 DbProviderFactory 添加到你的 .NET 4 64 位 machine.config 中 ("C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Config\machine.config"):就像在 app.config 中添加到相应部分一样,但是要添加到 machine.config 的适当部分。我的 machine.config 目前只有一个条目,用于 Microsoft SQL Server Compact Data Provider。请记得包括正确的公钥令牌。
<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>
  • 重新启动 Visual Studio。

现在,SqlEntityConnection 在设计时进行编译,您将能够看到所有可用的表。这也可以编译成可执行文件。

这回答了你的问题;但现在是奇怪的部分,这意味着你仍然不会满意。当您运行此代码时,它将在调用dbSchema.GetDataContext()时立即抛出ArgumentException,并显示以下内容:

提供的连接字符串应该是有效的特定于提供程序的连接字符串或被 EntityClient 接受的有效连接字符串。

内部异常说明

不支持 'server' 关键字。

堆栈跟踪为

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()

我尝试过修改连接字符串来使其工作,但我认为这必须是提供程序在运行时与设计时创建连接字符串时出现的错误。由于此代码被发射到动态程序集中,因此不明显如何查看代码以查看发生了什么。


1
我遇到了同样的困难。这可以通过在App.config文件中添加以下内容来解决:
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
  <parameters>
    <parameter value="v11.0" />
  </parameters>
</defaultConnectionFactory>
<providers>
  <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
  <provider invariantName="Npgsql" type="Npgsql.NpgsqlServices, Npgsql.EntityFramework" />
</providers>


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接