如何在LINQ中实现SQL的Where Exists嵌套Except查询逻辑
用LINQ方法语法实现SQL需求:找出姓名匹配但核心属性不匹配的人员ID
需求明确
我们要从sourcePeople(对应原SQL的Persons1)里筛选出符合以下条件的人员ID:
- 姓名在
destinationPeople(对应原SQL的Persons2)中有匹配项 - 但该人员的姓名、出生日期、地址这三个属性,和
destinationPeople里同姓名的人员不完全一致
解决方案代码
首先是基础的Person类和示例数据:
public class Person { public int PersonId { get; set; } public string Name { get; set; } public DateTime DateOfBirth { get; set; } public string Address { get; set; } } // 示例源数据 var sourcePeople = new List<Person> { new Person { PersonId = 1, Name = "张三", DateOfBirth = new DateTime(1990, 1, 1), Address = "北京朝阳区" }, new Person { PersonId = 2, Name = "李四", DateOfBirth = new DateTime(1985, 5, 5), Address = "上海浦东新区" }, new Person { PersonId = 3, Name = "王五", DateOfBirth = new DateTime(1995, 10, 10), Address = "广州天河区" } }; // 示例目标数据 var destinationPeople = new List<Person> { new Person { PersonId = 101, Name = "张三", DateOfBirth = new DateTime(1990, 1, 1), Address = "北京海淀区" }, new Person { PersonId = 102, Name = "李四", DateOfBirth = new DateTime(1985, 5, 5), Address = "上海浦东新区" }, new Person { PersonId = 103, Name = "赵六", DateOfBirth = new DateTime(1992, 3, 3), Address = "深圳南山区" } };
方法1:使用Except运算符实现
// 提取目标集合中用于对比的核心属性(姓名、生日、地址) var destMatchAttributes = destinationPeople.Select(p => new { p.Name, p.DateOfBirth, p.Address }); // 筛选出符合条件的源人员ID var mismatchedIds = sourcePeople // 先过滤出姓名在目标集合里存在的源人员 .Where(s => destinationPeople.Any(d => d.Name == s.Name)) // 包装源人员的ID和核心属性,确保和目标集合的对比结构一致 .Select(s => new { s.PersonId, s.Name, s.DateOfBirth, s.Address }) // 用Except找出核心属性不匹配的项(目标集合的属性要包装成相同结构,ID设默认值不影响对比) .Except(destMatchAttributes.Select(d => new { PersonId = default(int), d.Name, d.DateOfBirth, d.Address })) // 提取最终需要的PersonId .Select(result => result.PersonId) .ToList();
方法2:关联对比(可读性更高,无需强制用Except)
如果不需要硬性使用Except,这种通过姓名关联后直接对比属性的写法更直观:
var mismatchedIds = sourcePeople // 通过姓名关联两个集合 .Join(destinationPeople, s => s.Name, d => d.Name, (s, d) => new { Source = s, Dest = d }) // 筛选出任意核心属性不匹配的项 .Where(j => j.Source.DateOfBirth != j.Dest.DateOfBirth || j.Source.Address != j.Dest.Address || j.Source.Name != j.Dest.Name) // 提取源人员的ID .Select(j => j.Source.PersonId) .ToList();
代码说明
- 方法1里,
Except依赖匿名类型的结构相等性,所以必须保证前后两个匿名类型的属性名称、类型完全一致,这样才能正确对比出属性差异,最终拿到对应的源人员ID。 - 方法2通过
Join直接关联同姓名的人员,然后逐一对比属性,逻辑更直白,适合不需要强制使用Except的场景。
内容的提问来源于stack exchange,提问作者Shandy Sawyer
相关产品推荐
相关产品推荐

