当您使用 GroupBy 时,您希望创建具有共同点的元素组。您希望共有的属性在参数keySelector 中指定。
用这个参数你说:请把Paraticipants分组,所有的属性值都与keySelector中指定的属性值相同。
在您的情况下:您希望创建具有相同 ZIP 值的参与者组。换句话说:如果您获取同一组中的两个 Participants,您希望确定它们的 ZIP 值相同。
首先,更改您的 keySelector:
var result = dbContext.Participants.GroupBy(participant => participant.Zip)
结果是一组组。每个组都有一个密钥,每个组都是(没有!)一个参与者序列。所有参与者的 Zip 属性值都等于 Key 的值。
之后,您想要获取每个组,并从每个组中创建一个新的 Participant 对象,该对象仅填充两个属性
-
Count 是组中参与者的数量
-
Zip 是 Group 中任何元素的 Zip,也就是我们之前看到的 Group 的 Key。
.Select(groupOfParticipantsWithSameKey => 新参与者
{
计数 = groupOfParticipantsWithSameKey.Count(),
Zip = groupOfParticipantsWithSameKey.Key,
});
您是否注意到我用正确的标识符更改了标识符i。选择正确的标识符将帮助您识别 LINQ 中的问题。这可能有点牵连,但它可以帮助您了解您正在处理的序列中的每个元素代表什么。
顺便说一下Enumerable.GroupBy的重载,就是带参数resultSelector的那个。这使您的 Select 变得不必要。
var result = context.Participants
.GroupBy(participanti => participant.Zip,
// parameter resultSelector, take each common Zip, and all Participants that have this Zip
// to make one new object
(zip, participantsWithThisZip) => new Participant
{
Zip = zip,
Count = participantsWithThisZip.Count(),
});
这个更容易理解,因为你去掉了标识符Key。
一个小的设计改进
您创建了一个方法,该方法接受所有参与者并为每个使用的 Zip 返回一个参与者,其中 Count 是拥有此 Zip 的参与者的数量。
如果您将更频繁地使用它,那么最好为此创建一个单独的方法,即IQueryable<Participant> 的扩展方法。这样,您可以对每个参与者序列重用该方法,而不仅仅是数据库中的所有参与者。见Extension Methods demystified
public static class ParticpantExtensions
{
public static IQueryable<Participant> ToParticipantsWithSameZip(
this IEnumerable<Participant> participants)
{
return participants.GroupBy(
participanti => participant.Zip,
(zip, participantsWithThisZip) => new Participant
{
Zip = zip,
Count = participantsWithThisZip.Count(),
});
}
}
用法:
你原来的方法:
Task<IList<Participant>> FetchParticipantsWithSameZipAsync()
{
using (var dbContext in new MyDbContext(...))
{
return await dbContext.ToParticipantsWithSameZip().ToListAsync();
}
}
您可以在非异步版本中重复使用它:
IList<Participant>> FetchParticipantsWithSameZipAsync()
{
using (var dbContext in new MyDbContext(...))
{
return dbContext.ToParticipantsWithSameZip().ToList();
}
}
但现在你也可以将它与其他 LINQ 方法交织在一起:
var newYorkParticipantsWithSameZip = dbContext.Participants
.Where(participant => participant.State == "New York")
.ToParticipantsWithSameZip()
.OrderBy(participant => participant.Count())
.ToList();
几个优点:
- 可重复使用
- 代码看起来更干净,
- 更容易理解它的作用
- 您可以在没有数据库的情况下对其进行单元测试:任何
IQueryable<Participant> 都可以。
- 如果您需要更改
ToParticipantsWithSameZip,您只需更改一处并重写测试。
因此,如果您将在多个地方使用它:请考虑扩展方法