NpgsqlOperationInProgressException在查询PostgreSQL数据库时发生。

huangapple go评论154阅读模式
英文:

NpgsqlOperationInProgressException while querying postgres database

问题

每当我尝试运行查询时,都会出现以下异常:Npgsql.NpgsqlOperationInProgressException (0x80004005): A command is already in progress. 我正在使用 DapperPostgreSQL。以下是我的 CarsService 数据访问代码:

public class CarsService : ICarsService
{
    private readonly IDbConnection _connection;

    public CarsService(IDbConnection connection) => _connection = connection;

    public Task<IEnumerable<int>> GetAvailableCarsIdsAsync(int carModelId, DateTime startDate, DateTime endDate)
    {
        return _connection.QueryAsync<int>(@"" select c.id from cars c where c.car_model_id = @CarModelId and c.id not in ( select r.car_id from rentals r where r.car_id = c.id and r.start_date <= @EndDate and r.end_date >= @StartDate ) "", new { CarModelId = carModelId, StartDate = startDate, EndDate = endDate });
    }

    public Task<IEnumerable<int>> GetCarIdsAsync(int carModelId)
    {
        return _connection.QueryAsync<int>(@"" select c.id from cars c where c.car_model_id = @CarModelId "", new { CarModelId = carModelId });
    }
}

这是调用服务的方法:

public async Task<IEnumerable<GetCarModelResponse>> Handle(GetCarModelsQuery query, CancellationToken cancellationToken)
{
    var carModels = await _carModelsService.GetAsync(query);

    return await Task.WhenAll(carModels.Select
    (
        async carModel =>
        {
            var availableCarIds = await _carsService.GetAvailableCarsIdsAsync(carModel.Id, query.StartDate, query.EndDate);
                    
            return new GetCarModelResponse
            (
                carModel.Id,
                carModel.Model,
                carModel.Color,
                availableCarIds.Count(),
                availableCarIds,
                await _carsService.GetCarIdsAsync(carModel.Id)
            );
        }));
}

IDbConnection 被注入为瞬态,将其注入为范围或单例并未解决此问题。 (builder.Services.AddTransient<IDbConnection>(_ => new NpgsqlConnection("连接字符串"));)

如何解决这个问题?

谢谢

英文:

Whenever i try to run query i get this exception: Npgsql.NpgsqlOperationInProgressException (0x80004005): A command is already in progress. I'm using Dapper and PostgreSQL. Here is my code for data access in CarService:

public class CarsService : ICarsService
{
    private readonly IDbConnection _connection;

    public CarsService(IDbConnection connection) =&gt; _connection = connection;

    public Task&lt;IEnumerable&lt;int&gt;&gt; GetAvailableCarsIdsAsync(int carModelId, DateTime startDate, DateTime endDate)
    {
        return _connection.QueryAsync&lt;int&gt;(&quot;&quot;&quot;
            select c.id
            from cars c
            where c.car_model_id = @CarModelId
                and c.id not in (
                    select r.car_id
                    from rentals r
                    where r.car_id = c.id
                        and r.start_date &lt;= @EndDate
                        and r.end_date &gt;= @StartDate
            )
            &quot;&quot;&quot;, new { CarModelId = carModelId, StartDate = startDate, EndDate = endDate });
    }

    public Task&lt;IEnumerable&lt;int&gt;&gt; GetCarIdsAsync(int carModelId)
    {
        return _connection.QueryAsync&lt;int&gt;(&quot;&quot;&quot;
            select c.id
            from cars c
            where c.car_model_id = @CarModelId
            &quot;&quot;&quot;, new { CarModelId = carModelId });
    }
}

Here is the method, that calls service:

public async Task&lt;IEnumerable&lt;GetCarModelResponse&gt;&gt; Handle(GetCarModelsQuery query, CancellationToken cancellationToken)
{
    var carModels = await _carModelsService.GetAsync(query);

    return await Task.WhenAll(carModels.Select
    (
        async carModel =&gt;
        {
            var availableCarIds = await _carsService.GetAvailableCarsIdsAsync(carModel.Id, query.StartDate, query.EndDate);
                    
            return new GetCarModelResponse
            (
                carModel.Id,
                carModel.Model,
                carModel.Color,
                availableCarIds.Count(),
                availableCarIds,
                await _carsService.GetCarIdsAsync(carModel.Id)
            );
        }));
}

IDbConnection is injected as transient, injecting it as scoped or singleton didn't solve the issue. (builder.Services.AddTransient&lt;IDbConnection&gt;(_ =&gt; new NpgsqlConnection(&quot;connection string&quot;));)

How can I fix this?

Thanks

答案1

得分: 1

Here is the translated content you provided:

正如我在评论中写的那样:不要重复使用连接!

一个可工作的CarsService可以如下所示:

public class CarsService : ICarsService
{
    private readonly string connectionString;

    public CarsService(string connectionString) => this.connectionString = connectionString;

    public Task<IEnumerable<int>> GetAvailableCarsIdsAsync(int carModelId, DateTime startDate, DateTime endDate)
    {
        using (var connection = new NpgsqlConnection(connectionString))
        {   
            return connection.QueryAsync<int>(@"
                select c.id
                from cars c
                where c.car_model_id = @CarModelId
                    and c.id not in (
                        select r.car_id
                        from rentals r
                        where r.car_id = c.id
                            and r.start_date <= @EndDate
                            and r.end_date >= @StartDate
                )
                ", new { CarModelId = carModelId, StartDate = startDate, EndDate = endDate });
        }
    }

    public Task<IEnumerable<int>> GetCarIdsAsync(int carModelId)
    {
        using (var connection = new NpgsqlConnection(connectionString))
        {   
            return connection.QueryAsync<int>(@"
                select c.id
                from cars c
                where c.car_model_id = @CarModelId
                ", new { CarModelId = carModelId });
        }
    }
}

这与Postgres紧密耦合,因此您可能希望创建一个用于创建连接的工厂。然后,您可以选择注入该工厂,使其独立于数据库实现,并在那里处理连接字符串。

连接会放回连接池,并且创建连接的开销非常小,因此请始终在查询代码周围创建和处理连接。

英文:

As I wrote in the comment: Don't reuse connections!

A working CarsService could look like this:

public class CarsService : ICarsService
{
    private readonly string connectionString;

    public CarsService(string connectionString) =&gt; this.connectionString = connectionString;

    public Task&lt;IEnumerable&lt;int&gt;&gt; GetAvailableCarsIdsAsync(int carModelId, DateTime startDate, DateTime endDate)
    {
        using (var connection = new NpgsqlConnection(connectionString))
        {   
            return connection.QueryAsync&lt;int&gt;(&quot;&quot;&quot;
                select c.id
                from cars c
                where c.car_model_id = @CarModelId
                    and c.id not in (
                        select r.car_id
                        from rentals r
                        where r.car_id = c.id
                            and r.start_date &lt;= @EndDate
                            and r.end_date &gt;= @StartDate
                )
                &quot;&quot;&quot;, new { CarModelId = carModelId, StartDate = startDate, EndDate = endDate });
        }
    }

    public Task&lt;IEnumerable&lt;int&gt;&gt; GetCarIdsAsync(int carModelId)
    {
        using (var connection = new NpgsqlConnection(connectionString))
        {   
            return _connection.QueryAsync&lt;int&gt;(&quot;&quot;&quot;
                select c.id
                from cars c
                where c.car_model_id = @CarModelId
                &quot;&quot;&quot;, new { CarModelId = carModelId });
        }
    }
}

This is tightly coupled to Postgres, so you might want to make a factory for creating the connection. You can then choose to inject the factory and have it independent of the database implementation and have the conenction string handled there.

Connections are put back in the connection pool and there is very little overhead in creating a connection, so always create and dispose it around your query code.

huangapple
  • 本文由 发表于 2023年4月16日 23:57:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/76028811.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定