@romaro

Как правильно работать с npgsql при частых запросах к Postgres?

Я регулярно получаю ошибку "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 вроде бы нет методов для работы с пулом. То есть остается третий вариант?
  • Вопрос задан
  • 674 просмотра
Пригласить эксперта
Ответы на вопрос 1
vabka
@vabka Куратор тега .NET
Токсичный шарпист
Ты можешь спокойно убивать и пересоздавать Npgsqlconnection на каждый запрос, тк пулинг реализован на уровне Npgsql и он по-умолчанию включен.

Это описано на первой же странице в документации:
https://www.npgsql.org/doc/basic-usage.html#pooling

Но советую уйти от сырого ADO.NET и взять какую-нибудь ORM-ку типа Dapper/linq2db/EF Core
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы