繁体   English   中英

Npgsql EF 6:使用 ExecuteSqlInterpolatedAsync 时时间戳失败

[英]Npgsql EF 6: Timestamp fails when using ExecuteSqlInterpolatedAsync

更新到 6.0.3 后,我在 ExecuteSqlInterpolatedAsync 中遇到错误。 好吧,我知道这是一个重大变化,但我查看了数据库中的所有表,所有列都是“没有时区的时间戳”。 通过模型/DbSet 进行更新或插入是可以的。

考虑到这一点,看看这段代码:

        await Database.ExecuteSqlInterpolatedAsync($@"update nfservico set 
                chavenfse = {chave},
                lotenfse = {cLote},
                lotenfse_dh = {dhRecbto},
                lotenfse_sit = {sit},
                lotenfse_mot = {mot}
                where id = {id}");

dhRecbto 它是一个没有指定“种类”的 DateTime 参数。 运行给出以下错误:

System.InvalidCastException: Cannot write DateTime with Kind=Unspecified 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.
   at Npgsql.Internal.TypeHandlers.DateTimeHandlers.TimestampTzHandler.ValidateAndGetLength(DateTime value, NpgsqlParameter parameter)
   at Npgsql.Internal.TypeHandlers.DateTimeHandlers.TimestampTzHandler.ValidateObjectAndGetLength(Object value, NpgsqlLengthCache& lengthCache, NpgsqlParameter parameter)
   at Npgsql.NpgsqlParameter.ValidateAndGetLength()
   at Npgsql.NpgsqlParameterCollection.ValidateAndBind(ConnectorTypeMapper typeMapper)
   at Npgsql.NpgsqlCommand.ExecuteReader(CommandBehavior behavior, Boolean async, CancellationToken cancellationToken)
   at Npgsql.NpgsqlCommand.ExecuteReader(CommandBehavior behavior, Boolean async, CancellationToken can...

我无法理解“带时区的时间戳”部分,就像我之前说的,该字段没有时区。

我不得不做一个丑陋的工作:

            var sql = new StringBuilder();
            sql.AppendLine("update nfservico set ");
            sql.AppendLine($"    chavenfse = '{chave}',");
            sql.AppendLine($"    lotenfse = '{cLote}',");
            sql.AppendLine($"    lotenfse_dh = '{dhRecbto:yyyy-MM-dd HH:mm:ss}',");
            sql.AppendLine($"    lotenfse_sit = {sit},");
            sql.AppendLine($"    lotenfse_mot = '{mot}'");
            sql.AppendLine($"    where id = {id}");
            await Database.ExecuteSqlRawAsync(sql.ToString());

有同样问题的人吗? 不,我不想使用“EnableLegacyTimestampBehavior”开关,想要正确地使用它(至少就像在 Npgsql 6 的发行说明中找到的那样)。

这是 EF Core 原始 SQL 支持的限制。 EF 类型映射——它管理发送的参数的 PG 类型(timestamp 与 timestamptz)——仅由参数的 CLR 类型 (DateTime) 确定,而不查看其内容(即 Kind)。 而DateTime默认的EF映射是timestamptz,不是timestamp; 因此错误。 请注意,这与您的实际数据库列类型无关:这纯粹是客户端问题。

幸运的是,EF 的原始 SQL API 允许直接传入 DbParameter,允许您准确指定所需的 PostgreSQL 类型:

var p = new NpgsqlParameter { Value = new DateTime(2020, 1, 1, 12, 0, 0), NpgsqlDbType = NpgsqlDbType.Timestamp };
_ = ctx.Database.ExecuteSqlInterpolatedAsync($"SELECT {p}");

这是传递参数的安全、正确的方法,其中 CLR 类型 (DateTime) 具有默认的 PG 类型 (timestamptz),这不是您想要的(您需要时间戳)。 您上面的解决方法可能在某些方面是错误的,并且可能会引入不需要的时区转换。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM