切片 Entity Framework 的事务以减少内存使用

Slicing Entity Framework's transaction in order to reduce memory usage

所以我的问题是我必须 运行 32 位 ASP .NET 应用程序 运行ning。但是我必须处理一堆记录,这会在数据库中产生巨大的变化。万一出现问题,我必须将整个过程放入 一笔交易。 我想如果我在每个 f.e 之后使用 DBContext.SaveChanges()。 10000 条已处理的记录并删除引用等,因此 GC 可以完成它的工作可以解决我的问题,但事实并非如此。 问题是每个使用数据库的进程(我的意思是 CRUD 操作)都在显着变慢(甚至慢 10 倍左右)。

所以我的代码是这样的,为了更好的理解:

public void StartProcess()
{
    localScopeCtx = cont.Resolve<IApplicationDbContext>();
    IDbContextTransaction trans = localScopeCtx.BeginTransaction();

    int take = 10000;
    int index = 1;
    while (index <= needToProcess)
    {
        var records = GetRecords(take)
        List<obj> recordsToDelete;
        ProcessRecords(take, out recordsToDelete);

        localScopeCtx.Records.RemoveRange(recordsToDelete);

        localScopeCtx.SaveChanges();

        DetachAllEntities(localScopeCtx);
    }

    trans.Commit();
}

public void DetachAllEntities(IApplicationDbContext dbContext)
{
    var changedEntriesCopy = dbContext.ChangeTracker.Entries()
        .Where(e => e.State == EntityState.Added ||
                    e.State == EntityState.Modified ||
                    e.State == EntityState.Deleted ||
                    e.State == EntityState.Unchanged)
        .ToList();

    foreach (var entry in changedEntriesCopy)
        entry.State = EntityState.Detached;
}

在第一个循环中一切都很好。它速度很快,而且它的工作就像魅力一样。但是在 localScopeCtx.SaveChanges() 之后一切都变慢了,就像我说的那样。我认为这是因为 EF 并没有真正将修改发送到数据库,而是将其存储在内存中(根据内存使用情况),但以一种更聪明的方式,它永远不会 运行 离开它(也​​许虚拟内存使用率左右)。

有什么解决方案的建议吗?

编辑: 在进程中添加DetachAllEntities方法;

好的,所以我找到了解决方案,如果有人在这里寻找类似的东西,那就是:

我已经认识到,如果不创建新的 DbContext,它永远不会 "let go" 之前加载的任何对象。因此解决方案是更改事务创建和 DbContext 创建的顺序并创建一个新的每个 "slice".

后的上下文

我的代码看起来像这样:

public void StartProcess()
{
    /*This part isn't exacly the same in my program but the point is the same: create a SqlConnection*/
    string providerName = "System.Data.SqlClient";
    string serverName = ".";
    string databaseName = "SchoolDB";

    // Initialize the connection string builder for the SQL Server provider.
    SqlConnectionStringBuilder sqlBuilder =
        new SqlConnectionStringBuilder();

    // Set the properties for the data source.
    sqlBuilder.DataSource = serverName;
    sqlBuilder.InitialCatalog = databaseName;
    sqlBuilder.IntegratedSecurity = true;

    using (SqlConnection con = new SqlConnection(sqlBuilder.ToString()))
    {
    /*From this point my tested code has exactly the same construction*/
        con.Open();
        using (SqlTransaction transaction = con.BeginTransaction())
        {
            int take = 10000;
            int index = 1;
            while (index <= needToProcess)
            {
                localScopeCtx =  new ApplicationDbContext(trans, false);

                var records = GetRecords(take)
                List<obj> recordsToDelete;
                ProcessRecords(take, out recordsToDelete);

                localScopeCtx.Records.RemoveRange(recordsToDelete);

                localScopeCtx.SaveChanges();
                localScopeCtx.Dispose()
            }
            trans.Commit();
        }
    }
}