Dapper postgres sqlでエラー「42601: syntax error at or near “$1″」が発生した場合の対処法

Dapper postgres sqlでエラー「42601: syntax error at or near “$1″」が発生した場合の対処法

Dapper利用時に、where in実行時にpostgres sqlでエラー「42601: syntax error at or near “$1″」が発生した場合の対処法を記述してます。

環境

  • OS windows10 pro 64bit
  • VSCODE 1.56.2
  • postgres sql 13.3
  • Dapper 2.0.90
  • .NET Core 3.1.409

エラー全文

以下のコードを実行時に発生しました。

connection.Query<model>("SELECT * FROM table WHERE id in @ids",new { ids = new[] { 1, 2 } });

エラー全文

例外が発生しました: CLR/Npgsql.PostgresException
型 'Npgsql.PostgresException' の例外が System.Private.CoreLib.dll で発生しましたが、ユーザー コード内ではハンドルされませんでした: '42601: syntax error at or near "$1"'
   場所 Npgsql.NpgsqlConnector.<<ReadMessage>g__ReadMessageLong|194_0>d.MoveNext()
   場所 System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   場所 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   場所 Npgsql.NpgsqlDataReader.<NextResult>d__44.MoveNext()
   場所 System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   場所 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   場所 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   場所 System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   場所 Npgsql.NpgsqlDataReader.NextResult()
   場所 Npgsql.NpgsqlCommand.<ExecuteReader>d__105.MoveNext()
   場所 System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   場所 Npgsql.NpgsqlCommand.<ExecuteReader>d__105.MoveNext()
   場所 System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   場所 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   場所 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   場所 System.Threading.Tasks.ValueTask`1.get_Result()
   場所 System.Runtime.CompilerServices.ValueTaskAwaiter`1.GetResult()
   場所 Npgsql.NpgsqlCommand.ExecuteReader(CommandBehavior behavior)
   場所 Npgsql.NpgsqlCommand.ExecuteDbDataReader(CommandBehavior behavior)
   場所 System.Data.Common.DbCommand.System.Data.IDbCommand.ExecuteReader(CommandBehavior behavior)
   場所 Dapper.SqlMapper.ExecuteReaderWithFlagsFallback(IDbCommand cmd, Boolean wasClosed, CommandBehavior behavior) (/_/Dapper/SqlMapper.cs):行 1055
   場所 Dapper.SqlMapper.<QueryImpl>d__140`1.MoveNext() (/_/Dapper/SqlMapper.cs):行 1083
   場所 System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
   場所 System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
   場所 Dapper.SqlMapper.Query[T](IDbConnection cnn, String sql, Object param, IDbTransaction transaction, Boolean buffered, Nullable`1 commandTimeout, Nullable`1 commandType) (/_/Dapper/SqlMapper.cs):行 725
   場所 Book.Services.BookService.GetIdBooks() (C:\test\SampleService.cs):行 31
   場所 Book.Controllers.BookController.Get() (C:\test\SampleController.cs):行 65
   場所 Microsoft.Extensions.Internal.ObjectMethodExecutor.Execute(Object target, Object[] parameters)
   場所 Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.SyncObjectResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
   場所 Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeActionMethodAsync()
   場所 Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   場所 Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeNextActionFilterAsync()

対処法

where inではなく、anyを使用する

connection.Query<model>("SELECT * FROM table WHERE id = ANY (@ids)",new { ids = new[] { 1, 2 } });

下記のように利用することも可能です。

connection.Query<BookItem>("SELECT * FROM book WHERE id in (@ids1,@ids2)", new { ids1 = 1, ids2 = 2 });