处置DbContext创建的实体对象



我们正在使用EF Core和Postgres Npgsql provider实现DAL。

一些表jsonb列,我们将它们映射到JsonDocument实体对象属性。

Npgsql文档中的JSON Mapping页面有如下注释:

还请注意JsonDocument是一次性的,因此创建了实体类型也是一次性的;不处置JsonDocument将导致内存没有返回到池中,这将增加GC影响跨框架的各个部分。

根据文档,我们已经使实体是一次性的:

public class SomeEntity : IDisposable
{
public int Id { get; set; }
public JsonDocument JsonData { get; set; }
public void Dispose()
{
JsonData?.Dispose();
}
}

问题是Dispose方法的实体对象从来没有被调用,而DbContext是正确处置。我们看到的唯一方法是在处理DbContext时手动枚举DbSet,并为每个实体调用Dispose方法:

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

DbContext被处置时,是否有办法强制EF Core处置实体?

以上手工实体处理的方法是可以的还是有缺陷的?

不行。您的实现在dispose期间加载整个表,因为在枚举DbSet -时它从数据库加载数据。

考虑更改函数签名并从Local集合中删除实体:

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

虽然您的方法可以工作,但意图通常不是让DbContext"拥有";它分发的实体实例(因此在它自己被处置时处置它们)。您使用DbContext来获取实例,但此时它们是您的—它们比创建它们的上下文更长寿是完全合理的。

换句话说,在处理实体实例时调用Dispose实际上取决于应用程序代码。

还请注意,如果不调用Dispose,则没有泄漏或其他任何东西,因此不会出现灾难性问题;这意味着GC压力会更高,可能会导致一些性能下降。

最新更新