EF Core 以升级后可以翻译的形式重写查询

EF Core rewrite the query in a form that can be translated after upgrading

这个查询在我们升级之前工作正常:

var appUsers = await _masterDbContext
                      .Users
                      .Include(x => x.UserCustomers)
                      .AsNoTracking()
                      .Select(AppUserDto.Projection)
                      .Where(user => !user.IsDeleted && user.UserCustomers.Any(x => x.CustomerId == tenant.Id && x.UserId == user.Id))
                      .DistinctBy(x => x.Id)
                      .ToDataSourceResultAsync(request.GridOptions, cancellationToken: cancellationToken);

我们现在收到错误:

Either rewrite the query in a form that can be translated, 
or switch to client evaluation explicitly by inserting a call to 'AsEnumerable', 
'AsAsyncEnumerable', 'ToList', or 'ToListAsync'. 

看来 DistinctBy 是罪魁祸首,但对 LINQ 来说还很陌生,我不知道如何重写它才能正常工作。

看起来您已经从 EF Core 2.x 升级,它将完整的过滤集加载到内存中。 DistinctBy EF Core 6 无法翻译。

尝试以下解决方案:

var filtered = _masterDbContext.Users
    .Select(AppUserDto.Projection)
    .Where(user => !user.IsDeleted && user.UserCustomers.Any(x => x.CustomerId == tenant.Id && x.UserId == user.Id));

var query = 
    from d in filtered.Select(d => new { d.Id }).Distinct()
    from u in filtered.Where(u => u.Id == d.Id).Take(1)
    select u;

var appUsers = await query.ToDataSourceResultAsync(request.GridOptions, cancellationToken: cancellationToken);

DistinctBy 更改为 Distinct() 并将其和谓词移动到 Select 之前。我还将 AsNoTracking() 向上移动:

var appUsers = await _masterDbContext
    .Users
    .AsNoTracking()
    .Include(x => x.UserCustomers)
    .Where(user => 
        !user.IsDeleted 
        && user.UserCustomers
            .Any( x => x.CustomerId == tenant.Id ) )
    .Distinct()
    .Select(AppUserDto.Projection)
    .ToDataSourceResultAsync(request.GridOptions, cancellationToken: cancellationToken);