Search code examples
c#entity-framework-coreblazor-server-sidemediatr

Is Using-Statement necessary in a PooledDbContextFactory-Scenario?


I am inside a Blazor Server Application and using MediatR for Query and Commands.

// Register POOLED Factory in Program.cs
services.AddPooledDbContextFactory<MyDbContext>(options =>
{
    options.UseSqlServer(connectionString);
});

Inside the QueryHandlers i am creating a new Context for the whole operation and dispose it by wrapping everything in a using statement:

// MediatR Query with Result and Handler
public class GetSpecificEntities
{
    public record Query(int Parameter1): IRequest<GetSpecificiEntities.Result>;

    public class Result : ResultBase
    {
        public List<MyEntity> MySpecificEntities { get; set; } = new List<MyEntity>();
    }

    public class QueryHandler : IRequestHandler<GetSpecificiEntities.Query, GetSpecificiEntities.Result>
    {
        IDbContextFactory<MyDbContext> _dbContextFactory;

        public QueryHandler(IDbContextFactory<MyDbContext> dbContextFactory)
        {
            _dbContextFactory = dbContextFactory;
        }

        public async Task<Result> Handle(Query request, CancellationToken cancellationToken)
        {
            Result result = new Result();
            // !!!
            using(MyDbContext cx = await _dbContextFactory.CreateDbContextAsync())
            {
                // do different stuff with Database 
                result.MySpecificEntities = cx.MyEntities.Where(e => e.IsActive && e.Property1 == request.Parameter1).ToList();
            }

            return result;
        }
    }
}

Should i get rid of the using?

  • As far i know especially the PooledContextFactory should handle the disposing and reusing of the DbContexts so that new creations are minified.
  • I am afraid that i loose performance-gains when disposing it by myself too.
  • On the other hand i am not sure if there could happen InvalidOperationExceptions when not using "using" (especially in a Blazor Environment).

Solution

  • Yes you should, but can simplify it like this:

            public async Task<Result> Handle(Query request, CancellationToken cancellationToken)
            {
                Result result = new Result();
    
                using MyDbContext cx = await _dbContextFactory.CreateDbContextAsync();
    
                // do different stuff with Database 
                result.MySpecificEntities = cx.MyEntities.Where(e => e.IsActive && e.Property1 == request.Parameter1).ToList();
    
                return result;
            }
    

    It's now implicit in the method: Dispose gets called at the completion of the code block.

    Using only calls Dispose on the object, it doesn't destroy it. What Dispose does is up to the object. In the factory context it just returns it to the factory as stated by @SvyatoslavDanyliv.