用户定义的postgresql类型使用F#中的Npgsql

时间:2017-06-08 22:32:13

标签: postgresql f# npgsql f#-data custom-type

我们最大限度地利用postgresql的功能来简化我们的开发工作。我们在postgresql中大量使用自定义类型(用户定义的类型);我们的大多数函数和存储过程都将它们作为输入参数或返回它们。

我们希望从F#的SqlDataProvider中使用它们。这意味着我们应该以某种方式告诉F#如何将F#用户类型映射到postgresql用户类型。换句话说

  1. Postgresql具有我们定义的用户类型post_user_defined
  2. F#具有我们定义的用户类型fsharp_user_defined
  3. 我们应该指示Npgsql以某种方式执行此映射。到目前为止,我的研究指出了两种方法,其中没有一种方法对我来说完全清楚。任何帮助表示赞赏

    方法1

    NpgsqlTypes命名空间具有映射到.NET开箱即用的预定义的postgresql类型集。其中很少是课程,其他是结构。说我想使用postgresql的内置类型点,由Npgsql通过NpgsqlPoint映射到.NET。我可以将此映射到特定于应用程序的数据结构,如下所示:

    let point (x,y) = NpgsqlTypes.NpgsqlPoint(x,y)
    

    (来自PostgreSQLTests.fsx)

    在这种情况下,已经定义了postgresql point和NpgsqlPoint(.NET)。现在我想为我的自定义类型做同样的事情。

    假设用户定义的postgresql复合是

    create type product_t as ( name text, product_type text);
    

    应用程序数据结构(F#)是记录

    type product_f = {name :string; ptype :string }
    

    或元组

    type product_f = string * string
    

    当作为参数传递给postgresql函数/过程时,如何告诉Npgsql使用我的类型?看起来我需要使用没有公共构造函数的NpgsqTypes.NpgsqlDbType.Composite或Npgsql.PostgresCompositeType。

    我在这里死路一条!

    方法2

    this post获取提示,我可以创建一个自定义类型并使用MapCompositeGlobally注册并使用它传递给postgresql函数。所以,在这里我试试看它

    在Postgresql方面,类型和功能分别为

    CREATE TYPE product_t AS
       (name text,
        product_type text)
    

    func_product(p product_t)  RETURNS void AS
    

    从我在F#中的应用程序

    type PgProductType(Name:string,ProductType:string)=
      member this.Name = Name 
      member this.ProductType = ProductType
      new() = PgProductType("","")
    Npgsql.NpgsqlConnection.MapCompositeGlobally<PgProductType>("product_t",null)
    

    然后

    类型Provider = SqlDataProvider

    让ctx = Provider.GetDataContext() let prd = new PgProductType(“F#Product”,“”)  ctx.Functions.FuncProduct.Invoke(PRD);;

      ctx.Functions.FuncIproduct.Invoke(prd);;
      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    
    stdin(29,1): error FS0501: The member or object constructor 'Invoke' takes 0 argument(s) but is here given 1. The requir
    ed signature is 'SqlDataProvider<...>.dataContext.Functions.FuncIproduct.Result.Invoke() : Unit'.
    

    奇怪的是,错误报告:构造函数'Invoke'接受0参数但在此处给出1 。事物的F#方面对postgresql函数所采用的论点完全不了解。它确实认识到函数FuncIproduct存在但对它所采用的参数视而不见。

1 个答案:

答案 0 :(得分:1)

关于你的第一种方法,正如你所理解的那样,NpgsqlTypes包含一些Npgsql开箱即用的类型 - 但这些只是PostgreSQL的内置类型。你不能在不改变Npgsql的源代码的情况下添加新类型,这不是你想要做的事情。

此外,您应该了解用户定义类型(PostgreSQL称之为“复合”)与完全独立类型(如point)之间的区别。后者是完整类型(类似于int4),具有自己的自定义二进制表示,而前者不是。

你的第二种方法是正确的--Npgsql完全支持PostgreSQL复合类型。我不知道SqlDataProvider是如何运作的 - 我假设这是一个F#特定类型的提供者 - 但是一旦你通过MapCompositeGlobally正确映射了你的复合,Npgsql允许你通过将NpgsqlParameter的值设置为PgProductType的实例来透明地编写它。可能值得尝试让它首先使用类型提供程序。