如何在EF查询中排除<User,User>重复对并转为List<User>?
解决方法
核心问题是当前的Distinct()因为匿名对象中用户顺序不同就判定为不同实例,所以要先统一每对用户的排序规则,让顺序相反的配对变成完全一致的结构,再做去重,最后提取所有无重复的用户。
1. 统一配对顺序,过滤重复配对
修改查询逻辑,在Select时基于用户唯一标识(比如Id)调整顺序,把ID更小的用户放在前面,这样原本顺序相反的配对会变成完全相同的匿名对象,Distinct()就能正确过滤重复项:
var uniquePairs = _db.Messages .Where(p => p.UserId == parameters.UserId || p.ToUserId == parameters.UserId) .Select(p => new { First = p.FirstUser.Id < p.SecondUser.Id ? p.FirstUser : p.SecondUser, Second = p.FirstUser.Id < p.SecondUser.Id ? p.SecondUser : p.FirstUser }) .Distinct();
2. 提取并去重所有用户
从去重后的配对中,把两个用户合并成一个集合,再做一次去重得到最终的List<User>:
// 如果User类已正确实现IEquatable<User>或重写了Equals/GetHashCode var uniqueUsers = uniquePairs .SelectMany(pair => new[] { pair.First, pair.Second }) .Distinct() .ToList(); // 如果User类未实现相等比较,可按ID去重 var uniqueUsers = uniquePairs .SelectMany(pair => new[] { pair.First, pair.Second }) .GroupBy(u => u.Id) .Select(g => g.First()) .ToList();
合并为单查询(可选)
也可以把两步合并成一个EF查询,避免提前将数据拉取到内存:
var uniqueUsers = _db.Messages .Where(p => p.UserId == parameters.UserId || p.ToUserId == parameters.UserId) .Select(p => new { First = p.FirstUser.Id < p.SecondUser.Id ? p.FirstUser : p.SecondUser, Second = p.FirstUser.Id < p.SecondUser.Id ? p.SecondUser : p.FirstUser }) .Distinct() .SelectMany(pair => new[] { pair.First, pair.Second }) .Distinct() .ToList();
注意事项
- 必须用用户的唯一标识(比如
Id)来排序配对,确保顺序相反的配对能被识别为重复。 - 若要让EF将
Distinct()正确转换为SQL语句,User类需要正确实现相等比较逻辑,或者在查询中明确基于唯一标识分组去重。
内容的提问来源于stack exchange,提问作者FX_Sektor
相关产品推荐
相关产品推荐

