.net core 5 在函数中使用 EF LINQ (NPGSQL) Timestamp 参数导致 Npgsql.PostgresException (0x80004005)

.net core 5 with EF LINQ (NPGSQL) Timestamp parameter in a function causing an Npgsql.PostgresException (0x80004005)

尝试调用带有时间戳参数的函数(尝试使用时区和不使用时区),但出现此错误。

Npgsql.PostgresException (0x80004005): 22007: invalid input syntax for type timestamp: "@p1"
   at Npgsql.NpgsqlConnector.<ReadMessage>g__ReadMessageLong|194_0(NpgsqlConnector connector, Boolean async, DataRowLoadingMode dataRowLoadingMode, Boolean readingNotifications, Boolean isReadingPrependedMessage)
   at Npgsql.NpgsqlDataReader.NextResult(Boolean async, Boolean isConsuming, CancellationToken cancellationToken)
   at Npgsql.NpgsqlCommand.ExecuteReader(CommandBehavior behavior, Boolean async, CancellationToken cancellationToken)
   at Npgsql.NpgsqlCommand.ExecuteReader(CommandBehavior behavior, Boolean async, CancellationToken cancellationToken)
   at Npgsql.NpgsqlCommand.ExecuteDbDataReaderAsync(CommandBehavior behavior, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Query.Internal.FromSqlQueryingEnumerable`1.AsyncEnumerator.InitializeReaderAsync(DbContext _, Boolean result, CancellationToken cancellationToken)
   at Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal.NpgsqlExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func`4 operation, Func`4 verifySucceeded, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Query.Internal.FromSqlQueryingEnumerable`1.AsyncEnumerator.MoveNextAsync()
   at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListAsync[TSource](IQueryable`1 source, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListAsync[TSource](IQueryable`1 source, CancellationToken cancellationToken)
   at Rainman.Data.Repositories.RoutePlanRepository.GetCustomerRoutingCacheAsync(Int64 id) in C:\Users\sam_w\source\repos\rainman_api\lib\rainmanLibrary\Rainman.Data\Repositories\RoutePlanRepository.cs:line 893
   at Rainman.Services.RoutePlanService.GetCustomerRoutingCaches(Int64 id) in C:\Users\sam_w\source\repos\rainman_api\lib\rainmanLibrary\Rainman.Services\RoutePlanService.cs:line 184
   at Rainman.Api.Controllers.RoutePlanController.GetCustomerRoutingCache(Int64 id) in C:\Users\sam_w\source\repos\rainman_api\Rainman.Api\Controllers\RoutePlanController.cs:line 137
   at lambda_method5(Closure , Object )
   at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.AwaitableObjectResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeInnerFilterAsync>g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
   at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
   at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
   at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)
   at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
  Exception data:
    Severity: ERROR
    SqlState: 22007
    MessageText: invalid input syntax for type timestamp: "@p1"
    Position: 51
    File: datetime.c
    Line: 3761
    Routine: DateTimeParseError

这是错误的代码:

        FormattableString query = $"SELECT public.fn_test_lcr_custom('{routePlan.DeckApplyCustomer.tg_id}', timestamp '{routePlan.effective_date.ToString("u")}');";
        Console.WriteLine($"\n\nQUERY:\n{query}\n\n");
        List<CustomerRoutingCache> tmpList = await RainmanDbContext.CustomerRoutingCaches.FromSqlInterpolated(query).ToListAsync();

我尝试了几种不同的字符串格式,但都无法正常工作。我什至有一个使用相同格式获取时间戳的示例。

            string query = $"SELECT fnlcr_custom('{tg.tg_id}', timestamp '{asOfTS.ToString("u")}');";
            return await RainmanDbContext.Database.ExecuteSqlRawAsync(query);

任何帮助将不胜感激!!!

顺便说一句,使用

.net 核心 5

Microsoft.EntityFrameworkCore v5.0.8

NPgSQL v5.0.7

一般来说,您应该从查询文本中删除单引号和 timestamp,并使用 FromSqlInterpolated。它将为内插字符串中的每个标记绑定一个具有适当类型的参数(映射可以在 Npgsql 文档的 .NET types and PostgreSQL types 部分中看到),例如

var query = db.Set<CustomerRoutingCache>().FromSqlInterpolated(
    $"select * from public.fn_test_lcr_custom({routePlan.DeckApplyCustomer.tg_id}, {routePlan.effective_date})"
);

Console.WriteLine(query.ToQueryString());

var result = await query.ToListAsync();