几年前有这么多帖子,在具体化查询之前,你需要指定一次.AsNoTracking
;然后有人说它是错误的,你必须在顶部做一次,这将使它对整个查询有效.然而,这些帖子真的很旧,可能与EF6及以上版本无关.
考虑以下复杂的查询场景,涉及多个实体和includes(我删除了部分WHERE子句和投影,只是为了最小化查询的大小):
var dataSet1 = _dbContext.MarketTransactions.AsNoTracking()
.AsSplitQuery()
.Include(a => a.Commodity).ThenInclude(a => a.Product).AsNoTracking()
.Include(a => a.Contract).ThenInclude(a => a.Customer).AsNoTracking()
.Include(a => a.Offer).ThenInclude(a => a.Customer).AsNoTracking()
.Where(f => f.IsActive && (f.Source == EMarketTransactionSource...))
.GroupJoin(
_dbContext.HedgeAccounts.AsNoTracking(),
transaction => transaction.MarketAccount,
hedgeAcct => hedgeAcct.Account,
(transaction, hedgeAcct) => new { Transaction = transaction, HedgeAccounts = hedgeAcct })
.SelectMany(
x => x.HedgeAccounts.DefaultIfEmpty(),
(x, hedgeAcct) => new { x.Transaction, HedgeAccount = hedgeAcct })
.Select(f => new ...);
var dataSet2 = _dbContext.Set<OfferMonitoring>().AsNoTracking()
.AsSplitQuery()
.Include(a => a.Offer).ThenInclude(a => a.Commodity).ThenInclude(a => a.Product).AsNoTracking()
.Include(a => a.Offer).ThenInclude(a => a.Customer).AsNoTracking()
.Where(f => f.Action.Value == EOfferMonitorAction....)
.Select(f => new ...);
var query = dataSet1.Union(dataSet2);
var total = await query.CountAsync(cancellationToken);
query = query.OrderByDescending(x => x.UpdatedOn ?? x.CreationDate);
query = query.GetPagedQuery(request.Filter.Start, request.Filter.Limit);
var items = await query.ToListAsync(cancellationToken);
在这种情况下:
-
.AsNoTracking()
应该在查询开始时全局应用一次(_dbContext.MarketTransactions.AsNoTracking()
和_dbContext.Set<OfferMonitoring>().AsNoTracking()
),还是应该在每个include或join子句之前应用? - 每种方法的性能影响是什么,特别是考虑到结果集的潜在规模?
- Entity Framework Core版本之间在行为或性能上是否存在任何需要考虑的差异?