我不是在这里谈论多个不同的定义上下文。我有一个定义的 DbContext。
当我需要访问数据库时,我有一个
IDbContextFactory<MyDataDbContext>
,用于创建 MyDataDbContext。然后我使用该 DbContext 来访问数据库。
我还知道实例化的DbContext一次只能处理一个查询。它不是线程安全的。所以我并不是在询问在两个任务中使用单个实例化的 DbContext。
这是为了将 DbContext 设置为关闭跟踪。
我的问题是,从那首单曲
IDbContextFactory
中,我可以:
DbContext
对象。dbContext.TableName.ToListAsync()
。await Task.WaitAll(listTasks);
如果我做到了这一切,会赢吗? Azure SQL 数据库会更快吗?或者它只是将所有请求放入队列中并在开始下一个请求之前启动/完成一个请求?从根本上说,所有这些下面都有一个磁盘驱动器,因此磁盘访问必须排队。但在磁盘 I/O 之前/之后有所有处理。还有处理之前/之后的实体框架。
或者如果我走这条路,我只是给自己找麻烦吗?
我的生产系统是普通的 Azure Web 服务器和 Azure SQL 数据库。
使用单独的 DbContext 实例并行化任务很好,只要这些任务可以完全独立运行。但是,您仍然需要考虑诸如数据库锁定之类的细节。如果您有基于代码的处理时间,并行化会有所帮助,但如果大量时间花费在获取/更新数据上,您可能最好首先寻找尽可能高效地完成此操作的方法。与执行 SQL 语句相比,EF 并不是批处理类型操作的最佳选择(如果有这样的选项的话)。首先看看在没有 EF 的情况下如何做到这一点,然后考虑 EF 是否能改进任何东西。
如上述评论中所述,另一个选项是使用 EF Core 7+ 中提供的
ExecuteUpdate()
方法。但请注意,此方法仅针对数据库执行,不会更新可能已加载的跟踪实例。例如:
var record = context.MyTables.Single(x => x.Id == tableId);
// ...
context.MyTables
.Where(x => x.CategoryId == categoryId)
.ExecuteUpdate(x => x.SetProperty(t => t.Value, t.Value + 1);
var records = context.MyTables
.Where(x => x.CategoryId == categoryId)
.ToList();
如果第一个读取的记录属于相关类别,则最后加载的记录仍将具有原始跟踪实例中未更改的值。该实体的数据库行将已更新,但 EF 不会将更改应用于内存中的跟踪实例。如果使用注入的
ExecuteUpdate
实例中的 DbContext
,那么您可能需要警惕任何跟踪的引用。这可能涉及在任何 context.ChangeTracker.Clear()
调用之前调用 ExecuteUpdate()
,或者确保之后的任何读取都使用 AsNoTracking()
来确保当前数据状态来自数据库。