Home > Enterprise >  Dispose of entity objects created by DbContext
Dispose of entity objects created by DbContext

Time:07-02

We are implementing DAL with EF Core and Postgres Npgsql provider.

Some tables have jsonb columns and we map them to JsonDocument properties in entity objects.

The page JSON Mapping in Npgsql documentation has the following note:

Note also that JsonDocument is disposable, so the entity type is made disposable as well; not dispose the JsonDocument will result in the memory not being returned to the pool, which will increase GC impact across various parts of the framework.

According to the doc, we have made the entities disposable:

public class SomeEntity : IDisposable
{
    public int Id { get; set; }

    public JsonDocument JsonData { get; set; }

    public void Dispose()
    {
        JsonData?.Dispose();
    }
}

The problem is that Dispose method for entity objects is never called while DbContext is disposed correctly. The only way we see is to manually enumerate DbSet when DbContext is disposed and invoke Dispose method for each entity:

public class SomeDbContext : DbContext
{
    public DbSet<SomeEntity> SomeEntities { get; set; }

    private bool DisposedEntities { get; set; }

    public override void Dispose()
    {
        DisposeEntities();

        base.Dispose();
    }

    public override ValueTask DisposeAsync()
    {
        DisposeEntities();

        return base.DisposeAsync();
    }

    private void DisposeEntities()
    {
        if (DisposedEntities)
        {
            return;
        }

        DisposeEntities(SomeEntities);

        DisposedEntities = true;
    }

    private static void DisposeEntities<TEntity>(IEnumerable<TEntity> dbSet)
        where TEntity : IDisposable
    {
        foreach (var entity in dbSet)
        {
            entity.Dispose();
        }
    }
}

Is there a way to force EF Core to dispose entities when DbContext is disposed?

Is above approach with manual entities dispose OK or it has some flaws?

CodePudding user response:

Not OK. Your implementation loads whole table during dispose, because when enumerating DbSet - it loads data from database.

Consider to change function signature and dispose entities from Local collection:

private static void DisposeEntities<T>(DbSet<T> dbSet) 
    where T : class, IDisposable
{
    foreach (var entity in dbSet.Local)
    {
        entity.Dispose();
    }
}
  • Related