首页 > 解决方案 > EF 中是否有针对 LINQ 表达式的等效语句?

问题描述

我有一种方法可以从特定聊天室获取未被阻止且不是自己的参与者。有没有办法将所有语句放在一个 DB 语句中,这是一种更优雅紧凑的解决方案?

  Task<IList<ChatParticipant>> GetParticipants(int chatId, int excludeUserId)
        { 
            
            var chatParticipants = await Context.ChatParticipant
                .Include(x => x.Chat)
                .Include(x => x.Participant)
                .Where(c => c.ParticipantId != excludeUserId)
                .ToListAsync();
            
            var blockers = await Context.BlockedParticipant 
                .Include(x => x.Blocker)
                .Where(c => c.BlockedId == excludeUserId)
                .Select(x => x.Blocker)
                .ToListAsync();
             
            
            var result = chatParticipants.Where(p => blockers.All(p2 => p2.Id != p.ParticipantId)).ToList();
            
            return result;
        }

标签: c#linqentity-framework-core

解决方案


虽然我同意将查询分开可以提高可读性,但另一个考虑是这两个查询将在过滤和分页等之前将所有各自的数据加载到内存中。这对服务器资源来说会很昂贵。对这段关系有所了解,您可以尝试以下方法:

Task<IList<ChatParticipant>> GetParticipants(int chatId, int excludeUserId)
{ 

    var chatParticipants = await Context.ChatParticipant
        .Include(x => x.Chat)
        .Include(x => x.Participant)
        .Where(c => c.ParticipantId != excludeUserId
            && !Context.BlockedParticipant.Any(b => 
                 b.BlockedId == excludeUserId && b.Blocker.Id == c.ParticipantId))
        .ToListAsync();

    return chatPaticipants;
}

我相信该方法也应该标记为async便于await和避免对 DbContext 的潜在多线程访问。我不是 100% 确定我已经捕获了阻止者和参与者之间的关系,但这是我可以从原始查询中推断出来的。将它们合并到单个查询中并不能提高可读性,但可以避免在分页之类的操作之前将较大的集合加载到内存中。


推荐阅读