Я регулярно получаю ошибку "A command is already in progress". Видимо, это происходит из-за того, что мое приложение все SQL-запросы отправляет в одно и то же подключение (_connection хранит ссылку на NpgsqlConnection, который создается при старте программы):
public async Task<T> QueryAsync<T>(IApiCommand apiCommand)
{
if (!IsConnected)
{
throw new SessionLostException();
}
using var cmd = new NpgsqlCommand(apiCommand.CommandString, _connection);
//
if (apiCommand.HasOutParam)
{
//
}
else if (apiCommand.CommandType == ApiCommandType.Func)
{
NpgsqlDataReader reader;
switch (apiCommand.ResultType)
{
case ApiCommandResultType.Cell:
reader = await cmd.ExecuteReaderAsync(CommandBehavior.SingleResult);
result = reader.GetValue(0);
break;
case ApiCommandResultType.Row:
reader = await cmd.ExecuteReaderAsync(CommandBehavior.SingleRow);
var dt = ReadTable(reader);
result = dt.Rows[0];
break;
case ApiCommandResultType.Table:
reader = await cmd.ExecuteReaderAsync(CommandBehavior.Default);
result = ReadTable(reader);
break;
default:
throw new NotSupportedException();
}
await reader.DisposeAsync();
Соответственно, если у меня второй контрол асинхронно запрашивает данные в то время, как вызов первого не успел дойти до reader.DisposeAsync(), получаю ошибку.
Правильно ли я понимаю, что, поскольку Postgres
не может создавать параллельные транзакции на одно подключение, я должен ожидать завершения предыдущей транзакции прежде, чем создам новую команду со ссылкой на текущее подключение?
К сожалению, класс
NpgsqlConnection не предоставляет API доступа к команде, которая выполняется в данный момент. Поэтому вижу только три варианта:
1) всегда создавать новое подключение под каждый запрос
2) извлекать подключение из пула
3) самостоятельно реализовать очередь запросов
Первый вариант слишком дорог. Второй — в API вроде бы нет методов для работы с пулом. То есть остается третий вариант?