我已将我的 DbContext 之一设置为使用拆分查询:
builder.Services.AddDbContextFactory<NoTrackingDbContext>(options =>
options.UseSqlServer(config.GetConnectionString("LouisHoweDb"),
x =>
{
x.UseNetTopologySuite();
x.UseQuerySplittingBehavior(QuerySplittingBehavior.SplitQuery);
})
);
并且不进行跟踪:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
base.OnConfiguring(optionsBuilder);
optionsBuilder.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);
}
查看原始查询和附加实体(无),两者似乎都在工作。这是最好的验证方法吗?或者有没有办法查看 DbContext 属性来验证?
验证拆分查询的最简单方法是使用分析器。让它捕获针对测试数据库运行的 SQL,最好是不会从其他系统获得大量流量的数据库。当您执行查询 /w
AsSplitQuery
时,您应该看到多个单独的 SQL 语句正在运行,而不是一个带有多个 JOIN
的查询。有点类似于延迟加载所发生的情况,但它应该是每个实体/表一个查询。 (与每个顶级行每个表一个查询/w延迟加载相比,这可能是一种昂贵的场景)
为了验证跟踪是否发生,最简单的方法是在查询后添加临时检查。如果您要从 TableA 加载记录并连接到 TableB,则在查询后您可以检查 DbSet.Local 以查看是否有任何跟踪实例:
var results = context.TableAs.Include(a => a.TableBs).Where(a => /* condition */).ToList();
bool hasTrackedInstances = context.TableAs.Local.Any() || context.TableBs.Local.Any();
如果查询在未启用跟踪的情况下运行,则
.Local
跟踪缓存应保持为空。
对于读取量大的场景,禁用跟踪可能没问题,但对于更新场景来说会很痛苦,并且还要考虑在 DbContext 的范围内,我相信插入的项目将始终被视为已跟踪,因此在该 DbContext 范围内插入的任何内容将显示在
.Local
中。跟踪对于有效处理更新场景非常有用,只需将更改应用于跟踪实体并调用 SaveChanges
,然后利用投影 /w Select
进行自动忽略跟踪的读取。 (无需急切加入,引用的行将自动不被跟踪)