Postgresql 的 FSharp 数据类型提供程序

Posted

技术标签:

【中文标题】Postgresql 的 FSharp 数据类型提供程序【英文标题】:FSharp data type provider for Postgresql 【发布时间】:2013-07-25 02:40:07 【问题描述】:

我尝试使用 FSharp 数据提供程序,但使用 npgsql 对抗 Postgresql。我在第一线就失败了。

当我尝试创建 SqlDataConnection 时,它会抛出错误消息,连接字符串不正确。

类型提供者 'Microsoft.FSharp.Data.TypeProviders.DesignTime.DataProviders' 报错:Keyword not supported: 'port:5432;database'。

现在,我使用 Servicestack.Ormlite 测试连接字符串和数据。这基本上使用 IdbConnection。所以,连接都是正确的。但我不知道为什么 Type Provider 不起作用。

这是代码。

    //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 的评论之后,我都尝试了。这是带有网络配置的更新代码。

//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

这是网络配置

  <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 服务器。服务器未找到或无法访问。核实 实例名称正确且 SQL Server 配置为 允许远程连接。 (提供者:命名管道提供者,错误:40 - 无法打开到 SQL Server 的连接)网络路径不是 找到了

我还是不明白为什么要搜索 SQL server。

如果需要任何进一步的信息,请告诉我。

【问题讨论】:

您拥有Port:5432 似乎很奇怪,但所有其他值都采用key=value 的形式 SqlDataConnection 的代码生成依赖于sqlmetal.exe,据我所知仅支持 SQL Server。 您可以尝试改用SqlEntityConnection,因为实体框架确实支持多个数据库。我不知道如何配置它的细节,但另请参阅***.com/questions/1211475/entity-framework-postgresql 了解有关将 PostgreSQL 与实体框架一起使用的更多信息。 我认为你可能需要设置SqlEntityConnection的可选Provider参数除了正确设置连接字符串。 SqlEntityConnection&lt;ConnectionStringName="...", Provider="..."&gt; 【参考方案1】:

我将发布部分答案,希望有人可以解决下一个问题。

以下代码将编译:

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;

要做到这一点,你需要做四件事:

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(与 NuGet 下载 Npgsql.dll 的目录相同 将 DbProviderFactory 添加到您的 .NET 4 64 位 machine.config ("C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Config\machine.config"):这与您在 app.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 接受的有效连接字符串。

内部异常状态

不支持“服务器”关键字。

使用堆栈跟踪

在 System.Data.EntityClient.EntityConnectionStringBuilder.set_Item(字符串关键字,对象值) 在 System.Data.Common.DbConnectionStringBuilder.set_ConnectionString(字符串值) 在 System.Data.EntityClient.EntityConnectionStringBuilder..ctor(字符串连接字符串) 在 SqlEntityConnection1.dbSchema.GetDataContext()

我已经尝试过调整连接字符串以使其正常工作,但我认为这一定是提供程序在运行时与设计时创建连接字符串的方式的错误。由于此代码被发送到动态程序集中,因此您如何查看代码以了解发生了什么并不明显。

【讨论】:

感谢您的回答,我会检查并通知您。【参考方案2】:

我遇到了同样的困难。这可以通过在 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>

【讨论】:

以上是关于Postgresql 的 FSharp 数据类型提供程序的主要内容,如果未能解决你的问题,请参考以下文章

通过fsharp 使用Enterprise Library Unity 3 - 三种拦截模式的探索

在 PostgreSQL 中使用自定义类型并将它们用作函数中的参数

从 FSharp.Compiler.Service 嵌入 F# 交互式示例引发异常

在部署到IIS应用程序时升级FSharp.Core版本,程序集引用错误

将 app.config 中的连接字符串与 FSharp.Data.SqlClient 一起使用

FSharp 运行我的算法比 Python 慢