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();
}
}