LinqToSQL:如何基于字段组合排除另一张表中的数据
基于用户+职位组合的排除实现方案
问题背景
我已经拿到了特定职位的用户结果集。之前是通过单个UserID排除用户:
var toExclude = dc.Users.Where(p => p.SomeProperty == true); positionUsers = positionUsers.Where(p => !toExclude.Select(x => x.UserID).Contains(p.UserID));
但现在需要排除的是用户+职位的特定组合(不是排除所有该用户或所有该职位),之前尝试拼接字符串的方式明显错误,下面是正确的实现方法:
正确实现方式
方法一:利用匿名类型的Contains(EF6及以上支持)
LINQ to Entities支持匿名类型的相等比较,直接投影出要排除的组合,再用Contains过滤:
// 获取要排除的「用户ID+职位ID」组合(请根据你的实体调整字段名) var excludeCombinations = dc.UserPositions .Where(p => p.SomeProperty == true) .Select(p => new { p.UserID, p.PositionID }); // 过滤结果集,排除匹配的组合 positionUsers = positionUsers .Where(p => !excludeCombinations.Contains(new { p.UserID, p.PositionID }));
注意:匿名类型的属性名称、类型必须完全一致,否则无法正确匹配。
方法二:用Any做关联判断(兼容所有EF版本)
如果匿名类型的Contains不生效,或者你用的是旧版EF,可以用Any直接判断组合是否存在:
var excludePairs = dc.UserPositions .Where(p => p.SomeProperty == true) .Select(p => new { p.UserID, p.PositionID }); positionUsers = positionUsers .Where(p => !excludePairs.Any(x => x.UserID == p.UserID && x.PositionID == p.PositionID));
方法三:内存中过滤(适合排除列表数据量小的情况)
如果要排除的组合数量不多,可以先把数据加载到内存,用Tuple存储后过滤:
// 加载排除组合到内存 var excludeTuples = dc.UserPositions .Where(p => p.SomeProperty == true) .Select(p => Tuple.Create(p.UserID, p.PositionID)) .ToList(); // 过滤结果集 positionUsers = positionUsers .Where(p => !excludeTuples.Contains(Tuple.Create(p.UserID, p.PositionID)));
为什么之前的字符串拼接不行?
拼接UserID + Position会出现哈希冲突:比如UserID=123+Position=45 和 UserID=12+Position=345拼接后都是12345,导致错误排除无关组合,必须用两个字段同时匹配的方式。
内容的提问来源于stack exchange,提问作者Cameron Castillo
相关产品推荐
相关产品推荐

