C#使用PostgreSQL及其衍生产品GaussDB时(Npgsql.EntityFrameworkCore.PostgreSQL)过程中的几个问题
PostgreSQ作为开源免费的数据库,现在正在火热的占据市场,它衍生产品,比如GaussDB在国产化替代中使用比较多,然而它们或多或少存在一个兼容问题,或者说是版本之间的问题,所以这里记录几个在使用过程中碰到的问题,做个笔记,后续有新的问题就再记录。
问题一:0A000: DISCARD statement is not yet supported.
这个问题是连接池重置导致的一个问题,官网介绍:https://www.npgsql.org/doc/performance.html#pooled-connection-reset
这个时候,我们可以在连接字符串中添加 No Reset On Close=true
配置项,比如:
string connectionString = "Host=localhost;Port=5432;Database=postgres;Password=123456;User ID=postgres;No Reset On Close=true;"
问题二:使用EFCore执行Linq查询时,因为版本问题报错,特别是在使用GaussDB等衍生产品时,比较常见
比如我执行一个Linq的查询时:
var accounts = new string[] { "zhangsan", "lisi" };
var users = await context.Set<SysUser>().Where(f => accounts.Contains(f.Account)).ToArrayAsync();
使用最新的 Npgsql.EntityFrameworkCore.PostgreSQL
得到的SQL语句是这样的:
SELECT s."Id", s."Account", s."Avatar", s."Birthday", s."Email", s."Name", s."NickName", s."Password", s."Phone",
FROM sys_user AS s
WHERE s."Account" = ANY (@__accounts_0) OR (((s."Account" IS NULL)) AND ((array_position(@__accounts_0, NULL) IS NOT NULL)))
然后执行报错:Npgsql.PostgresException (0x80004005): 42883: function array_position(character varying[], unknown) does not exist
很显然他是说找不到指定的函数(你的可能是其它函数),这就是版本的问题
解决方法是在添加服务时,使用 UseRedshift
方法来处理:
string connectionString = "Host=localhost;Port=5432;Database=postgres;Password=123456;User ID=postgres;"
services.AddDbContext<MyDbContext>(options =>
{
options.UseNpgsql(connectionString, options =>
{
options.UseRedshift(true);
});
});
这其实就是告诉EFCore不要使用那些不支持的属性,然后我这边上面的Linq查询就会被翻译成:
SELECT s."Id", s."Account", s."Avatar", s."Birthday", s."Email", s."Name", s."NickName", s."Password", s."Phone",
FROM sys_user AS s
WHERE s."Account" IN ('zhangsan', 'lisi')
问题三:日期问题(有时区和无时区时间)( DateTimeOffset
和DateTime
)
遇到报错:
One or more errors occurred. (Cannot write DateTime with Kind=Local to PostgreSQL type 'timestamp with time zone',
only UTC is supported. Note that it's not possible to mix DateTimes with different Kinds in an array/range.
See the Npgsql.EnableLegacyTimestampBehavior AppContext switch to enable legacy behavior.)
很明显,这个是在说我们时间使用上的问题,我们数据库对应字段是 timestamp with time zone
,它表示的是一个有时区的时间,但是我们类型用的是DateTime
,他表示的是一个无时区的时间,所以我们要使用有时间的时间类型 DateTimeOffset
,但是我们用习惯了DateTime
,如果要改动,代价太大了,怎么办呢,有个兼容的办法,全局添加这两个代码就行了
internal class MyDbContext : DbContext
{
static MyDbContext()
{
AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true);
AppContext.SetSwitch("Npgsql.DisableDateTimeInfinityConversions", true);
}
...
}