我们最大限度地利用postgresql的功能来简化我们的开发工作。我们在postgresql中大量使用自定义类型(用户定义的类型);我们的大多数函数和存储过程都将它们作为输入参数或返回它们。
我们希望从F#的SqlDataProvider中使用它们。这意味着我们应该以某种方式告诉F#如何将F#用户类型映射到postgresql用户类型。换句话说
我们应该指示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存在但对它所采用的参数视而不见。
答案 0 :(得分:1)
关于你的第一种方法,正如你所理解的那样,NpgsqlTypes包含一些Npgsql开箱即用的类型 - 但这些只是PostgreSQL的内置类型。你不能在不改变Npgsql的源代码的情况下添加新类型,这不是你想要做的事情。
此外,您应该了解用户定义类型(PostgreSQL称之为“复合”)与完全独立类型(如point
)之间的区别。后者是完整类型(类似于int4
),具有自己的自定义二进制表示,而前者不是。
你的第二种方法是正确的--Npgsql完全支持PostgreSQL复合类型。我不知道SqlDataProvider是如何运作的 - 我假设这是一个F#特定类型的提供者 - 但是一旦你通过MapCompositeGlobally正确映射了你的复合,Npgsql允许你通过将NpgsqlParameter的值设置为PgProductType的实例来透明地编写它。可能值得尝试让它首先使用类型提供程序。